Skip to content

Docker Deployment

Gadarr runs as one container that serves the Fastify API and the built Vite UI. SQLite data lives under /config, the finished game library is mounted at /games, and download-client paths are exposed through /downloads and optional read-only /data.

Keep real hostnames, LAN IPs, usernames, share names, and private folder layouts out of public docs and screenshots. Use placeholders in examples, then put the real values only in local .env files, compose overrides, or password-manager notes.

Local Docker

cp .env.docker.example .env
docker compose up --build -d

Open http://localhost:9787.

The local compose file builds from source and tags the result as gadarr:local unless GADARR_IMAGE is changed.

Published Image

For installs that should pull a prebuilt image, set these values in the local .env used by Docker Compose:

GADARR_IMAGE=docker.io/bigbeardedman/gadarr:latest
GADARR_VERSION=latest

Then pull and recreate the container while preserving the mounted /config volume:

docker compose pull
docker compose up -d

Fresh installs start with a browser Forms setup screen. Create the Gadarr username and password there; integration API and calendar feed keys are generated behind the scenes unless GADARR_API_KEY or GADARR_CALENDAR_FEED_KEY are provided.

For first testing, keep Gadarr on LAN or VPN only. Do not expose it publicly until Forms auth, feed token, reverse proxy, backups, and restore workflow are verified.

Volumes

Container path Example host path Purpose
Compose project ./docker/gadarr Compose file, local .env, and project notes
/config ./docker/gadarr/config SQLite database, generated keys, settings, and backups
/games /srv/games Writable finished game library
/downloads /srv/downloads Download staging path shared with clients such as qBittorrent, Transmission, SABnzbd, or NZBGet
/data /srv/downloads Optional read-only download-client root for reported completed paths

Gadarr data must live in bind mounts, not inside the container. The default database path is /config/gadarr.db. Backups are stored in /config/backups, including SQLite sidecar files when present.

Replacing the container or pulling a new latest image should not remove the database, settings, library, or game folders when /config, /games, and /downloads are mounted to durable host paths.

Environment

Variable Required Notes
GADARR_IMAGE Prebuilt image installs Use docker.io/bigbeardedman/gadarr:latest or ghcr.io/bigbeardedman/gadarr:latest
GADARR_VERSION Prebuilt image installs Human-readable version shown in runtime checks; use latest for the public Docker image path
GADARR_PORT No Host port, defaults to 9787
PUID / PGID Docker installs Must match the owner of the mounted folders
GADARR_AUTH_METHOD No Defaults to forms; use external only behind a trusted reverse proxy
GADARR_BASE_URL Reverse proxy subpath installs Optional URL base for static UI, API, feed, and session routes, for example /gadarr
GADARR_API_KEY No Optional fixed integration token; generated during first-run setup when empty
GADARR_CALENDAR_FEED_KEY No Optional fixed /feed/calendar/gadarr.ics token; generated during first-run setup when empty
GADARR_GAMES_DIR Docker installs Host path mounted to /games; for example /srv/games
GADARR_DOWNLOADS_DIR Docker installs Host path mounted to /downloads; for example /srv/downloads
GADARR_DATA_DIR Docker installs Host path mounted read-only to /data so Gadarr can read completed paths reported by download clients
PROWLARR_URL If using Prowlarr http://prowlarr:9696 on the same compose network, or another private URL
PROWLARR_API_KEY If using Prowlarr Stays server-side
PROWLARR_GAME_CATEGORIES No Optional comma-separated category ids; empty uses game-safe defaults 1000,4000,4050, set all to disable filters

Leave GADARR_API_KEY, GADARR_CALENDAR_FEED_KEY, and provider API-key variables empty unless you intentionally manage fixed integration tokens outside the repository.

Prowlarr And Download Clients

If Prowlarr is in the same compose project/network, set:

PROWLARR_URL=http://prowlarr:9696
PROWLARR_API_KEY=<prowlarr-api-key>

