Skip to content

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.

  • 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).
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:
Terminal window
docker compose up -d

Open http://localhost:3000. The first user to sign in becomes the admin — continue to First boot.

To just confirm the image runs, start it with no configuration:

Terminal window
docker run --rm -p 3000:3000 narratorr/narratorr-requests:latest

Out 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.

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.

VariableDefaultPurpose
SESSION_SECRETHMAC key for session cookies. Required in production (dev auto-generates an ephemeral one). Supports the _FILE convention.
SETTINGS_KEYderived from SESSION_SECRETDedicated key for encrypting connector secrets at rest. Set a stable one to decouple them from session-secret rotation. Supports the _FILE convention.
NODE_ENVdevelopmentproduction enables the prod posture (secure cookies, AUTH_BYPASS refusal, etc.).
BEHIND_TLSdefaults to NODE_ENV=productionWhether 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_BYPASSfalseDev shortcut — seeds a dev admin, every request is that admin. Refused in prod / non-loopback.
ALLOW_INSECURE_AUTH_BYPASSfalseEscape hatch to allow AUTH_BYPASS on a non-loopback bind.
LOCAL_AUTHtrueEnable local email/password auth.
OIDC_PROVIDERSComma-separated OIDC provider ids; each configured with OIDC_<ID>_*. See Authentication. OIDC_<ID>_CLIENT_SECRET supports the _FILE convention too.
BOOTSTRAP_ADMINPin admin to <provider>:<subjectOrUsername>; disables first-user-auto-admin.
TRUSTED_PROXIESoffTrust X-Forwarded-* for the real client IP behind a reverse proxy (for rate-limit keying).
BIND_HOST127.0.0.1Listen interface (the Docker image sets 0.0.0.0).
DATABASE_PATH/data/narratorr-requests.db (image)libSQL database file.
PORT3000HTTP 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.

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.txt

Behavior:

  • The file’s contents are trimmed (a trailing newline from echo/editors won’t corrupt the value).
  • <NAME>_FILE takes precedence over the plain <NAME> if both are set.
  • An explicitly-set _FILE that’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 _FILE unset and behavior is unchanged from a plain env var.
  1. Open the app and sign in — create a local account, or use an OIDC provider if you configured one.

  2. The first user becomes admin + active automatically. (Pin a specific identity instead with BOOTSTRAP_ADMIN — see Authentication.)

  3. Go to Settings and enter your narratorr connection (Server URL + API key) — use Test to verify, then Save. See Configuration.

  4. 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.

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.

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).

  1. Clone and install

    Terminal window
    git clone https://github.com/tjiddy/narratorr-requests.git
    cd narratorr-requests
    pnpm install
  2. Build

    Terminal window
    pnpm build
  3. Run (set SESSION_SECRET + an auth method in the environment first)

    Terminal window
    node dist/server/index.js