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.
15 KiB
*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
- Deploy qBittorrent first (or Transmission).
- In the qBittorrent Web UI, set No auth mode for LAN (Settings → Web UI).
- Create download categories:
movies,tv,music,books. - Change the default Web UI password.
Phase 2: Indexer Management
- Deploy Prowlarr.
- Add indexers (3–5 recommended for testing). Use the Test button on each.
- Add qBittorrent as a download client in Prowlarr.
- Verify search from the Prowlarr web UI.
Phase 3: Arr Apps (one at a time)
- Deploy Sonarr first (TV shows are the most common use case).
- Add Prowlarr as the indexer source (Settings → Indexers → Add Prowlarr).
- Add qBittorrent as the download client with categories.
- Add a test series. Wait for the episode to download. Verify in
/tv/. - Repeat for Radarr, Lidarr, Readarr.
Phase 4: Media Server Integration
- Configure Jellyfin libraries pointing to
/movies,/tv,/music,/books. - Set On Download notifications in each arr app → Jellyfin webhook URL.
- Test end-to-end: Add a movie in Radarr → download → verify in Jellyfin.
Quality Profiles
Each arr app uses a hierarchical quality system:
- Quality Profile — Defines tiers (e.g., 2160p → 1080p BluRay → 720p).
- Cutoff — The quality target. Downloads at or above cutoff are accepted.
- Custom Formats — Additional filters (e.g., "Has HDR", "Is Director's Cut").
- 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 likeMovies/TVShows), not/mnt/media/*; TZ isAmerica/Los_Angeles. - Readarr runs
lscr.io/linuxserver/readarr:amd64-1.0.980— LSIO ships no untaggedlatestfor readarr; the tag was pinned after a manifest probe. - Prowlarr's
/configmount was missing mid-deploy (off-by-one in an edit); restored in commit67695cf. - Auth posture: every arr runs
AuthenticationMethod=None+AuthenticationRequired=Enabled— verified live via each config.xml and by probing/api/v3/system/statusunauthenticated (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 (Nonebehind the Anubis wall vsExternalvia 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 (
Applicationstable): four Application rows (sonarr/radarr/lidarr/readarr) now carry each arr's real baseUrl+apiKey withSyncLevel=FullSync. Before this, the table was empty and every sync attempt threwNullConfiginGetIndexerMappings()— visible inpodman 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/bookscreated via API after the v1 validator layers peeled back one at a time (defaultQualityProfileId/defaultMetadataProfileIdmust reference an existing profile id on v1 apps; v1 has no/api/v1/profileendpoint — 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=022in 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
- Use tags to route content to specific download clients or categories.
- Enable the Blocklist in arr apps to prevent re-downloading failed torrents.
- Set download limits in qBittorrent to avoid bandwidth saturation.
- Back up arr configs regularly (they are small SQLite DBs + JSON).
- Monitor Prowlarr indexer health — broken indexers hide new content.
- Start with default quality profiles. Add custom formats gradually.
- 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
- Radarr Wiki