# Configuration reference For setup examples and help applying changes, see the [configuration guide](https://docs.cantinarr.com/install/configuration/). ## Service credentials and AI Shared service credentials are managed through the admin UI -- no environment variables are needed for API keys. AI is different from the other integrations: an admin can configure a server profile using an API key or a shared OAuth link (OpenAI or xAI Grok), while every user can independently configure the same choices as a personal override. API keys and OAuth authorization stay encrypted and server-side. Self-hosted AI is its own provider: pick **Local (OpenAI-compatible)** in **Settings > Providers & Credentials**, enter the server's base URL (llama.cpp `llama-server`, vLLM, Ollama, and similar; use the endpoint's final URL, usually ending in `/v1` -- redirects are not followed) and the model ID it hosts. No API key is needed (an optional token slot covers proxies that check auth), the same save-time test proves the endpoint before anything is stored, and personal OpenAI keys are unaffected and keep using api.openai.com. Both the Local and hosted OpenAI providers offer a reasoning-effort pin (Auto/None/Minimal/Low/Medium/High) -- None keeps thinking-heavy local models fast, Auto preserves the provider's own default. Every provider, model, remediation-model override, or key save -- and every completed OAuth selection -- must complete one small real, tool-free, low-reasoning message-response turn before Cantinarr activates it. Validation reports a safe actionable category for an invalid credential, unsupported model/access, exhausted quota, or temporary provider outage without exposing upstream secrets. OpenAI OAuth offers the recommended Codex model plus GPT-5.6 Sol, Terra, and Luna. xAI Grok (OAuth) signs in with a SuperGrok or X Premium+ account via xAI's device flow and serves the same Grok models as the API-key path. The server also runs one small shared-model health turn every 24 hours by default. A failure opens one deduplicated admin-only issue; a later successful turn resolves it. Admins who want zero background AI usage can disable this check in **Settings > Providers & Credentials** without weakening the mandatory save-time test. The remediation agent remains independent of this monitor and always resolves credentials directly from the admin's shared profile. Included AI is an explicit per-user entitlement for new accounts; the initial admin starts enabled. Upgrades preserve the previous global-provider behavior for existing users so access does not disappear, after which the admin can revoke or grant it from **Settings > Users**. Enabling an OpenAI OAuth-backed grant shows the shared-account allowance and cost warning before it is applied. ## Service settings | Setting | Where | Description | |---|---|---| | TMDB access token | Admin UI | Optional -- discovery and search ship working on Cantinarr's built-in public key; add your own token to use your TMDB account instead ([get one here](https://www.themoviedb.org/settings/api)) | | Radarr/Sonarr instances | Admin UI | Add via Settings > Add Instance | | Chaptarr instance | Admin UI | Books module; grant access per user from the instance editor or user settings -- full walkthrough in [`docs/books-setup.md`](books-setup.md) | | Lidarr instance | Admin UI | Music module; grant access per user the same way -- full walkthrough in [`docs/music-setup.md`](music-setup.md) | | SABnzbd/qBittorrent/NZBGet/Transmission/Deluge/ruTorrent | Admin UI | Download client modules (queue, history, speeds) | | Tautulli or Tracearr instance | Admin UI | Monitoring: live streams, watch history, stats. Tautulli watches Plex; Tracearr watches Plex, Jellyfin, and Emby (public API key from its Settings > General) | | Tdarr instance | Admin UI | Settings > Add Instance > Tdarr: name, server API URL (normally port 8266, not WebUI port 8265), and optional API key from Tools > API Keys when Tdarr authentication is enabled. The **Transcoding** menu groups these instances with admin-only Activity and Libraries tabs. Blank key edits preserve the saved key; **Remove saved API key** explicitly clears it | | Plex, Jellyfin, Emby, or Audiobookshelf instance | Admin UI | Media server access: per-user grants, shared libraries, the address users open, and Audiobookshelf listening-app defaults; Plex links a plex.tv account with a PIN and picks the server to share | | Anthropic/OpenAI/Gemini/xAI API key | Admin UI | Enables shared API-key-backed AI chat and autonomous remediation | | OpenAI reasoning effort | Admin UI | Optional; pins `reasoning_effort` for the shared OpenAI provider (none/minimal/low/medium/high). Auto sends no effort field; endpoints that reject the field fall back automatically | | Local (OpenAI-compatible) | Admin UI | First-class shared provider for self-hosted OpenAI-compatible servers: required base URL and model ID, optional key/token, own reasoning-effort pin. Shared profile only -- never selectable as a personal provider | | OpenAI (OAuth) | Personal link under Settings > AI Access, or an admin-managed shared link | Uses a ChatGPT account's Codex allowance for the selected personal or included model; the admin-shared link also powers server-owned remediation. Per-user shared chat access is opt-in and carries a quota/cost warning | | xAI Grok (OAuth) | Personal link under Settings > AI Access, or an admin-managed shared link | Uses an xAI account's Grok subscription allowance (SuperGrok or X Premium+) via xAI's device flow instead of a metered API key; the admin-shared link also powers server-owned remediation | | Trakt client ID | Admin UI | Enhances discovery + fallback ID bridging; required to select the Trakt trending source under Settings > Discovery, which the headline rows then adopt automatically | | Discovery row source | Admin UI | Settings > Discovery: which feed backs the movie and TV headline rows (Trakt when configured, else TMDB trending), plus the English-only filter (on by default) | | Outbound proxy | Admin UI | Settings > Outbound Proxy: an `http`, `https`, `socks5`, or `socks5h` proxy for the server's internet-bound traffic only (TMDB, Trakt, hosted AI providers, plex.tv, the GitHub update check, the push relay), with an optional username and password stored encrypted -- the password is write-only. Arr instances, download clients, Plex Media Server, Jellyfin/Emby/Audiobookshelf, Tautulli/Tracearr, and the Local AI provider are never proxied, though a Local AI endpoint that lives out on the internet can be switched onto the proxy from its own settings. **Test** fetches TMDB through the proxy and reports the server's reason on failure; a blank address clears it | ## Instance addresses **Instance URLs are dialed only by the Cantinarr server** -- phones and browsers never contact them, so cluster-internal names (Docker service names like `http://radarr:7878`, Kubernetes cluster DNS, Tailscale MagicDNS) are the recommended form, and the arrs never need to be exposed outside their network. One topology exception: a container that shares another container's network stack (`network_mode: container:`, or Unraid's `Container` network type -- common when routing a service through a VPN gateway) has no address or DNS name of its own, so `http://chaptarr:8789` never resolves. Point the instance URL at the gateway that publishes the port instead. The in-app **Test Connection** button runs from the server too, so it tells the truth about these URLs. Plain `http` is fully supported on a trusted network; `https` needs a certificate the server's container trusts (mount an internal CA into the image trust store -- a self-signed cert otherwise fails the connection test with an x509 error). Four service-specific notes: SABnzbd's hostname verification rejects service names it doesn't know, so add the name to its `host_whitelist` (Config > Special) or set the container's hostname to match; for Transmission enter just `scheme://host:port` -- Cantinarr appends `/transmission/rpc`; for Deluge enter the web UI address (port 8112 by default, e.g. `http://deluge:8112`) -- Cantinarr appends `/json` -- and the only credential is its web UI password, since Deluge has no username; for ruTorrent enter the ruTorrent address (e.g. `http://rutorrent:8080`, or the path ruTorrent is served under) -- Cantinarr appends `/plugins/httprpc/action.php` to speak XML-RPC to rTorrent and removes files through the erasedata plugin, both of which ship with ruTorrent, so ruTorrent must have been opened at least once (that is when it learns rTorrent's command names; until then Cantinarr says so and keeps the torrent) -- and the HTTP Basic username and password are optional, needed only when the web server asks for them. Poster and fanart images load on devices straight from the TMDB/TVDB CDNs, so client devices still need internet egress to those hosts. ## Outbound proxy **Internet-bound traffic can ride a proxy** -- the pattern Radarr and Sonarr users know from Settings > General > Proxy, for a server whose metadata and AI traffic should leave through a VPN: run Privoxy or 3proxy beside the VPN gateway on the same Docker host, then enter it under **Settings > Outbound Proxy** as an `http`, `https`, `socks5`, or `socks5h` URL (`http://proxy:8118`, no path) with an optional username and password. The password is write-only and the whole setting is stored encrypted; **Test** fetches TMDB's configuration through the candidate proxy and reports the server's reason when it fails (wrong port, wrong password, and so on). Only traffic that leaves for the internet takes that route: TMDB, Trakt (the API and the artwork relay), the hosted AI providers (Anthropic, OpenAI, Gemini, xAI Grok, and the bundled Codex app-server through its environment), plex.tv, the GitHub update check, and the push relay. Arr instances, download clients, Jellyfin, Emby, Audiobookshelf, Tautulli and Tracearr, the instant-updates webhook install, the instance connection test, and the Local (OpenAI-compatible) AI provider are dialed directly -- not even `HTTP_PROXY` in the environment changes that -- so `NO_PROXY` never needs your arr hosts, and a deployment that relied on `HTTP_PROXY` to reach its arrs now dials them directly. The Local AI provider is the one you can move, because its endpoint is the only one you type in yourself: if it is a rented GPU box or any other server out on the internet rather than one on your own network, turn on **Route through the outbound proxy** beside its base URL under **Settings > Providers & Credentials** and that endpoint alone joins the internet-bound list above. It is off by default, and Cantinarr will not guess it from the address, because split-horizon DNS and Tailscale both hand out names that an address test reads wrong. The in-app setting proxies every internet-bound host with no bypass list; when it is empty, the standard `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY` variables (Go's semantics, lower-case names accepted) apply to the same traffic instead. Two caveats: a self-hosted push relay on the LAN counts as internet-bound, so that layout belongs on the env vars with `NO_PROXY` rather than the in-app setting; and the bundled Codex app-server reads the proxy through its environment, so use an HTTP or HTTPS proxy when OpenAI (OAuth) is the AI provider -- Cantinarr does not verify its SOCKS support. The proxy is server-side only: devices keep loading posters straight from the TMDB/TVDB CDNs as above. ## Requester tags Each Radarr, Sonarr, Chaptarr, or Lidarr instance has a **Tag requests with requester** setting, off by default. Enable and save it in the instance editor to add native requester tags for newly submitted requests after approval and successful library delivery. Tags use the original requester and preserve existing tags. Radarr tags movies, Sonarr tags series, Lidarr tags artists, and Chaptarr tags authors for the requested eBook or audiobook format. Artist and author tags also apply to their other albums or books. Shared book subscribers have separate tagging results. Turning it off or changing the instance URL cancels unfinished tagging; applied tags remain. Re-enabling does not backfill old history. Check **Approvals > History** for status and **Retry tag**. No environment variable is required. ## Library file downloads Completed-media downloads are deliberately opt-in because Radarr, Sonarr, Chaptarr, and Lidarr report paths but do not serve those file bytes through their APIs. Configuration has two layers: the deployment makes each wanted library read-only to Cantinarr and lists the Cantinarr-visible boundary in `CANTINARR_MEDIA_ROOTS`, then the admin maps each media instance's reported path to a folder inside that boundary from the instance editor. The two paths do not have to match, and an arr source may use POSIX, Windows drive, or UNC syntax regardless of the Cantinarr host OS. For Docker, for example, mount `- /mnt/nas/media:/media:ro`, set `CANTINARR_MEDIA_ROOTS=/media`, and map Radarr's `/data/media/movies` to `/media/movies`; a native server instead uses an absolute local directory readable by its process. A Chaptarr instance may have separate mappings for `/ebooks`, `/audiobooks`, `/yana-ebooks`, and `/yana-audiobooks`; folder names never determine the book format. Albums are delivered per track, never repackaged into an archive. Download controls are enabled per instance: an instance offers downloads only after an admin saves explicit path mappings for it, and every instance starts with media downloads off. Cantinarr accepts only live file IDs from a user's explicitly assigned Radarr, Sonarr, Chaptarr, or Lidarr instance, refuses files outside that instance's mappings and the global roots, and gives the app a short-lived file-scoped link so large files stream through the browser or operating system without buffering in Flutter. The feature covers the primary files indexed by the arrs, not arbitrary files, subtitles, or extras found on disk. ## Environment variables Optional server env vars for deployment tuning: | Variable | Default | Description | |---|---|---| | `CANTINARR_PORT` | `8585` | HTTP listen port. Kubernetes service-link values (`tcp://…`) injected by a Service named `cantinarr` are ignored in favor of the default; set a numeric value to override | | `CANTINARR_SERVER_NAME` | `Cantinarr` | Display name shown in clients | | `CANTINARR_ARR_CALLBACK_URL` | direct request origin | Origin the Radarr/Sonarr/Chaptarr/Lidarr containers POST webhooks back to, so it must be resolvable and reachable **from the arrs themselves** -- in same-network/cluster deployments a cluster-internal origin like `http://cantinarr:8585` is usually the right value. Set it explicitly behind a reverse proxy (forwarded headers are deliberately ignored). Formerly `CANTINARR_PUBLIC_URL`, which stays accepted forever (the new name wins when both are set); it was renamed because "public URL" suggested the user-facing address, which is the in-app **Settings > External Address** instead | | `CANTINARR_OAUTH_ISSUER` | request-derived origin | Canonical external HTTPS origin for inbound MCP OAuth metadata, token audience, and browser-origin checks; setting it also enables stable RFC 9207 authorization-response `iss` and permits that origin to call `/mcp`. Set it behind a reverse proxy and keep it stable (changing it makes existing audience-bound MCP tokens reconnect); do not substitute the arr-reachable `CANTINARR_ARR_CALLBACK_URL` | | `CANTINARR_MCP_ALLOWED_ORIGINS` | unset | Comma-separated additional browser origins allowed to call `/mcp`. If neither this nor `CANTINARR_OAUTH_ISSUER` is configured, requests that supply `Origin` are rejected; native and server-side MCP clients need no entry | | `CANTINARR_JWT_SECRET` | auto-generated | HMAC secret for signing short-lived access tokens. Device sessions do not depend on it: changing it never signs anyone out | | `CANTINARR_ENCRYPTION_KEY` | auto-generated key file | Base64 32-byte key for secrets-at-rest (default: `/config/encryption.key`) | | `CANTINARR_AI_PROVIDER` | `codex` | Fallback provider for the included server AI profile when none is saved in the admin UI (`anthropic`, `openai`, `gemini`, `grok`, `codex`, `grok_oauth`, or `local_openai`). Local AI also needs a saved endpoint and an explicit model | | `CANTINARR_AI_MODEL` | provider default | Fallback model for the included server AI profile when none is saved in the admin UI | | `CANTINARR_CODEX_BIN` | auto-discovered | Optional path to `codex-app-server` or the full `codex` CLI; container images bundle the tested 0.144.3 app-server at `/usr/local/bin/codex-app-server` | | `CANTINARR_CODEX_RUNTIME_DIR` | `/dev/shm/cantinarr-codex` | Absolute Linux tmpfs/ramfs directory used for server-owned, ephemeral per-session Codex state; if it already exists, it must be owned by the server user with mode `0700` | | `CANTINARR_MEDIA_ROOTS` | unset | Comma-separated absolute paths forming the outer filesystem allowlist for completed-media downloads. Empty disables file downloads. Mount libraries read-only inside these Cantinarr-visible roots, then map each arr-reported prefix to a path beneath them in that instance's settings; `/` is refused | | `CANTINARR_PUSH_GATEWAY_URL` | unset | Push gateway origin -- setting it enables push notifications (auto-enrolls on first start). The community relay is `https://push.cantinarr.com`; its former name `https://push.julian.codes` is still accepted and rewritten to the new one at start (same gateway, same enrollment) | | `CANTINARR_PUSH_API_KEY` | unset | Optional pinned gateway key (blank = auto-enroll) | | `CANTINARR_PUSH_ENROLL_TOKEN` | unset | Only for gateways with gated enrollment | | `CANTINARR_APPLE_APP_IDS` | unset | `TeamID.BundleID` values for native Apple passkeys (`/.well-known/apple-app-site-association`) | | `CANTINARR_ANDROID_PACKAGE_NAME` | `codes.julian.cantinarr` | Android package name for native passkeys | | `CANTINARR_ANDROID_CERT_SHA256_FINGERPRINTS` | unset | Android signing cert fingerprints for `/.well-known/assetlinks.json` | | `CANTINARR_WEBAUTHN_EXTRA_ORIGINS` | unset | Additional WebAuthn origins to trust | | `CANTINARR_DISABLE_UPDATE_CHECK` | unset | Set to `1` to disable the periodic GitHub release check behind the admin update-status endpoint | | `HTTP_PROXY` / `HTTPS_PROXY` | unset | Standard proxy variables (Go's semantics; lower-case names accepted) for the server's internet-bound traffic only -- TMDB, Trakt, hosted AI providers, plex.tv, the GitHub update check, and the push relay. An address saved under **Settings > Outbound Proxy** wins whenever one is set. Arr instances, download clients, Plex Media Server, Jellyfin/Emby/Audiobookshelf, Tautulli/Tracearr, and the Local AI provider are dialed directly no matter what these say | | `NO_PROXY` | unset | Hosts the env-var proxy skips (Go's semantics). It never needs your arr, download-client, or media-server hosts, because LAN instance traffic is never proxied; it is the right tool for a self-hosted push relay on the LAN, which the in-app setting would proxy | | `PUID` | unset (runs as root) | Container image only. Run the server as this user id: on every start the image takes ownership of `/config` for it, so the database and encryption key it writes are owned by that user on the host (the linuxserver-style convention Synology and Unraid stacks expect). Ignored when the container is already started as a non-root user (compose `user:`, TrueNAS) | | `PGID` | same as `PUID` | Group id to pair with `PUID`; ignored without it | ## Source builds Source image builds also accept the Docker build argument `CANTINARR_E2E_WEB_SEMANTICS` (default `false`). It exists only for the disposable private lab: setting it to `true` compiles deterministic Maestro labels into the Flutter web bundle. Official production images keep the default and preserve normal browser accessibility semantics. OpenAI (OAuth) source deployments use Codex app-server and are supported only on Linux; non-Linux hosts report this provider unavailable even when a Codex binary is installed. The runtime directory's parent must exist, and the directory must be on tmpfs or ramfs; not persistent storage. Give each concurrently running Cantinarr process its own runtime directory; startup removes stale `session-*` entries from that dedicated root. The official container uses its private Docker `/dev/shm` tmpfs. Use the tested Codex 0.144.3 release or a protocol-compatible build. ## Passkeys and device sessions Native app passkeys require a public HTTPS server domain associated with the app (AASA for Apple, Digital Asset Links for Android). Browser passkey setup remains available when native association isn't possible. See [`server/README.md`](../server/README.md#configuration) for details. By default, users are passwordless and passkeyless: a connect link starts a permanent device session, so household members never deal with credentials. Each link signs one device into the app, once. A session never expires -- not from idle time, server restarts, upgrades, or secret rotation -- and ends only when an admin revokes the device (**Settings > Devices**) or deletes the user. Admins grant a password and/or passkey per user from **Settings > Users** when a user needs one -- that is also the durable way to sign in on the web, where clearing browser data wipes the device session a link created. A password is what authorizes MCP clients on deployments served over plain HTTP, where passkeys are unavailable (WebAuthn requires a secure context). Disabling a method is a real revoke -- it clears the stored password or deletes the user's passkeys. To recover access, an admin issues a fresh connect link. Connect links embed a server address. Set **Settings > External Address** to the origin people reach your server through (a reverse proxy domain, a public IP) and links are built from it; left unset, a link uses the address the generating admin's own app is connected with, which usually only works on the admin's network -- the invite dialog says so when that happens.