Installation
narratorr-requests ships as a single container (the Fastify API serves the built SPA). The SQLite database lives on a volume and migrations apply automatically on boot.
Prerequisites
Section titled “Prerequisites”- Docker (recommended) — or Node.js 24.10+ with pnpm for a source install.
- A running narratorr instance and an API key for it (narratorr → Settings → API). You connect to it after first boot, in narratorr-requests’s Settings page.
- A session secret for production (
openssl rand -hex 32).
Docker (recommended)
Section titled “Docker (recommended)”services: narratorr-requests: image: narratorr/narratorr-requests:latest container_name: narratorr-requests ports: - "3000:3000" volumes: - narratorr-requests-data:/data environment: - NODE_ENV=production - AUTH_BYPASS=0 # REQUIRED in production. Generate: openssl rand -hex 32 - SESSION_SECRET=change-me # Pick at least one auth method (see Authentication): - LOCAL_AUTH=true restart: unless-stopped
volumes: narratorr-requests-data:docker compose up -dIf you’d rather keep the database on a host path instead of a named volume:
services: narratorr-requests: image: narratorr/narratorr-requests:latest container_name: narratorr-requests ports: - "3000:3000" volumes: - /path/on/host/narratorr-requests:/data environment: - NODE_ENV=production - AUTH_BYPASS=0 - SESSION_SECRET=change-me - LOCAL_AUTH=true restart: unless-stoppedOpen http://localhost:3000. The first user to sign in becomes the admin — continue to First boot.
Zero-config smoke test
Section titled “Zero-config smoke test”To just confirm the image runs, start it with no configuration:
docker run --rm -p 3000:3000 narratorr/narratorr-requests:latestOut of the box it boots in AUTH_BYPASS mode (a seeded dev admin, every request is that
admin) so you land straight in the UI. GET /api/health reports readiness (it pings the DB and
reports narratorrConfigured), and the container ships a matching HEALTHCHECK. Configure
narratorr in Settings to actually request anything.
Environment variables
Section titled “Environment variables”The connector config (narratorr URL/key and your notifiers) lives in the Settings page, not the environment — so the env surface is deliberately just server + auth + secrets.
| Variable | Default | Purpose |
|---|---|---|
SESSION_SECRET | — | HMAC key for session cookies. Required in production (dev auto-generates an ephemeral one). Supports the _FILE convention. |
SETTINGS_KEY | derived from SESSION_SECRET | Dedicated key for encrypting connector secrets at rest. Set a stable one to decouple them from session-secret rotation. Supports the _FILE convention. |
NODE_ENV | development | production enables the prod posture (secure cookies, AUTH_BYPASS refusal, etc.). |
BEHIND_TLS | defaults to NODE_ENV=production | Whether a reverse proxy / load balancer terminates TLS in front of the app. Gates the CSP upgrade-insecure-requests directive, the HSTS header, and the Secure session cookie flag. Set to false if running production over plain HTTP with no TLS in front — otherwise the browser silently blocks page assets (blank page) and the Secure cookie prevents login. See Troubleshooting. |
AUTH_BYPASS | false | Dev shortcut — seeds a dev admin, every request is that admin. Refused in prod / non-loopback. |
ALLOW_INSECURE_AUTH_BYPASS | false | Escape hatch to allow AUTH_BYPASS on a non-loopback bind. |
LOCAL_AUTH | true | Enable local email/password auth. |
OIDC_PROVIDERS | — | Comma-separated OIDC provider ids; each configured with OIDC_<ID>_*. See Authentication. OIDC_<ID>_CLIENT_SECRET supports the _FILE convention too. |
BOOTSTRAP_ADMIN | — | Pin admin to <provider>:<subjectOrUsername>; disables first-user-auto-admin. |
TRUSTED_PROXIES | off | Trust X-Forwarded-* for the real client IP behind a reverse proxy (for rate-limit keying). |
BIND_HOST | 127.0.0.1 | Listen interface (the Docker image sets 0.0.0.0). |
DATABASE_PATH | /data/narratorr-requests.db (image) | libSQL database file. |
PORT | 3000 | HTTP port. |
The default request quota is not an environment variable — it’s admin-editable in Settings so it can change without a redeploy.
See .env.docker.example
in the repo for a copy-paste production template, including the full OIDC variable pattern.
Docker secrets: the _FILE convention
Section titled “Docker secrets: the _FILE convention”Instead of passing SESSION_SECRET, SETTINGS_KEY, or an OIDC CLIENT_SECRET as a plain
environment variable (readable via docker inspect / /proc/<pid>/environ), point <NAME>_FILE
at a file mounted read-only and the app reads the value from there instead — it never enters
the process environment:
services: narratorr-requests: # ... environment: - SESSION_SECRET_FILE=/run/secrets/session_secret - SETTINGS_KEY_FILE=/run/secrets/settings_key - OIDC_PLEX_CLIENT_SECRET_FILE=/run/secrets/oidc_plex_client_secret secrets: - session_secret - settings_key - oidc_plex_client_secret
secrets: session_secret: file: ./secrets/session_secret.txt settings_key: file: ./secrets/settings_key.txt oidc_plex_client_secret: file: ./secrets/oidc_plex_client_secret.txtBehavior:
- The file’s contents are trimmed (a trailing newline from
echo/editors won’t corrupt the value). <NAME>_FILEtakes precedence over the plain<NAME>if both are set.- An explicitly-set
_FILEthat’s unreadable or empty fails fast at startup, naming the variable and path — never the file contents — rather than silently falling back to an empty secret. - Fully additive: leave
_FILEunset and behavior is unchanged from a plain env var.
First boot
Section titled “First boot”-
Open the app and sign in — create a local account, or use an OIDC provider if you configured one.
-
The first user becomes admin + active automatically. (Pin a specific identity instead with
BOOTSTRAP_ADMIN— see Authentication.) -
Go to Settings and enter your narratorr connection (Server URL + API key) — use Test to verify, then Save. See Configuration.
-
Optionally add a notifier (ntfy, email, Discord, Slack, Telegram, Pushover, Gotify, or a generic webhook) so you’re pinged about new requests, signups, and failed requests.
Published images
Section titled “Published images”CI builds a multi-arch (amd64/arm64) image and pushes to Docker Hub
narratorr/narratorr-requests and GHCR ghcr.io/tjiddy/narratorr-requests:
- Release — a semver tag →
:latest,:X.Y.Z,:X.Y. - Bleeding edge — every push to
develop→:develop.
Upgrading
Section titled “Upgrading”Migrations are forward-only (no down-migrations) and apply automatically on boot. Before upgrading a populated instance, snapshot the data volume / host directory so you can roll back by restoring it and redeploying the previous image (an older image can’t run against a newer schema).
Manual install (from source)
Section titled “Manual install (from source)”-
Clone and install
Terminal window git clone https://github.com/tjiddy/narratorr-requests.gitcd narratorr-requestspnpm install -
Build
Terminal window pnpm build -
Run (set
SESSION_SECRET+ an auth method in the environment first)Terminal window node dist/server/index.js