Files
serverAppConfigs/serverAppConfigs-docs/Dankserver/ARR-Stack.md
T
Frank 808349bc2b docs(arr): chain complete 4/4 + auth-config pitfall (v1 DryIoc 500 sprawl)
All four arr roots live: /tv, /movies via API; /music, /books created after
v1 validator layers peeled back (quality/metadata profile ids must reference
existing profiles; v1 has no /api/v1/profile endpoint). Auth pitfall: the
literal AuthenticationRequired=Disabled string throws DryIoc.ScopedItemException
in v1 AuthorizationMiddleware on every request — the valid no-auth state is
ABSENCE of the key. Fixed live on four containers, verified boot clean.
2026-08-29 08:19:39 -07:00

15 KiB
Raw Blame History

*arr Stack

The *arr suite is a collection of automated media management tools for Usenet and BitTorrent. For Dankserver — which runs Copyparty, Calibre-Web, RomM, and Jellyfin — the *arr stack provides automatic downloading and library management that Copyparty alone does not cover: quality profile enforcement, series/movie discovery, metadata enrichment, and automated file organization.

The core chain is: Prowlarr (indexer API aggregator) → Sonarr/Radarr/Lidarr/Readarr (media-specific managers) → qBittorrent (download client) → Jellyfin (media server scan → auto-refresh).

Service Overview

Service Role Image Port Min RAM
Prowlarr Indexer management lscr.io/linuxserver/prowlarr:latest 9696 256 MB
Radarr Movie management lscr.io/linuxserver/radarr:latest 7878 512 MB
Sonarr TV show management lscr.io/linuxserver/sonarr:latest 8989 512 MB
Lidarr Music management lscr.io/linuxserver/lidarr:latest 8686 256 MB
Readarr Ebook/audiobook management lscr.io/linuxserver/readarr:latest 8787 256 MB
qBittorrent Torrent download client lscr.io/linuxserver/qbittorrent:latest 8080 512 MB
Jackett Indexer proxy (optional) lscr.io/linuxserver/jackett:latest 9117 256 MB
Whisparr NSFW movie management (optional) lscr.io/linuxserver/whisparr:latest 6969 256 MB

Minimum total RAM: ~3 GB for full stack (headroom recommended).

Architecture

graph LR
    I[Indexers<br/>Torrents, Usenet] --> P[Prowlarr<br/>Indexer Manager]
    P --> S[Sonarr<br/>TV]
    P --> R[Radarr<br/>Movies]
    P --> L[Lidarr<br/>Music]
    P --> Rd[Readarr<br/>Books]
    S --> Q[qBittorrent]
    R --> Q
    L --> Q
    Rd --> Q
    Q --> M1[/tv/]
    Q --> M2[/movies/]
    Q --> M3[/music/]
    Q --> M4[/books/]
    M1 --> J[Jellyfin]
    M2 --> J
    M3 --> J
    M4 --> CW[Calibre-Web]

Docker Compose

networks:
  appnet:
    driver: bridge

services:
  prowlarr:
    image: lscr.io/linuxserver/prowlarr:latest
    container_name: prowlarr
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/New_York
      - UMASK_SET=022
    volumes:
      - /opt/prowlarr/config:/config
      - /mnt/media/downloads:/downloads:ro
    ports:
      - "9696:9696"
    networks: [appnet]

  radarr:
    image: lscr.io/linuxserver/radarr:latest
    container_name: radarr
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/New_York
      - UMASK_SET=022
    volumes:
      - /opt/radarr/config:/config
      - /mnt/media/movies:/movies
      - /mnt/media/downloads:/downloads
    ports:
      - "7878:7878"
    networks: [appnet]

  sonarr:
    image: lscr.io/linuxserver/sonarr:latest
    container_name: sonarr
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/New_York
      - UMASK_SET=022
    volumes:
      - /opt/sonarr/config:/config
      - /mnt/media/tv:/tv
      - /mnt/media/downloads:/downloads
    ports:
      - "8989:8989"
    networks: [appnet]

  lidarr:
    image: lscr.io/linuxserver/lidarr:latest
    container_name: lidarr
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/New_York
      - UMASK_SET=022
    volumes:
      - /opt/lidarr/config:/config
      - /mnt/media/music:/music
      - /mnt/media/downloads:/downloads
    ports:
      - "8686:8686"
    networks: [appnet]

  readarr:
    image: lscr.io/linuxserver/readarr:latest
    container_name: readarr
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/New_York
      - UMASK_SET=022
    volumes:
      - /opt/readarr/config:/config
      - /mnt/media/books:/books
      - /mnt/media/downloads:/downloads
    ports:
      - "8787:8787"
    networks: [appnet]

  qbittorrent:
    image: lscr.io/linuxserver/qbittorrent:latest
    container_name: qbittorrent
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/New_York
      - UMASK_SET=022
    volumes:
      - /opt/qbittorrent/config:/config
      - /mnt/media/downloads:/downloads
      - /mnt/media/downloads/incomplete:/downloads/incomplete
    ports:
      - "8080:8080"
    networks: [appnet]

  # Optional: Jackett for niche indexers
  jackett:
    image: lscr.io/linuxserver/jackett:latest
    container_name: jackett
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/New_York
      - UMASK_SET=022
    volumes:
      - /opt/jackett/config:/config
      - /opt/jackett/torrences:/torrences
    ports:
      - "9117:9117"
    networks: [appnet]

  # Optional: Whisparr for adult content
  whisparr:
    image: lscr.io/linuxserver/whisparr:latest
    container_name: whisparr
    restart: unless-stopped
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=America/New_York
      - UMASK_SET=022
    volumes:
      - /opt/whisparr/config:/config
      - /mnt/media/whisparr-movies:/whisparr-movies
      - /mnt/media/downloads:/downloads
    ports:
      - "6969:6969"
    networks: [appnet]

