espial: Espial is an open-source, web-based bookmarking server.

[ agpl, library, web ] [ Propose Tags ] [ Report a vulnerability ]

Espial is an open-source, web-based bookmarking server. - Yesod + TypeScript + sqlite3 - multi-user (w/ privacy scopes) - tags, stars, editing, deleting


[Skip to Readme]

Flags

Manual Flags

NameDescriptionDefault
usebuildinfo

read buildinfo from generated file buildinfo/BuildInfo.hs

Disabled
Automatic Flags
NameDescriptionDefault
dev

Turn on development settings, like auto-reload templates.

Disabled
library-only

Build for use with "yesod devel"

Disabled

Use -f <flag> to enable a flag, or -f -<flag> to disable that flag. More info

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 0.0.1, 0.0.2, 0.0.3, 0.0.4, 0.0.5, 0.0.5.1, 0.0.7, 0.0.9, 0.0.10, 0.0.11, 0.0.16, 0.0.19, 0.0.20, 0.0.26, 0.0.34, 0.0.35 (info)
Change log changelog.md
Dependencies aeson (>=1.4), attoparsec, base (>=4.18.1.0 && <5), base64 (>=1 && <2), bcrypt (>=0.0.8), blaze-html (>=0.9 && <1), bytestring (>=0.11.5 && <0.13), case-insensitive, classy-prelude (>=1.4 && <1.6), classy-prelude-conduit (>=1.4 && <1.6), classy-prelude-yesod (>=1.4 && <1.6), conduit (>=1.0 && <2), containers, cryptohash-sha256, crypton-connection, data-default, directory (>=1.1 && <1.4), entropy, espial, esqueleto (>=3.5.11.1 && <3.7), fast-logger (>=2.2 && <4), fgl, file-embed, foreign-store, gitrev, hjsmin (>=0.1 && <0.3), hscolour, html-entities, http-api-data (>=0.3.4), http-client, http-client-tls (>=0.3 && <0.4), http-conduit (>=2.3 && <2.4), http-types, iso8601-time (>=0.1.3), microlens, monad-logger (>=0.3 && <0.4), mtl, optparse-applicative, optparse-generic (>=1.2.3), parser-combinators, persistent (>=2.14 && <2.18), persistent-sqlite (==2.13.3.0), persistent-template (>=2.12 && <2.13), pretty-show, safe, shakespeare (>=2.0 && <2.2), template-haskell, text (>=2 && <3), time, transformers (>=0.2.2), unix, unordered-containers, vector, wai, wai-extra (>=3.0 && <3.2), wai-logger, warp (>=3.0 && <3.5), yaml (>=0.8 && <0.12), yesod (>=1.6 && <1.8), yesod-auth (>=1.6 && <1.8), yesod-core (>=1.6 && <1.8), yesod-form (>=1.6 && <1.8), yesod-newsfeed (>=1.6 && <1.8), yesod-static (>=1.6 && <1.8) [details]
Tested with ghc ==9.10.3
License AGPL-3.0-or-later
Copyright Copyright (c) 2018 Jon Schoning
Author Jon Schoning
Maintainer jonschoning@gmail.com
Uploaded by jonschoning at 2026-06-17T21:12:16Z
Category Web
Home page https://github.com/jonschoning/espial
Bug tracker https://github.com/jonschoning/espial/issues
Source repo head: git clone https://github.com/jonschoning/espial.git
Distributions
Executables migration, espial
Downloads 4423 total (52 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs uploaded by user [build log]
All reported builds failed as of 2026-06-17 [all 2 reports]

Readme for espial-0.0.35

[back to package description]

Espial

Espial is an open-source, web-based bookmarking server.

It allows mutiple accounts, but currently intended for self-host scenarios.

The bookmarks are stored in a sqlite3 database, for ease of deployment & maintenence.

The easist way for logged-in users to add bookmarks, is with the "bookmarklet", found on the Settings page.

Demo Server

Log in with:

  • username: demo
  • password: demo

https://espdemo.ae8.org/u:demo

jpg

Installation

Docker Setup

See:

https://github.com/jonschoning/espial-docker

Server Setup (From Source)

  1. Install the Stack executable here:
  2. Build executables:
stack build
  1. Create the database:
stack exec migration -- createdb
  1. Create a user:
stack exec migration -- createuser --userName myusername --userPassword myuserpassword
  1. Import a pinboard bookmark file for a user (optional):
stack exec migration -- importbookmarks --userName myusername --bookmarkFile sample-bookmarks.json
  1. Import a firefox bookmark file for a user (optional):
stack exec migration -- importfirefoxbookmarks --userName myusername --bookmarkFile firefox-bookmarks.json
  1. Start a production server:
stack exec espial

Configuration

See config/settings.yml for changing default run-time parameters & environment variables.

  • config/settings.yml is embedded into the app executable when compiled and also read once when the app starts. Current settings in config/settings.yml will override the embedded compile-time settings.
  • config/settings.yml values formatted like _env:ENV_VAR_NAME:default_value can be overridden by the specified environment variable.
  • Example:
    • _env:PORT:3000
    • environment variable PORT
    • default app http port: 3000

Request IP Logging

Espial supports the IP_FROM_HEADER environment variable for request logging.

  • IP_FROM_HEADER=true: log the client IP from the X-Real-IP or X-Forwarded-For header when present, and fall back to the peer address if neither header is available.
  • IP_FROM_HEADER=false: log the peer address from the HTTP connection.

Only set IP_FROM_HEADER=true if your application is safely positioned behind a trusted reverse proxy.

SSL / Reverse Proxy

Espial does not terminate TLS itself. Run it behind a reverse proxy that handles HTTPS and forwards traffic to Espial over HTTP.

For container-based deployment examples, including production-oriented layouts, see the espial-docker repository:

Minimal Caddy example:

Localhost without a real domain:

https://localhost:3050 {
    reverse_proxy localhost:3000
}

