Skip to main content

EPUB Browser

A private EPUB reading service and a self-contained static-site generator.

English | 简体中文

EPUB Browser logo

PyPI version Python versions License

EPUB Browser has two explicit modes:

ssg server
Deployment Static hosting, Pages, object storage, Nginx A persistent private reading service
Accounts None Local accounts; optional trusted-proxy identity
Progress, annotations, bookshelf This browser only Authenticated account in SQLite
Source updates Run ssg again Restart or use --watch
Runtime database None Required

Use ssg when the result must be ordinary static files. Use server when readers need accounts, cross-device data, access control, or automatic source reconciliation.

Requirements and installation

  • Python 3.9 or newer
  • One or more .epub files, files in nested directories, or a Calibre-style library directory

Install from PyPI:

pip install epub-browser

Show the mode-specific command reference:

epub-browser --help
epub-browser ssg --help
epub-browser server --help

Quick start

Generate a static site

epub-browser ssg /path/to/books \
  --output-dir /path/to/dist

Serve dist/ over HTTP. Opening generated pages directly through file:// is not supported because browser storage, modules, manifests, and Service Workers require an HTTP origin.

For a site hosted below a URL prefix, set the public path separately from the filesystem destination:

epub-browser ssg /path/to/books \
  --output-dir /path/to/dist \
  --base-path /my-repository/

--base-path changes generated URLs, not where files are written. With /my-repository/, links, icons, manifests, book metadata, and Service Worker entries all use that prefix while the files remain directly inside dist/.

Run a persistent Server library

epub-browser server /path/to/books \
  --server-dir /path/to/epub-browser-state \
  --watch

Open http://127.0.0.1:8000/. On first access, EPUB Browser prompts you to create the initial administrator. The library is not scanned or exposed until this one-time setup finishes.

Sources and stable book identity

Every positional SOURCE may be an EPUB file or a directory. Directories are searched recursively. Multiple sources can be passed to one command:

epub-browser server book.epub /srv/library /srv/periodicals \
  --server-dir /srv/epub-browser \
  --watch

Each book receives a stable book_id, also exposed as book_hash in generated URLs and browser data. The general CLI default is:

--book-id-storage sidecar

Sidecar mode writes a visible identity file beside the EPUB, such as BOOK.epub.epub-browser.json, and leaves the EPUB bytes unchanged. The sidecar contains the stable ID and a verified SHA-256 source fingerprint.

To place the ID in OPF metadata instead, select embedded storage for the entire invocation:

--book-id-storage embedded

Embedded mode can rebuild the EPUB ZIP, so the source must be writable and safe to modify. EPUB Browser does not silently fall back to a database-only identity. It stops when IDs disagree, active sources duplicate an ID, a carrier is invalid, or a required carrier cannot be written.

When migrating storage modes, the existing ID is copied to the selected carrier; the other valid carrier is retained. An existing embedded ID from v2.0.4 is copied to the default sidecar without rewriting the EPUB.

SSG mode

SSG builds a complete snapshot in a sibling staging directory, validates it, and then replaces the destination. If any conversion fails, the previous destination remains unchanged. Generated output contains no Server database, migration state, account page, or runtime cache metadata.

SSG behavior is intentionally local and account-free:

  • Reading progress and annotations use browser storage on the current origin.
  • The bookshelf supports local JSON Import and Export; it has no cloud Sync action.
  • Login, account settings, Server APIs, and user-dependent controls are absent.
  • The storage destination is fixed to local browser storage and is not presented as a setting.
  • Static output includes the Service Worker required for offline-capable assets.

All required application JavaScript, CSS, fonts, and icons are included in the output. See Self-contained and network behavior for the only optional network request.

Server mode

Initial setup, accounts, and permissions

On a fresh persistent state directory, normal pages redirect to /setup. APIs, event streams, generated assets, and books return a setup-required response until the initial administrator is created. Complete setup over loopback or another trusted private path before exposing the port: the first successful setup submission claims the administrator account.

