# *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 ```mermaid graph LR I[Indexers
Torrents, Usenet] --> P[Prowlarr
Indexer Manager] P --> S[Sonarr
TV] P --> R[Radarr
Movies] P --> L[Lidarr
Music] P --> Rd[Readarr
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 ```yaml 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 ```caddy 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` (``); 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 `` 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 - [[Dankserver Stack]] - [[Jellyfin]] — media server that consumes *arr downloads - [[Copyparty]] — alternative file viewer - [[Calibre-Web]] — manual ebook management (Readarr auto-downloads into the same library) - [Sonarr Wiki](https://wiki.servarr.com/sonarr) - [Radarr Wiki](https://wiki.servarr.com/radarr)