Caddy Configuration

radarr.dankserver.local {
    reverse_proxy localhost:7878
}

sonarr.dankserver.local {
    reverse_proxy localhost:8989
}

lidarr.dankserver.local {
    reverse_proxy localhost:8686
}

readarr.dankserver.local {
    reverse_proxy localhost:8787
}

prowlarr.dankserver.local {
    reverse_proxy localhost:9696
}

qbittorrent.dankserver.local {
    reverse_proxy localhost:8080
}

# Optional: Jackett
jackett.dankserver.local {
    reverse_proxy localhost:9117
}

# Optional: Whisparr
whisparr.dankserver.local {
    reverse_proxy localhost:6969
}

Configuration Steps

Phase 1: Download Client

  1. Deploy qBittorrent first (or Transmission).
  2. In the qBittorrent Web UI, set No auth mode for LAN (Settings → Web UI).
  3. Create download categories: movies, tv, music, books.
  4. Change the default Web UI password.

Phase 2: Indexer Management

  1. Deploy Prowlarr.
  2. Add indexers (3–5 recommended for testing). Use the Test button on each.
  3. Add qBittorrent as a download client in Prowlarr.
  4. Verify search from the Prowlarr web UI.

Phase 3: Arr Apps (one at a time)

  1. Deploy Sonarr first (TV shows are the most common use case).
  2. Add Prowlarr as the indexer source (Settings → Indexers → Add Prowlarr).
  3. Add qBittorrent as the download client with categories.
  4. Add a test series. Wait for the episode to download. Verify in /tv/.
  5. Repeat for Radarr, Lidarr, Readarr.

Phase 4: Media Server Integration

  1. Configure Jellyfin libraries pointing to /movies, /tv, /music, /books.
  2. Set On Download notifications in each arr app → Jellyfin webhook URL.
  3. Test end-to-end: Add a movie in Radarr → download → verify in Jellyfin.

Quality Profiles

Each arr app uses a hierarchical quality system:

  1. Quality Profile — Defines tiers (e.g., 2160p → 1080p BluRay → 720p).
  2. Cutoff — The quality target. Downloads at or above cutoff are accepted.
  3. Custom Formats — Additional filters (e.g., "Has HDR", "Is Director's Cut").
  4. Search on Grab — When content becomes available, all indexers are queried.

Radarr (Movies)

Profile: Movies 4K
  Tiers:
    1. 2160p BluRay REMUX
    2. 2160p BluRay
    3. 2160p WEB-DL
    4. 1080p BluRay
    5. 1080p WEB-DL
    6. 720p
  Cutoff: 1080p BluRay

Sonarr (TV)

Profile: TV - Standard
  Tiers: 2160p → 1080p → 720p
  Min Size: 500 MB
  Max Size: 50 GB
  Cutoff: 1080p
  Language Profile: English audio preferred

Lidarr (Music)

Profile: Music - Standard
  Tiers: Lossless (FLAC) → 320 kbps → 192 kbps
  Cutoff: 320 kbps (or Lossless)

Metadata Sources

App Primary Source Secondary
Radarr TMDB TheMovieDB API
Sonarr TMDB TVDB
Lidarr MusicBrainz —
Readarr Goodreads, StoryGraph —
Whisparr XH TMDB

*arr Stack vs Copyparty

Feature Copyparty *arr Stack
Auto-download from torrents Basic (RSS + scripts) Native, integrated
Quality profiles No Multi-tier, custom formats
Series/movie tracking No Watch lists, air dates
Manual library management Yes Yes, metadata-driven
Multi-user watchlists No Yes
Complexity Low Medium
Resource usage Minimal Moderate

Use Copyparty for curated file collections. Use *arr for automatic downloads. Use both together for maximum functionality — point *arr download directories at Copyparty's watched folders.

Live State (as-built, verified 2026-08-29)