After setup:

  • Public registration is closed. Administrators create and manage users.
  • Accounts have either the administrator or member role.
  • Ordinary books are visible to every authenticated account.
  • Restricted books are visible only to administrators and explicitly selected users.
  • Each user owns their bookshelf, progress, annotations, and active sessions.
  • Users can change their password and revoke their sessions.
  • Administrators can manage users, roles, passwords, sessions, external identities, and book grants.
  • Sessions use an HttpOnly cookie, CSRF protection, and a 30-day sliding lifetime.

For unattended first start, provide a username and password file:

epub-browser server /path/to/books \
  --server-dir /path/to/state \
  --admin-username admin \
  --admin-password-file /run/secrets/epub-browser-admin-password \
  --no-browser

The password file should be mode 0600. EPUB Browser removes one trailing newline, stores an Argon2id hash, and never prints the secret. An incomplete configuration, empty file, or unreadable file stops startup. Once setup is complete, subsequent starts do not read the bootstrap secret.

Environment equivalents are EPUB_BROWSER_ADMIN_USERNAME and EPUB_BROWSER_ADMIN_PASSWORD_FILE. EPUB_BROWSER_ADMIN_PASSWORD is a plaintext fallback only when no password file is configured. A CLI password-file path has priority over environment password sources.

Browser launch and logging

By default, Server tries to open the operating system's default browser after the HTTP listener has started. --no-browser prevents that local launch. It does not disable the web interface or browser access; it only suppresses the local webbrowser.open(...) call. Use it for Docker, systemd, SSH sessions, headless machines, and scripts.

Without --log, the CLI avoids routine output so terminal progress displays are not corrupted. An interactive terminal prints the bound URL once; non-interactive Docker and service runs remain quiet. --log enables operational and HTTP access logging.

Initial and watch scans appear in the web interface rather than terminal tqdm. A successful summary closes automatically; failures stay visible until dismissed. With --watch, fixing or replacing a source starts another scan without a manual retry action.

Persistent and ephemeral state

Persistent Server mode requires --server-dir. For a disposable run, use --ephemeral instead:

epub-browser server book.epub --ephemeral

Ephemeral state is deleted at shutdown. Because its database is new on every run, setup also repeats unless unattended bootstrap credentials are supplied.

Persistent layout:

<server-dir>/
├── .server.lock                 # reusable process-lock metadata
├── data/
│   ├── epub-browser.db          # authoritative accounts, books, grants, reading data
│   ├── migration-state.json     # restart-safe migration state
│   └── backups/                 # verified pre-migration database copies
└── cache/
    ├── catalog.json             # generated-cache status
    ├── public/                  # served application and converted books
    └── staging/                 # replaceable conversion work

Only data/ is authoritative. cache/ may be deleted and will be rebuilt. Preserve data/ across upgrades and container replacement. An operating-system lock controls exclusivity; .server.lock may remain after a normal shutdown as diagnostic metadata.

LAN, reverse proxy, and OIDC

Server binds to 127.0.0.1:8000 by default. For a trusted LAN:

epub-browser server /path/to/books \
  --server-dir /path/to/state \
  --watch \
  --host 0.0.0.0 \
  --port 8080 \
  --no-browser

Do not expose the built-in HTTP server directly to the public internet. Terminate TLS at a reverse proxy, apply network controls, and enable secure cookies.

EPUB Browser is not an OAuth/OIDC client. To use OIDC, place an OIDC-aware authentication proxy in front of it and pass a stable authenticated subject:

epub-browser server /path/to/books \
  --server-dir /path/to/state \
  --watch \
  --host 0.0.0.0 \
  --cookie-secure \
  --trusted-proxy-cidr 10.42.0.0/16 \
  --proxy-subject-header X-Remote-User \
  --proxy-display-name-header X-Remote-Name \
  --proxy-issuer https://login.example.com \
  --no-browser

The trusted CIDR must identify the reverse proxy's direct socket network, not the public client range. Configure the proxy to remove client-supplied copies of the identity headers and set its own authenticated values. Headers from untrusted peers are ignored. Uvicorn forwarded-address processing is disabled, so X-Forwarded-For, Forwarded, and FORWARDED_ALLOW_IPS cannot expand this trust boundary.

Use an immutable provider subject, not a display name, in --proxy-subject-header. Keep --proxy-issuer stable for that identity domain. A user can link an unknown trusted identity by proving a local account password, or an administrator can create the mapping. Local administrator/password login remains the recovery path.