or with a domain:

espial.example.com {
  reverse_proxy 127.0.0.1:3000
}

With the domain setup:

  • Caddy terminates TLS for espial.example.com.
  • Espial continues listening on HTTP, locally on 127.0.0.1:3000
    • If using Docker Compose, it would like like espial:3000
  • Set IP_FROM_HEADER=true only when Espial is reachable solely through that trusted proxy.

If you are using Cloudflare:

  • Prefer Cloudflare SSL mode Full (strict).
  • use header_up X-Forwarded-For {http.request.header.CF-Connecting-IP}
  • If traffic can reach Espial directly without passing through your trusted proxy, do not enable IP_FROM_HEADER=true, because client IP headers can be spoofed.

Archive Backends

Espial supports configurable archive backends for saving bookmark snapshots.

Set the backend with archive-backend in config/settings.yml:

  • disabled: archiving is turned off (default).

  • wayback-machine: enables submission to the Internet Archive Wayback Machine.

    Wayback Machine support requires the following settings:

    • wayback-machine-access-key

    • wayback-machine-secret-key

      Create these by signing in to your Internet Archive account and generating S3-style API credentials at https://archive.org/account/s3.php.
      If wayback-machine is selected but the access key or secret key is missing, archiving is disabled at runtime.

  • archivebox07: queues the URL in a local ArchiveBox 0.7 instance and stores an ArchiveBox link on the bookmark.

    IMPORTANT - ArchiveBox stores all archive data in a single global index space, so this arcive-backend is best suited to single-user Espial instances.

    Recommended setup is to use Docker Compose to run the ArchiveBox instance

    ArchiveBox support requires the following settings:

    • archivebox-url

      archivebox-url is the URL espial uses to sign in to ArchiveBox and submit URLs through the web UI. In Docker Compose this is typically http://archivebox:8000.

    • archivebox-public-url (optional)

      Public ArchiveBox URL stored on bookmarks.

    • archivebox-username plus archivebox-password

      Espial signs in to the ArchiveBox web UI with these credentials before submitting URLs.

    • archivebox-tag (optional)

      A tag Espial adds to submissions (example: espial).

    • archivebox-plugins (optional)

      Comma-separated list of ArchiveBox methods (plugins) to request when submitting URLs, e.g. title,favicon,singlefile,screenshot.

    Set the ArchiveBox admin credentials in the override path by supplying:

    • ARCHIVEBOX_USERNAME=...
    • ARCHIVEBOX_PASSWORD=...

    The Makefile includes the following helpers:

    • docker-compose-up-archivebox07
    • docker-compose-up-d-archivebox07
    • docker-compose-exec-archivebox07

    Or start the instance manually via docker compose, example:

    docker compose -f docker-compose.archivebox07.yml up
    

    Configure the enrivonment variable ARCHIVE_METHODS to control which archive methods ArchiveBox uses:

    environment:
      - ARCHIVE_METHODS=title,favicon,singlefile,screenshot
    

    Available ARCHIVE_METHODS plugins:

    • archive_org, dom, favicon, git, headers, htmltotext, media, mercury, pdf, readability, screenshot, singlefile, title, wget

    If ARCHIVE_METHODS is unset/not-present, ArchiveBox will uses all plugins.

    For additional information and configuration, refer to the ArchiveBox repository