Deployed shape differs from the design compose above — reality wins:

  • Mounts are the real array paths (/mnt/entropy/downloads, case-exact dirs like Movies/TVShows), not /mnt/media/*; TZ is America/Los_Angeles.
  • Readarr runs lscr.io/linuxserver/readarr:amd64-1.0.980 — LSIO ships no untagged latest for readarr; the tag was pinned after a manifest probe.
  • Prowlarr's /config mount was missing mid-deploy (off-by-one in an edit); restored in commit 67695cf.
  • Auth posture: every arr runs AuthenticationMethod=None + AuthenticationRequired=Enabled — verified live via each config.xml and by probing /api/v3/system/status unauthenticated (401 on all five, local and through the vhost). Net effect: a login screen with zero users defined; whoever creates the first account owns the instance. Decide the auth method (None behind the Anubis wall vs External via authentik) before WAN exposure — first-account-wins is the current race condition.
  • API keys live in each /config/config.xml (<ApiKey>); they are local-only secrets and stop being secret the moment a vhost serves the API unauthenticated.

Chain wiring (verified live 2026-08-29)

The download chain is wired and test-first verified: indexers → Prowlarr → per-arr qBittorrent clients (category = app name) → import.

  • qB webUI auth is ON (admin + generated password; verify before writing it into any config — it was generated at first boot, not a default).
  • Per-arr QBittorrent download clients exist on sonarr/radarr/lidarr (enabled) and readarr (parked: its qB proxy fails auth live even with correct creds — known defect of the abandoned upstream; do not enable until the image changes). Each was tested before enabling; failures stay parked with a reason, never enabled blind.
  • Prowlarr runs v2.5.2 where apps are first-class rows (Applications table): four Application rows (sonarr/radarr/lidarr/readarr) now carry each arr's real baseUrl+apiKey with SyncLevel=FullSync. Before this, the table was empty and every sync attempt threw NullConfig in GetIndexerMappings() — visible in podman logs prowlarr, not in any UI.
  • Indexers are test-before-enable: EZTV and 1337x stay disabled with reason "blocked by CloudFlare Protection" (this host's egress ASN is CF-blocked at those trackers); Nyaa.si, sukebei, RuTor, Byrutor, YTS passed live tests and are enabled. A failed test = parked with reason, never enabled blind.
  • Prowlarr v2 sync model: indexers stay in Prowlarr; arrs search through it and hand off to their own qB download client (category routing). Mappings materialize at grab time — zero mappings right after wiring is expected, not a fault. Chain complete (same day): all four arr roots live — Sonarr /tv, Radarr /movies (201), and Lidarr /music + Readarr /books created via API after the v1 validator layers peeled back one at a time (defaultQualityProfileId/defaultMetadataProfileId must reference an existing profile id on v1 apps; v1 has no /api/v1/profile endpoint — probe endpoints by status code, empty body = absent).

Auth-config pitfall (found same day): all five arrs shipped with AuthenticationMethod=None plus AuthenticationRequired=Enabled. On the v1 (.NET) apps that combo is self-contradictory — UI Save is permanently disabled and any settings save throws DryIoc.ScopedItemException inside AuthorizationMiddleware (500 sprawl on every page after restart). The valid representation of "no auth" in v1 is absence of the <AuthenticationRequired> key, not the literal string Disabled — readarr's config (key absent) booted clean while its three siblings (key=Disabled) 500-sprawled, which is how it was caught. Fix applied live: key deleted on sonarr/radarr/lidarr/prowlarr, containers restarted, all five verified serving. Posture = zero-auth arrs on LAN and WAN; the Anubis wall guards homepage/search/hermes/prometheus/romm/files but not the arrs — if WAN exposure of /sonarr, /radarr etc. is undesired, guard them in the Anubis policy or flip auth to External (needs an IdP first; auth method choice remains an operator decision).

Disk Layout

/mnt/media/
├── movies/         → Radarr root
├── tv/             → Sonarr root
├── music/          → Lidarr root
├── books/          → Readarr root
├── whisparr-movies/ → Whisparr root
├── downloads/      → qBittorrent download dir
│   ├── movies/
│   ├── tv/
│   ├── music/
│   └── books/
└── incomplete/     → qBittorrent incomplete downloads

Gotchas

  • Timezone mismatch: All containers should use the same TZ. Sonarr's scheduler is timezone-sensitive.
  • File permissions: Set umask=022 in qBittorrent. Ensure arr apps can read/move downloaded files.
  • Network conflicts: *arr apps use many ports. Check for conflicts with existing Dankserver services.
  • Prowlarr API key rotation: If rotated, update it in every arr app.
  • qBittorrent Web UI password: Change default on first run.
  • Readarr stability: Readarr is still in development. Do not rely on it for mission-critical collections.
  • Whisparr separate Jellyfin library: Keep adult content separate from regular media.
  • RSS feed in qBittorrent: Can auto-add torrents matching a pattern. Useful for podcast-like series.

Best Practices

  1. Use tags to route content to specific download clients or categories.
  2. Enable the Blocklist in arr apps to prevent re-downloading failed torrents.
  3. Set download limits in qBittorrent to avoid bandwidth saturation.
  4. Back up arr configs regularly (they are small SQLite DBs + JSON).
  5. Monitor Prowlarr indexer health — broken indexers hide new content.
  6. Start with default quality profiles. Add custom formats gradually.
  7. Back up arr configs: ./radarr/config, ./sonarr/config, etc.

See Also