Docker

The image runs persistent Server mode with these defaults:

  • /app/Library as the source
  • /app/EpubBrowserFiles as persistent state
  • --watch
  • --no-browser
  • --host 0.0.0.0 --port 80
  • --book-id-storage embedded

Because embedded identity may rewrite an EPUB, mount the library read-write. Mount Server state read-write and keep it across container replacement:

docker run -d \
  --name epub-browser \
  -p 127.0.0.1:8080:80 \
  -v /path/to/books:/app/Library:rw \
  -v /path/to/epub-browser-state:/app/EpubBrowserFiles \
  epub-browser:2.1.0

Visit http://127.0.0.1:8080/setup before changing the port binding or proxy rules.

For unattended setup:

docker run -d \
  --name epub-browser \
  -p 127.0.0.1:8080:80 \
  -v /path/to/books:/app/Library:rw \
  -v /path/to/epub-browser-state:/app/EpubBrowserFiles \
  -e EPUB_BROWSER_ADMIN_USERNAME=admin \
  -e EPUB_BROWSER_ADMIN_PASSWORD_FILE=/run/secrets/epub-browser-admin-password \
  --mount type=bind,src=/path/to/admin-password,dst=/run/secrets/epub-browser-admin-password,readonly \
  epub-browser:2.1.0

After the first successful start, the one-time secret mount may be removed. A read-only library works only when every EPUB already contains a matching valid embedded ID. Existing sidecars are retained when their IDs are embedded.

Mount /app/SyncData:ro only while importing legacy bookshelf JSON:

-v /path/to/legacy-sync:/app/SyncData:ro

The loopback published port in the examples keeps the container behind the host boundary. For remote access, use a TLS reverse proxy and configure its actual container-network CIDR, identity headers, and --cookie-secure.

Complete command reference

epub-browser ssg SOURCE [SOURCE ...]

Option Meaning
--output-dir DIR, -o DIR Required destination for the atomic static snapshot.
--base-path PATH Public URL prefix; default /. It must begin and end with /.
--book-id-storage sidecar|embedded Stable identity carrier for every selected source; default sidecar.
--log Print conversion detail. Without it, routine output stays quiet.

epub-browser server SOURCE [SOURCE ...]

Exactly one of --server-dir and --ephemeral is required.

Option Meaning
--server-dir DIR Persistent authoritative data and replaceable cache root.
--ephemeral Use disposable state; mutually exclusive with --server-dir.
--watch, -w Watch sources and reconcile additions, updates, moves, and deletions.
--host ADDRESS Bind address; default 127.0.0.1.
--port PORT, -p PORT Bind port; default 8000.
--no-browser Do not launch the local default browser. The web UI remains available.
--log Enable operational and HTTP access logs.
--legacy-sync-dir DIR Read legacy bookshelf JSON during startup migration.
--book-id-storage sidecar|embedded Stable identity carrier for every selected source; default sidecar.
--admin-username NAME Initial unattended administrator; fallback EPUB_BROWSER_ADMIN_USERNAME.
--admin-password-file FILE Preferred initial secret file; fallback EPUB_BROWSER_ADMIN_PASSWORD_FILE, then EPUB_BROWSER_ADMIN_PASSWORD when no file is set.
--trusted-proxy-cidr CIDR Repeatable direct-proxy network trust boundary. Requires subject header and issuer.
--proxy-subject-header NAME Header containing the immutable authenticated external subject.
--proxy-display-name-header NAME Optional header containing a display name.
--proxy-issuer VALUE Stable issuer/security-domain identifier for proxy subjects.
--cookie-secure Send the session cookie only over browser-facing HTTPS.

Legacy v1 syntax

Legacy syntax is supported throughout the v2 major line:

v1 command v2 mapping
epub-browser BOOKS epub-browser server BOOKS --ephemeral
epub-browser BOOKS --output-dir STATE epub-browser server BOOKS --server-dir STATE
epub-browser BOOKS --no-server --output-dir DIST epub-browser ssg BOOKS --output-dir DIST
--sync-dir DIR server --legacy-sync-dir DIR

Legacy-only --keep-files retains a temporary Server directory. Persistent Server directories are already permanent. With --log, the compatibility adapter prints the equivalent v2 command; otherwise it remains quiet.

