Unofficial Docker image for KoShelf.
A reading companion powered by KOReader metadata — browse your library, highlights, annotations, and reading statistics from a web dashboard.
- new cli interface
- folder data required for serve option
The books or central metadata mount must be writable by UID 1000 when KOSHELF_ENABLE_WRITEBACK is enabled.
Create /path/to/koshelfdata on the host and make it writable by UID 1000 before starting the container (for example, sudo mkdir -p /path/to/koshelfdata followed by sudo chown 1000:1000 /path/to/koshelfdata). Keep this directory persistent: it stores databases, preserved metadata, and covers.
services:
koshelf:
image: ghcr.io/devtigro/koshelf:latest
ports:
- "3000:3000"
volumes:
- /path/to/your/books:/books:rw
- /path/to/your/settings:/settings:ro
- /path/to/koshelfdata:/data:rw
environment:
KOSHELF_TITLE: "My KoShelf"
restart: "unless-stopped"Start the web server. Serves the embedded React app at / with API endpoints under /api/**, and automatically refreshes data on library changes. (Default in the container)
Export uses a separate subcommand. Override the entrypoint with --entrypoint koshelf and pass export /output; mount a writable output directory. KOSHELF_OUTPUT, KOSHELF_WATCH, and KOSHELF_INCLUDE_FILES apply only to export, not the default serve command.
docker exec koshelf koshelf set-password
set or rotate the serve-mode authentication password, for details see https://github.com/paviro/KoShelf/blob/main/docs/authentication.md
docker exec koshelf koshelf list-languages
Print all supported UI locales and exit.
docker exec koshelf koshelf github
Print the repository URL and exit.
Mount your TOML file and set KOSHELF_CONFIG to its container path. CLI arguments take precedence over environment variables, then TOML settings. The image defaults for library path, statistics database, data path, port, authentication, unread items, and stable metadata also take precedence over TOML.
The two volumes mounted into the container (/books and /settings) can be kept up to date automatically by syncing them with Syncthing or any other file synchronization tool. This means:
You can run Syncthing on your host or across multiple devices to sync your KOReader books and settings folders in real-time.
The KoShelf Docker container will automatically reflect the latest notes, highlights, and settings without needing to restart or manually update data.
This setup allows for seamless syncing of your reading data between devices while KoShelf always serves the most recent version.
KoShelf reads its environment variables directly, including new options in 2026.10.0 and 2026.10.1. Use quoted "true" and "false" values in Compose. See the upstream configuration reference for the full list.
| Enviroment Variable | cli flag | explanaition |
|---|---|---|
| KOSHELF_LIBRARY_PATH: "/books" | --library-path | Path(s) to folders containing ebooks (EPUB, FB2, MOBI) and/or comics (CBZ, CBR) with KoReader metadata. Can be specified multiple times. replaces the deprecated KOSHELF_BOOKS_PATH (can still be used for now) |
| KOSHELF_STATISTICS_DB: "/settings/statistics.sqlite3" | --statistics-db | Path to the statistics.sqlite3 file for additional reading stats |
| KOSHELF_PORT: 3000 | --port | Port for web server mode (default: 3000) |
| KOSHELF_DOCSETTINGS_PATH: "/docsettings" | --docsettings-path | Path to KOReader's docsettings folder for users who store metadata separately (requires KOSHELF_LIBRARY_PATH; may be combined with KOSHELF_HASHDOCSETTINGS_PATH) |
| KOSHELF_HASHDOCSETTINGS_PATH: "/hashdocsettings" | --hashdocsettings-path | Path to KOReader's hashdocsettings folder for users who store metadata by content hash (requires KOSHELF_LIBRARY_PATH; may be combined with KOSHELF_DOCSETTINGS_PATH) |
| KOSHELF_KOBO_DB: "/books/.kobo/KoboReader.sqlite" | --kobo-db | Path to Kobo's KoboReader.sqlite database for matching extensionless kepub files. Requires KOSHELF_LIBRARY_PATH. |
| KOSHELF_OUTPUT: "/output" | positional output | Output directory for export only |
| KOSHELF_WATCH: "true" | --watch | Enable file watching with static output (requires KOSHELF_OUTPUT) |
| KOSHELF_TITLE: "My KoShelf" | --title | Site title (default: "KoShelf") |
| KOSHELF_INCLUDE_UNREAD: "true" | --include-unread | Include unread items (files without KoReader metadata) |
| KOSHELF_HEATMAP_SCALE_MAX: "auto" | --heatmap-scale-max | Maximum value for heatmap color intensity scaling (e.g., "auto", "1h", "1h30m", "45min"). Values above this will still be shown but use the highest color intensity. Default is "auto" for automatic scaling |
| KOSHELF_TIMEZONE: "Europe/Oslo" | --timezone | Timezone to interpret timestamps (IANA name, e.g., Australia/Sydney); defaults to system local |
| KOSHELF_DAY_START_TIME: "02:00" | --day-start-time | Logical day start time as HH:MM (default: 00:00) |
| KOSHELF_MIN_PAGES_PER_DAY: 3 | --min-pages-per-day | Minimum pages read per book per day to be counted in statistics |
| KOSHELF_MIN_TIME_PER_DAY: "10m" | --min-time-per-day | Minimum reading time per book per day to be counted in statistics (e.g., "15m", "1h") Note: If both KOSHELF_MIN_PAGES_PER_DAY and KOSHELF_MIN_TIME_PER_DAY are provided, a book's data for a day is counted if either condition is met for that book on that day. These filters apply per book per day, meaning each book must individually meet the threshold for each day to be included in statistics. |
| KOSHELF_INCLUDE_ALL_STATS: "true" | --include-all-stats | By default, statistics are filtered to only include books present in your KOSHELF_BOOKS_PATH directory. This prevents deleted books or external files (like Wallabag articles) from skewing your recap and statistics. Use this flag to include statistics for all books in the database, regardless of whether they exist in your library. |
| KOSHELF_IGNORE_STABLE_PAGE_METADATA: "false" | --ignore-stable-page-metadata | Legacy alias: KOSHELF_IGNORE_STABLE_METADATA. Ignore KOReader stable page metadata for page totals and page-based stats scaling. By default, stable metadata is used when available. |
| KOSHELF_LANGUAGE: "de_DE" | --language | Language for UI translations. Use full locale code (e.g., en_US, de_DE, pt_BR) for correct date formatting. Default: en_US |
| KOSHELF_ENABLE_AUTH: "true" | --enable-auth | start server with auth enabled (on first run, KoShelf generates a password and prints it once) for details see https://github.com/paviro/KoShelf/blob/main/docs/authentication.md |
| KOSHELF_ENABLE_WRITEBACK: "true" | --enable-writeback | writeback enabled (edit annotations and metadata from the UI) for this to work the folder KOSHELF_LIBRARY_PATH (or if used KOSHELF_DOCSETTINGS_PATH or KOSHELF_HASHDOCSETTINGS_PATH) needs to be writable by UID 1000 |
| KOSHELF_TRUSTED_PROXIES: "172.20.0.2/32" | --trusted-proxies | Comma-separated or repeated trusted reverse proxy IP/CIDR entries for forwarded client IP/proto resolution |
for detailed information regarding the cli flags please look at the Koshelf repository too.
| Environment variable | Default | Purpose |
|---|---|---|
KOSHELF_DATA_PATH |
/data (image default) |
Persistent databases, preserved metadata, and covers. Must be writable by UID 1000. |
KOSHELF_ARCHIVE_ENABLED |
"true" |
Preserve missing library entries with persistent storage. |
KOSHELF_ARCHIVE_RETENTION_DAYS |
"30" |
Retain saved files after an archived entry is removed: days, 0, or forever. Archived entries do not expire automatically. |
KOSHELF_ENABLE_LIBRARY_MANAGEMENT |
"false" |
Allow removal of archived entries. |
KOSHELF_DOCUMENT_METADATA_FOLDER |
"doc" |
KOReader metadata location: doc, dir, or hash. |
KOSHELF_BIND_ADDRESS |
"0.0.0.0" |
Server listen address inside the container. |
KOSHELF_AUTH_PROXY_PEERS |
empty | Comma-separated proxy IPs/CIDRs allowed to assert authentication and a path prefix. Requires KOSHELF_ENABLE_AUTH: "true". |
For proxy authentication and subpath hosting, the trusted proxy supplies X-KoShelf-User and X-Forwarded-Prefix. It must strip these headers from unauthenticated requests. KOSHELF_TRUSTED_PROXIES alone does not authorize proxy authentication. Follow the upstream proxy setup.
Run python3 -m unittest discover -s tests -v to check entrypoint argument handling and legacy aliases without downloading KoShelf.