Deployment and Maintenance
This page covers operating a Docker deployment after the initial Getting Started setup.
The image runs one Shisho process that serves both the web interface and API on container port 5173. It does not require a separate web server inside the container. The entrypoint prepares /config ownership and starts Shisho as PUID and PGID; Shisho handles shutdown directly.
Choose an Image Tag
Published images support Linux AMD64 and ARM64.
- A pinned release tag, such as
ghcr.io/shishobooks/shisho:0.0.49, keeps deployments reproducible and changes only when you edit the tag. ghcr.io/shishobooks/shisho:latestfollows the newest release and is convenient for evaluation, but a future pull may introduce application and database changes.
Use a pinned tag for installations where you want to review and schedule each update.
Persistent State
With the default container paths, persist /config. It contains:
- The SQLite database at
/config/shisho.db - Server caches under
/config/cache - Installed plugins and plugin data under
/config/plugins /config/shisho.yaml, if you use a config file
Also protect these deployment-specific resources:
- The deployment secret containing
JWT_SECRET - Writable media, including Shisho-generated covers and sidecars
- A custom database path if
DATABASE_FILE_PATHpoints outside/config - Custom cache or plugin directories if they point outside
/config
The image creates /config and adjusts its ownership for PUID and PGID. It does not create or adjust ownership for /data, /media, or other custom mounts.
Back Up Shisho
Stop the container before making a filesystem copy of the database. SQLite may use write-ahead logging, so copying only shisho.db while Shisho is running can omit committed data from the -wal file or capture mismatched files.
For the bind-mount layout from Getting Started:
docker compose stop shisho
tar -C . -czf "shisho-config-$(date +%Y%m%d-%H%M%S).tar.gz" config
docker compose start shisho
Store the archive and the JWT secret securely. If the database, cache, plugin data, or media uses another host path or volume, back it up separately while the container is stopped. Media backups matter because scans and metadata edits can write sidecars and covers, and file organization can move or rename content.
Test backups by restoring them in an isolated environment. An untested archive is not a recovery plan.
Update Shisho Safely
Shisho automatically applies forward database migrations during startup. Database downgrades are not guaranteed, so changing the image tag back may not make a database migrated by a newer release compatible with an older release.
Take and test a stopped-container backup before updating. Recovery may require restoring that pre-update backup as well as the corresponding application version.
- Read the release notes and choose the target tag. When a release changes something you must act on (a renamed config option, a changed default, a removed route), it is listed under Breaking Changes at the top of the release notes and of that version's entry in
CHANGELOG.md. - Stop Shisho and take a backup of
/configand any custom state paths. - Update the image tag in
docker-compose.yml. - Pull and recreate the container.
- Inspect logs, health, and normal library access.
docker compose stop shisho
# Back up persistent state here.
docker compose pull shisho
docker compose up -d
docker compose logs -f shisho
Startup applies migrations before the web frontend is served.
Restore a Backup
Do not restore only shisho.db from a live filesystem copy, and do not use a restore to downgrade a newer database in place. Restore a complete, consistent stopped-container backup and select an application version compatible with it. Keep the current state until the restored installation has been verified.
- Stop Shisho.
- Move the current state aside rather than deleting it immediately.
- Restore the complete
/configbackup, plus any custom database, plugin, cache, media, and secret paths. - Select an application version compatible with the restored database.
- Start Shisho and inspect migration and startup logs.
- Verify login, libraries, and representative files before removing the previous state.
Health Checks
The image exposes:
GET /health
Use it as a liveness signal that the HTTP service is responding:
curl --fail http://localhost:5173/health
The endpoint is not a database readiness or integrity check. It does not replace checking startup logs, confirming migrations completed, logging in, or reading representative library data.
Logs
Follow container output with:
docker compose logs -f shisho
The image emits JSON logs by default. Set LOG_FORMAT=console for human-readable output. Successful frontend asset requests are omitted from request logs; application API, integration, and error responses are logged. The Settings > Logs page shows recent application logs and streams new ones live to users with Config Read permission. Container logs remain important for startup failures and reverse proxy issues.
HTTPS and Reverse Proxies
Shisho trusts forwarded headers from private-network peers. A client that can reach the origin through such a peer can influence generated URLs and secure-cookie handling if the proxy passes through client-supplied headers. Restrict origin access to your trusted proxy and have it overwrite forwarded headers before exposing the service. Keep direct access on a trusted local network if you do not need public access.
Terminate HTTPS at a trusted reverse proxy and proxy to Shisho's container port 5173. Preserve the original Host and supply X-Forwarded-Proto for the public scheme. Kobo also uses X-Forwarded-Host and X-Forwarded-Port when provided.
Shisho accepts X-Forwarded-Proto, X-Forwarded-Host, X-Forwarded-Port, X-Forwarded-Prefix, and X-Forwarded-For only when the direct TCP peer is loopback, link-local, an RFC 1918 IPv4 address, or an IPv6 unique-local address in fc00::/7. It strips these headers from public-address peers. Trust depends on the direct connection, not an address claimed in X-Forwarded-For. Connect a remote proxy over a private network if its public address would otherwise reach Shisho directly.
Shisho must be served from the origin root, such as https://books.example.com/. Deploying it below a path prefix such as https://example.com/shisho/ is not supported.
The reverse proxy must pass all of these public route families without rewriting them to the frontend:
/api/*for the application API and event streams/opds/*for OPDS feeds/kobo/*for Kobo sync/ereader/*for the eReader browser/e/*for short eReader setup URLs
Do not strip /api before forwarding it. Also pass /health if your external monitor uses it. Avoid response buffering for streaming API responses. The browser interface and API must share an origin; Shisho does not send CORS permission headers for cross-origin browser access.
Review authentication for OPDS, Kobo, and eReader links before publishing them. Treat device URLs and API keys as secrets.
Response Handling
Shisho uses gzip for eligible responses of at least 1 KiB when the client accepts it. Event streams, covers, page images, and file downloads bypass gzip. Keep proxy buffering disabled for event streams so live updates arrive promptly.
Hashed frontend files under /assets/ carry Cache-Control: public, max-age=31536000, immutable. The frontend's index.html uses Cache-Control: no-cache so browsers revalidate it. Do not override these with a blanket proxy cache rule. Unknown paths under /api, /opds, /kobo, /ereader, and /e return JSON errors rather than the frontend page; other unknown paths open the frontend.
Responses include X-Frame-Options: SAMEORIGIN, X-Content-Type-Options: nosniff, and Referrer-Policy: strict-origin-when-cross-origin. Shisho does not emit a Server header or the deprecated X-XSS-Protection header. A reverse proxy may add its own headers, so check the public response when auditing the deployment.
Outbound Connections
Core local library management does not require sending your library to a hosted Shisho service. Features you explicitly use can make outbound connections, including plugin repository access, plugin installation and updates, metadata or cover providers configured through plugins, Audible chapter lookup, and Kobo integration. Plugins can implement their own network behavior, so review a plugin and its configuration before enabling it.
Maintain Server Caches
Generated downloads, cover thumbnails, extracted CBZ pages, and rendered PDF pages live under CACHE_DIR, which defaults to /config/cache. Each of these four caches has its own size limit under Settings > Cache.
Cover thumbnails are generated only when the web interface requests a size. Scanning a library does not generate every thumbnail size. The first view of an uncached cover or size can take longer; later requests reuse the saved thumbnail, including after a server restart. See Gallery Size for the display controls.
To change a limit, set Maximum size (GiB) on the cache's card under Settings > Cache, then select Save limit. Fractional values are allowed, from 0 to 1024 GiB. Select No limit instead to let the cache use as much disk space as it needs; the size stays filled in, so clearing No limit later restores it. A saved limit applies immediately and survives restarts. Lowering a limit removes the least recently used files until the cache fits.
| Cache | Default limit | Over the limit |
|---|---|---|
| Cover Thumbnails | 1 GiB | The least recently used thumbnails are removed. 0 keeps no thumbnails on disk, so every uncached request resizes the cover again. |
| Downloads | 5 GiB | After each generated download, the least recently used files are removed until the cache is at 80% of its limit. Cleanup is skipped while a bulk download is running. |
| CBZ Pages and PDF Pages | No limit | The least recently used pages are removed. Pages opened in the last minute are kept so they can finish loading, so the cache can briefly go over its limit. |
Changed covers get new thumbnails on demand, and their older versions are removed when a replacement is generated. Metadata-only edits reuse the existing thumbnails. Generating, evicting, or clearing thumbnails leaves the cover files in your library untouched.
Clearing a cache permanently deletes its generated files, but does not delete the library database, source media, or original covers. Verify that you selected the intended cache. The content can be regenerated, although the next affected cover, download, or reader request may be slower.
Users with Config Read permission can open Settings > Cache to inspect each cache. Config Write permission is required to change a limit or select Clear. See Configuration for the cache directory and PDF rendering options.