Reading features and data placement

  • Recursive EPUB and Calibre-library discovery, metadata tags, search, and pinyin search
  • Responsive Library, book detail, and chapter-reading interfaces
  • Scrolling, page turning, continuous reading, adjustable content width, fonts, custom CSS, themes, and pure reading mode
  • Highlights, notes, annotation browsing, nested bookshelf groups, tags, and JSON Import/Export
  • English and Simplified Chinese interfaces
  • E-reader-friendly behavior for Kindle/Silk browsers; browser-heavy features may be reduced
Data SSG Server
Reading progress Browser-local Authenticated user's SQLite record
Highlights and notes Browser-local Authenticated user's SQLite records
Bookshelf Browser-local; Import/Export Authenticated user's versioned cloud document; automatic save
Accounts and sessions Not present SQLite under <server-dir>/data
Book grants Not present SQLite under <server-dir>/data

Server does not offer a local/cloud storage selector: authenticated reading data is always stored on the Server. SSG never probes Server APIs and always uses the current browser origin's local storage.

Self-contained and network behavior

The application is self-contained for reading: required JavaScript, CSS, fonts, icons, manifests, and converted EPUB resources are served locally. There are no CDN runtime dependencies. Blocking outbound internet access does not prevent setup, login, browsing, reading, annotations, progress, bookshelf use, administration, or source conversion.

The footer may make an optional request to the GitHub Releases API to discover a newer EPUB Browser version. Failure, blocking, or offline use only suppresses that update hint. OIDC also requires the separately operated authentication proxy and provider you explicitly configure; it is not a built-in dependency.

SSG publishes a static Service Worker. Server deliberately disables and retires the origin-wide Service Worker so one account cannot receive another account's cached protected content.

Data safety and migration

Before upgrading persistent Server installations, back up the source EPUBs and <server-dir>/data. Keep the same persistent state volume during container replacement.

Startup migration is automatic and restart-safe. It verifies legacy databases, creates a backup, upgrades a copy, imports eligible legacy bookshelf/progress/annotation data into the pending initial administrator, and only retires legacy files after successful checkpoints. Ordinary requests never scan legacy sync directories. Corrupt databases, invalid password hashes, ambiguous legacy databases, and conflicting IDs fail closed instead of being guessed or overwritten.

If both epub-browser.db and annotations.db exist at a legacy root, startup stops and leaves them untouched. See Migrating to v2 for backup, rollback, cache rebuilding, and conflict recovery.

Troubleshooting

The command started, but no browser opened

Remove --no-browser when running on a graphical local machine, or open the printed/bound URL manually. In Docker, systemd, SSH, and non-interactive sessions, opening the URL yourself is expected.

The CLI appears quiet

Quiet operation is intentional without --log, especially in non-interactive environments. Add --log for operational and access detail. Server scan progress is shown in the web interface.

Docker cannot write a stable ID

The image defaults to embedded identity. Mount /app/Library read-write or pre-embed valid matching IDs. Use a custom command with --book-id-storage sidecar only if a writable sidecar carrier is preferable.

A generated SSG site has broken links below a subpath

Regenerate it with a normalized --base-path, such as /reader/, and configure the static host to serve the output at that same prefix.

Server refuses to start after an upgrade

Read the first logged migration or validation error, preserve the data and source files, and consult docs/migration-v2.md. Do not delete the authoritative data/ directory to work around an error.

Contributing

Issues and pull requests are welcome at dfface/epub-browser. A useful report includes the exact command, browser/device, reproduction steps, relevant logs, and the EPUB when it can be shared legally.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

