Skip to content

Architecture

github-actions[bot] edited this page Oct 28, 2026 · 1 revision

Architecture

                  LAN / host ports
   7878 8989 8686 9696 6767 8090 8085 6789 5055 8787
     │    │    │    │    │    │    │    │    │    │
 ┌───┴────┴────┴────┴────┴────┴────┴────┴────┴────┴──────────────────────┐
 │ docker network "arrs"                                                 │
 │                                                                       │
 │  radarr  sonarr  lidarr  prowlarr  bazarr  qbittorrent sabnzbd nzbget │
 │     │       │       │       │         │    seerr ──▶ radarr, sonarr   │
 │     └───────┴───────┴───────┴─────────┴──────┴── postgres:5432        │
 │                                                                       │
 │  wranglarr ──API──▶ every app (status, backup task, restore upload)   │
 │     │       ──pg_dump/pg_restore──▶ postgres                          │
 │     │       ──docker.sock──▶ stop/start on restores, image updates    │
 │     └── /backups  (versions)   /config (wranglarr.toml, state db)     │
 └───────────────────────────────────────────────────────────────────────┘

 with compose.vpn.yaml + compose.vpn-all.yaml (compose.vpn.yaml alone: only the download clients):
 ┌─ vpn (gluetun) ── WireGuard/OpenVPN ──▶ internet ─────────────────────┐
 │  radarr sonarr lidarr prowlarr bazarr qbittorrent sabnzbd nzbget      │
 │  (network_mode: service:vpn — share its stack, ports published on it) │
 └── aliases radarr/sonarr/… so wranglarr still reaches them by name ────┘

Containers

Service Image (default) Profile Role
postgres postgres:17 always one cluster, one database per arr (<app>, <app>-log) plus bazarr and seerr
radarr / sonarr / lidarr lscr.io/linuxserver/<app>:latest radarr / sonarr / lidarr media managers, config.xml patched to point at Postgres
prowlarr lscr.io/linuxserver/prowlarr:latest prowlarr indexer manager on Postgres (prowlarr, prowlarr-log), no /data mount; wranglarr registers every arr in it
bazarr lscr.io/linuxserver/bazarr:latest bazarr subtitles; Postgres settings from environment
qbittorrent lscr.io/linuxserver/qbittorrent:latest qbittorrent torrent client (web UI on 8090 inside the container)
sabnzbd lscr.io/linuxserver/sabnzbd:latest sabnzbd usenet client
nzbget lscr.io/linuxserver/nzbget:latest nzbget usenet client
seerr ghcr.io/seerr-team/seerr:latest seerr requests (Plex / Jellyfin / Emby users ask, Radarr / Sonarr get it); database seerr; never inside the VPN (Service: Seerr)
wranglarr-init ${WRANGLARR_IMAGE} always one-shot before wranglarr: hands appdata/wranglarr and appdata/backups to PUID:PGID, then exits. The only root part, with only the chown capabilities (Security)
wranglarr ${WRANGLARR_IMAGE}: the published ghcr.io/wranglarrr/wranglarr, or one you built (The wranglarr image) always backup / version / restore UI + API; wires the apps together (App Connections). Runs as PUID:PGID, read-only, no capabilities
vpn qmcgaw/gluetun:v3.41.3 with compose.vpn.yaml shared tunnel, kill switch, DNS over TLS, control server

Compose files

File Purpose
compose.yaml the stack
compose.init.yaml used only by scripts/init.sh: starts the arrs without Postgres to generate config.xml and the download clients to generate their defaults, then runs patch-config (Postgres keys, download paths)
compose.vpn.yaml override: adds vpn, attaches the download clients to its network namespace, moves their published ports onto it
compose.vpn-prowlarr.yaml, compose.vpn-all.yaml add-ons to compose.vpn.yaml: Prowlarr, or Prowlarr, the arrs and Bazarr, join the tunnel (which to pick)
compose.authtunnel.yaml generated by scripts/init.sh for AuthTunnel: the apps' ports move to wranglarr-gate (App logins)
compose.vpn-per-app.yaml override: swaps apps to hotio images with a built-in WireGuard client each

Overrides are selected with COMPOSE_FILE in .env (COMPOSE_FILE=compose.yaml:compose.vpn.yaml:compose.vpn-all.yaml). They use the !reset YAML tag, which needs Docker Compose 2.24 or newer.

Volumes

Host path Mounted where Notes
${APPDATA}/postgres postgres:/var/lib/postgresql/data the cluster
${APPDATA}/<app> <app>:/config per-app config; also mounted into wranglarr at /arrconfig/<app> (read-only for the arrs, read-write for Bazarr and the download clients)
${APPDATA}/wranglarr wranglarr:/config wranglarr.toml, wranglarr.db, restore-plan.json
${APPDATA}/backups wranglarr:/backups versions: <suite>/<timestamp>/…
${APPDATA}/vpn vpn:/gluetun server lists, wireguard/wg0.conf, custom.conf
${DATA_ROOT} <app>:/data (not Prowlarr) one mount for downloads (torrents/, usenet/) and media so hardlinks work
${DATA_ROOT_2} <app>:/data2 optional, commented out in compose.yaml
/var/run/docker.sock wranglarr (through group DOCKER_GID) root-equivalent, see Security; lets it stop/start apps around restores and pull/recreate containers for updates; remove the line to withhold it (both features then switch off)

Startup order

postgres (healthcheck: pg_isready) → the apps (depends_on: service_healthy) → wranglarr. With the VPN override, the apps also wait for vpn to be healthy (gluetun's own connectivity check).

Clone this wiki locally