Docker Quick Start
Prerequisites
- A recent Docker version installed
- A TTS API server that OpenReader can reach:
OpenReader currently pins embedded SeaweedFS to 4.18 in CI and Docker builds.
4.19 introduced intermittent InternalError responses on S3 PutObject in our upload flow.
1. Start the Docker container
- Localhost
- LAN Host
- Minimal
Persistent storage, embedded SeaweedFS weed mini, optional auth, optional library mount:
docker run --name openreader \
--restart unless-stopped \
-p 3003:3003 \
-p 8333:8333 \
-v openreader_docstore:/app/docstore \
-v /path/to/your/library:/app/docstore/library:ro \
-e API_BASE=http://host.docker.internal:8880/v1 \
-e API_KEY=none \
-e BASE_URL=http://localhost:3003 \
-e AUTH_SECRET=$(openssl rand -hex 32) \
-e ADMIN_EMAILS=you@example.com \
ghcr.io/richardr1126/openreader:latest
What this command enables:
-p 3003:3003: exposes the OpenReader web app/API.-p 8333:8333: exposes embedded SeaweedFS S3 endpoint for direct browser presigned upload/download.-v openreader_docstore:/app/docstore: persists SQLite metadata, SeaweedFS blob data, and migration/runtime state.-v /path/to/your/library:/app/docstore/library:ro: mounts a read-only importable library source.-e API_BASE=.../-e API_KEY=...: first-boot seed only. On the first container start, these are auto-migrated into adefault-openaiadmin shared provider stored in the DB (key encrypted at rest). After that, the running app no longer reads them — manage the provider from Settings → Admin → Shared providers. See Admin Panel.-e BASE_URL=...and-e AUTH_SECRET=...: together they turn on auth/session mode for local sign-in flows.-e ADMIN_EMAILS=...: (optional, requires auth) comma-separated emails auto-promoted to admin. Admins see the Admin tab in Settings.
Use this when the app should be reachable from other devices on your LAN:
docker run --name openreader \
--restart unless-stopped \
-p 3003:3003 \
-p 8333:8333 \
-v openreader_docstore:/app/docstore \
-e API_BASE=http://host.docker.internal:8880/v1 \
-e BASE_URL=http://<YOUR_LAN_IP>:3003 \
-e AUTH_SECRET=$(openssl rand -hex 32) \
-e AUTH_TRUSTED_ORIGINS=http://localhost:3003,http://127.0.0.1:3003 \
-e USE_ANONYMOUS_AUTH_SESSIONS=true \
-e ADMIN_EMAILS=you@example.com \
ghcr.io/richardr1126/openreader:latest
Replace YOUR_LAN_IP with the Docker host IP address on your local network to allow access from other devices.
What this command enables:
- LAN access from phones/tablets/other computers via
http://<YOUR_LAN_IP>:3003. BASE_URLpoints auth/session cookies and callbacks at your LAN URL.AUTH_TRUSTED_ORIGINSallows localhost loopback origins in addition to your primary LAN origin.USE_ANONYMOUS_AUTH_SESSIONS=trueallows guest sessions while auth is enabled.API_BASEseeds the default TTS endpoint into the admin-manageddefault-openaishared provider on first boot. Edit it from Settings → Admin → Shared providers after that.ADMIN_EMAILS=...(optional) auto-promotes the listed email(s) to admin so they can manage shared providers and site feature flags from the UI.openreader_docstorevolume keeps data persistent across restarts.
Auth disabled, embedded storage ephemeral, no library import:
docker run --name openreader \
--restart unless-stopped \
-p 3003:3003 \
-p 8333:8333 \
ghcr.io/richardr1126/openreader:latest
What this command enables:
- Fastest startup with no extra env vars.
- No persistent volume (
/app/docstorestays container-local), so data is ephemeral unless you add a mount. - Auth remains disabled because
BASE_URLandAUTH_SECRETare not set. The admin panel requires auth, so it's unavailable in this mode. - No TTS provider preset by default. Configure
API_BASE/API_KEYon first boot if you want a seeded shared provider, or run auth+admin mode and manage providers from the admin panel.
- Set
API_BASEon first boot to a TTS endpoint the container can reach (host.docker.internalworks for host-local services). After first boot, manage providers in Settings → Admin → Shared providers. - Auth is enabled only when both
BASE_URLandAUTH_SECRETare set. The admin panel requires auth. - Set
ADMIN_EMAILSto your email if you want the Admin tab in Settings. restrictUserApiKeyscontrols shared-provider-only mode. For per-user BYOK in auth-enabled setups, toggle it off in Settings → Admin → Site features. Legacy first-boot seed viaNEXT_PUBLIC_RESTRICT_USER_API_KEYS=falseis still supported.- Use a
/app/docstoremount if you want data to survive container/image replacement. - Startup automatically runs DB/storage migrations via the shared entrypoint.
8333 ExposureExpose 8333 for direct browser presigned upload/download with embedded SeaweedFS.
If 8333 is not reachable from the browser, direct presigned access is unavailable. Uploads can still fall back to /api/documents/blob/upload/fallback, and document reads/downloads continue through /api/documents/blob.
2. Configure settings in the app UI
Visit http://localhost:3003 after startup.
- If you set
ADMIN_EMAILS, sign in with that email and open Settings → Admin to manage shared TTS providers and site feature flags for all users. - Per-user: set TTS provider/model in Settings → TTS Provider. API key/base URL inputs are shown only when
restrictUserApiKeys=false. - Select the model voice from the voice dropdown.
3. Update Docker image
Legacy image compatibility: ghcr.io/richardr1126/openreader-webui:latest remains available as an alias.
docker stop openreader || true && \
docker rm openreader || true && \
docker image rm ghcr.io/richardr1126/openreader:latest || true && \
docker pull ghcr.io/richardr1126/openreader:latest
If you use a mounted volume for /app/docstore, your persisted data remains after image updates.