epub_browser-2.1.0.tar.gz (1.6 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

epub_browser-2.1.0-py3-none-any.whl (1.6 MB view details)

Uploaded Python 3

File details

Details for the file epub_browser-2.1.0.tar.gz.

File metadata

  • Download URL: epub_browser-2.1.0.tar.gz
  • Upload date:
  • Size: 1.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.7

File hashes

Hashes for epub_browser-2.1.0.tar.gz
Algorithm Hash digest
SHA256 c8be7b5f15764c1bccc1d78d2b785da5e2e9024205082fb72a9d5279aff846d0
MD5 9b3b27c1b56c1c7f0b938a1428f62e36
BLAKE2b-256 1be30e144371ac658eda8cce9b3b8a368f2200e3582a57fbf535007c578bc825

See more details on using hashes here.

File details

Details for the file epub_browser-2.1.0-py3-none-any.whl.

File metadata

  • Download URL: epub_browser-2.1.0-py3-none-any.whl
  • Upload date:
  • Size: 1.6 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.7

File hashes

Hashes for epub_browser-2.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 60796b0738735f10cc715e172440fa1cb1df363c9d738d953e02176723ac44db
MD5 58847410619ea791bebe85d8115b98c3
BLAKE2b-256 09554d67d8b6df28ebeaed0f8821ef9c36b20b075ee9dea6badb122778ea16c2

See more details on using hashes here.

Release history Release notifications | RSS feed

2.1.1

2 files

This release

2.1.0 This release

2 files

2.0.5

2 files

2.0.4

2 files

2.0.3

2 files

2.0.2

2 files

2.0.1

2 files

2.0.0

2 files

1.11.5

2 files

1.11.4

2 files

1.11.3

2 files

1.11.2

2 files

1.11.1

2 files

1.11.0

2 files

1.10.9

2 files

1.10.8

2 files

1.10.7

2 files

1.10.6

2 files

1.10.5

2 files

1.10.4

2 files

1.10.3

2 files

1.10.2

2 files

1.10.1

2 files

1.10.0

2 files

1.9.4

2 files

1.9.3

2 files

1.9.2

2 files

1.9.1

2 files

1.9.0

2 files

1.8.13

2 files

1.8.12

2 files

1.8.11

2 files

1.8.10

2 files

1.8.9

2 files

1.8.7

2 files

1.8.6

2 files

1.8.5

2 files

1.8.4

2 files

1.8.3

2 files

1.8.2

2 files

1.8.1

2 files

1.8.0

2 files

1.7.16

2 files

1.7.15

2 files

1.7.14

2 files

1.7.13

2 files

1.7.12

2 files

1.7.11

2 files

1.7.10

2 files

1.7.9

2 files

1.7.8

2 files

1.7.7

2 files

1.7.6

2 files

1.7.5

2 files

1.7.4

2 files

1.7.3

2 files

1.7.2

2 files

1.7.1

2 files

1.7.0

2 files

1.6.19

2 files

1.6.18

2 files

1.6.17

2 files

1.6.16

2 files

1.6.15

2 files

1.6.14

2 files

1.6.13

2 files

1.6.12

2 files

1.6.11

2 files

1.6.9

2 files

1.6.8

2 files

1.6.7

2 files

1.6.6

2 files

1.6.5

2 files

1.6.4

2 files

1.6.3

2 files

1.6.2

2 files

1.6.1

2 files

1.6.0

2 files

1.5.4

2 files

1.5.3

2 files

1.5.2

2 files

1.5.1

2 files

1.5.0

2 files

1.4.9

2 files

1.4.8

2 files

1.4.7

2 files

1.4.6

2 files

1.4.5

2 files

1.4.4

2 files

1.4.3

2 files

1.4.2

2 files

1.4.1

2 files

1.4.0

2 files

1.3.5

2 files

1.3.4

2 files

1.3.3

2 files

1.3.1

2 files

1.3.0

2 files

1.2.12

2 files

1.2.11

2 files

1.2.10

2 files

1.2.9

2 files

1.2.8

2 files

1.2.7

2 files

1.2.6

2 files

1.2.5

2 files

1.2.4

2 files

1.2.3

2 files

1.2.2

2 files

1.2.1

2 files

1.2.0

2 files

1.1.7

2 files

1.1.6

2 files

1.1.5

2 files

1.1.4

2 files

1.1.3

2 files

1.1.2

2 files

1.1.1

2 files

1.1.0

2 files

1.0.9

2 files

1.0.8

2 files

1.0.7

2 files

1.0.6

2 files

1.0.5

2 files

1.0.4

2 files

1.0.2

2 files

1.0.1

2 files

1.0.0

2 files

0.6.3

2 files

0.6.2

2 files

0.6.1

1 file

0.6.0

1 file

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page