# Database DATABASE_URL=postgres://bookorbit:bookorbit@localhost:5432/bookorbit # App PORT=3000 # Listen address (IPv4 or IPv6, without brackets). Unset or blank keeps 0.0.0.0. # Use 127.0.0.1 for local-only native deployments. # HOST=0.0.0.0 NODE_ENV=development # API docs (optional) # Set to true to serve Swagger UI at /api/docs and OpenAPI JSON at /api/docs-json. # SWAGGER_ENABLED=false # Auth JWT_SECRET=change-me-in-production JWT_EXPIRES_IN=15m JWT_REFRESH_EXPIRES_IN=7d # Required in production for initial /auth/setup (x-setup-token header) SETUP_BOOTSTRAP_TOKEN= # Storage # App data directory for covers, author images, user avatars, and cache. # This path resolves relative to server/ (where the process runs). # ../local/data points to /local/data. APP_DATA_PATH=../local/data # Top of the library creation folder picker. Defaults to / when unset. # Set this to the server-visible folder where users should create libraries. # LIBRARY_BROWSE_ROOT=../local/books # Staging area a fulfilled book request is filed through. Defaults to /book-dock. # # Put this inside the same mount as your download client's completed directory. A finished # download is hardlinked into the dock so the torrent keeps seeding from the same bytes, and two # separate bind mounts of one filesystem still refuse the link even though they report the same # device: under Docker or Kubernetes that means every fulfilment silently copies and uses the # space twice. Linux fs.protected_hardlinks=1 also requires the BookOrbit process user to own the # completed source file or be able to write it. Run BookOrbit and the download client with the same # UID, or use a shared group that grants BookOrbit write access to completed files. The per-mapping # test under Settings > System > Requests creates a BookOrbit-owned file, so it validates the mount # and paths but cannot prove that a differently-owned completed file is linkable. # BOOK_DOCK_PATH=../local/data/book-dock # File write scheduler and concurrency tuning (optional) # FILE_WRITE_DEBOUNCE_MS=3000 # FILE_WRITE_MAX_CONCURRENT_WRITES=2 # Podcast security and resource limits # Required in production. Development falls back to JWT_SECRET when unset. # Existing production installs must initially use their current JWT_SECRET so encrypted feed URLs remain readable. # Generate with: openssl rand -hex 32 # PODCAST_ENCRYPTION_KEY= # PODCAST_MAX_FEED_BYTES=10485760 # PODCAST_MAX_EPISODE_BYTES=2147483648 # PODCAST_MAX_CONCURRENT_DOWNLOADS=2 # PODCAST_REQUEST_TIMEOUT_MS=30000 # PODCAST_MAX_DOWNLOAD_DURATION_MS=21600000 # Limits for rebuilding read-along EPUBs without their narration audio (KOReader downloads). # AUDIOLESS_EPUB_MAX_CONCURRENT_BUILDS=2 # AUDIOLESS_EPUB_MAX_SOURCE_ENTRIES=50000 # AUDIOLESS_EPUB_MAX_METADATA_BYTES=16777216 # AUDIOLESS_EPUB_MAX_OUTPUT_BYTES=2147483648 # KOReader plugin source folder served by the preconfigured plugin download (optional). # Defaults to /koreader-plugin/bookorbit.koplugin in dev; the Docker image sets it. # KOREADER_PLUGIN_PATH=../koreader-plugin/bookorbit.koplugin # Optional: allow Cloudflare Web Analytics beacon in CSP when automatic setup is enabled. # Keep unset/false to preserve strict CSP (`script-src 'self'`). # CSP_ALLOW_CLOUDFLARE_INSIGHTS=false # OIDC (optional - configure via admin settings UI; these are just for reference) # OIDC config is stored in the database (app_settings table, key: oidc_config) # OIDC runtime tuning (optional - uncomment to override defaults) # OIDC_STATE_TTL_SECS=600 # OIDC_DISCOVERY_CACHE_TTL_SECS=3600 # OIDC_JWKS_CACHE_TTL_SECS=3600 # OIDC_CLOCK_TOLERANCE_SECS=30 # OIDC_TOKEN_EXCHANGE_TIMEOUT_MS=10000 # Allow OIDC issuer/discovery URLs that resolve to private/local addresses in production. # Default false. Keep false unless you intentionally trust your private network. # OIDC_ALLOW_LOCAL_ISSUERS=false # Trust additional PEM-encoded certificate authorities for outbound TLS, including OIDC. # Mount the CA bundle read-only, set its in-container path here, and restart BookOrbit. # NODE_EXTRA_CA_CERTS=/path/to/private-ca-bundle.pem # Disable username/password sign-in after at least one active administrator has linked an enabled # OIDC provider. Set false and restart to recover access if the identity provider is unavailable. # DISABLE_LOCAL_AUTH=false # App URL (used for building password reset links in emails) APP_URL=http://localhost:5173 # Email encryption key (optional but recommended - 64-char hex string for AES-256) # Generate with: openssl rand -hex 32 # EMAIL_ENCRYPTION_KEY= # Migration encryption key (optional but recommended - 64-char hex string for AES-256) # Encrypts source connection credentials at rest. # Generate with: openssl rand -hex 32 # MIGRATION_ENCRYPTION_KEY= # Book request encryption key (required before a download client or indexer can be saved). # Unlike the two keys above, credentials are refused rather than stored in the clear when this # is unset. 64-char hex string for AES-256. # Generate with: openssl rand -hex 32 # BOOK_REQUEST_ENCRYPTION_KEY= # Server-side root containing migration backup files (optional). # Use a dedicated read-only mount. Backup paths submitted through the migration API # must be absolute and resolve inside this root. # MIGRATION_IMPORT_ROOT=/imports # SMTP for system emails (password reset) is configured via the admin UI, # not via environment variables.