Optional proxy settings for archive requests:

  • archive-socks-proxy-host
  • archive-socks-proxy-port

Also, see the android app for adding bookmarks via an Android Share intent:

https://github.com/jonschoning/espial-share-android

Development

Frontend

  • See frontend/ folder

CLI

Migration commands are run via:

stack exec migration -- <command> [options]

All commands take an optional --conn parameter for the database location; if omitted, the database location is loaded from config/settings.yml or environment variable SQLITE_DATABASE

Commands

Command Example
createdb stack exec migration -- createdb
createuser stack exec migration -- createuser --userName myusername --userPassword myuserpassword
createuser (password file) stack exec migration -- createuser --userName myusername --userPasswordFile mypassword.txt
deleteuser stack exec migration -- deleteuser --userName myusername
createapikey stack exec migration -- createapikey --userName myusername
deleteapikey stack exec migration -- deleteapikey --userName myusername
importbookmarks stack exec migration -- importbookmarks --userName myusername --bookmarkFile sample-bookmarks.json
importfirefoxbookmarks stack exec migration -- importfirefoxbookmarks --userName myusername --bookmarkFile firefox-bookmarks.json
importnetscapebookmarks stack exec migration -- importnetscapebookmarks --userName myusername --bookmarkFile bookmarks.html
importnotes stack exec migration -- importnotes --userName myusername --noteDirectory ./notes
exportbookmarks stack exec migration -- exportbookmarks --userName myusername --bookmarkFile exported-bookmarks.json
exportnetscapebookmarks stack exec migration -- exportnetscapebookmarks --userName myusername --bookmarkFile exported-bookmarks.html
printmigratedb stack exec migration -- printmigratedb
showuser stack exec migration -- showuser --userName myusername

importbookmarks Command Notes:

See sample-bookmarks.json, which contains a JSON array, each line containing a FileBookmark object.

Example:

[
  {
    "href": "http://raganwald.com/2018/02/23/forde.html",
    "description": "Forde's Tenth Rule, or, \"How I Learned to Stop Worrying and \u2764\ufe0f the State Machine\"",
    "extended": "",
    "time": "2018-02-26T22:57:20Z",
    "shared": "yes",
    "toread": "yes",
    "tags": "raganwald"
  },
  ,
  {
    "href": "http://downloads.haskell.org/~ghc/latest/docs/html/users_guide/flags.html",
    "description": "7.6. Flag reference \u2014 Glasgow Haskell Compiler 8.2.2 User's Guide",
    "extended": "-fprint-expanded-synonyms",
    "time": "2018-02-26T21:52:02Z",
    "shared": "yes",
    "toread": "no",
    "tags": "ghc haskell"
  }
]