If Prowlarr is in another container stack or on another host, use its private URL:

PROWLARR_URL=http://<prowlarr-host>:9696

For download clients, keep downloads separate from the final /games library. Gadarr monitors the configured category, destination, or provider-specific identifier, waits until the client reports the download as complete, then imports from the reported path into /games/<Game>/<Release>. For torrents, Gadarr tries to hardlink first so seeding can continue without duplicate disk usage, and falls back to copy if hardlinks are not available.

If a download client reports a host path that is not the same path inside the Gadarr container, add a mapping in Settings -> Download Clients -> Remote Path Mappings. For example:

Host Remote Path Local Path
qbittorrent /srv/downloads/gadarr/torrents /downloads/gadarr/torrents
transmission /downloads/complete /data/complete
sabnzbd /downloads/usenet/complete /downloads/usenet/complete

This mirrors the Sonarr/Radarr Docker pattern: the download client can keep its own path, and Gadarr translates that reported path to the bind mount visible inside the Gadarr container before importing.

Import behavior is configurable in Settings -> Game Management. The default imports immediately with hardlink/copy fallback, verifies non-empty completed downloads, and keeps the download-client source path for seeding or external retention. Optional trust policy can compute and require an allowlisted SHA-256 checksum or a .gadarr.sig Ed25519 signature manifest before import. Dry-run mode stages imports for manual Apply, and Remove Completed can be enabled only when you intentionally want Gadarr to delete the completed download after import.

Activity -> Import can review a completed download path before staging it. Reviewing /downloads lists its immediate children with inferred games, target paths, replacement warnings, trust-policy results, and approval/rejection reasons. Approved rows can be staged or applied from the review table; staged rows can be rejected before they touch the library.

When Backup Target is enabled and an import replaces an existing file or folder, Gadarr records the old target as the import backup. Applied imports with a recorded backup can be rolled back from Activity -> Import; rollback restores the previous target and moves the imported artifact aside for manual inspection.

Signed manifests live either beside a file as <download>.gadarr.sig or inside a completed folder as .gadarr.sig. The signed payload is gadarr-import-v1\nsha256:<checksum>\n, and the manifest format is:

{
  "algorithm": "ed25519",
  "checksum": "sha256:<completed-download-sha256>",
  "signature": "<base64-signature>"
}

Published Images

GitHub Actions publishes multi-arch images to GHCR and, when Docker Hub repository settings are present, Docker Hub. Public Docker installs should use:

  • docker.io/bigbeardedman/gadarr:latest
  • ghcr.io/bigbeardedman/gadarr:latest

The workflow also publishes traceability tags for maintainers and semver tags after release tags are created, but user-facing install docs should point to latest.

The Docker Hub job uses repository variable DOCKERHUB_REPOSITORY plus the DOCKERHUB_USERNAME and DOCKERHUB_TOKEN Actions secrets. Keep those values in GitHub Actions settings only; do not commit them to the repo or bake them into an image.

Linux servers, Portainer, Unraid, and other Compose-capable hosts should pull the image instead of building from source.

Backups And Updates

  • Create backups from System -> Backups before updating.
  • Backups are SQLite .db files under /config/backups.
  • Restore stages a selected backup as /config/gadarr.db.restore-pending; restart the container to apply it before SQLite opens.
  • To update a Docker install, pull the newer image and recreate the container while preserving /config.
  • If the container cannot write /config, fix host folder ownership with the host file manager or chown.

Build Checks

Before publishing an image, run:

pnpm typecheck
pnpm test
pnpm build
docker build -t gadarr:local .

Documentation-only publishes should run the documentation agent. It verifies docs, screenshots, README screenshot embeds, source-backed claims, Sonarr parity scripts, and git diff --check without implying that the runtime changed:

pnpm docs:agent

After pushing a docs-only commit, prove GitHub has the same commit:

pnpm exec node scripts/documentation-agent.mjs --check-github