Sonarr/Radarr root folders created via API (201). Lidarr/Readarr deferred to first-run wizard (v1 validators demand quality-profile ids that don't exist yet). Root cause of the write failures: LSIO PUID=1000 under rootless podman maps to host uid 101000 — a phantom user owning nothing; PUID=0 maps to the host user that owns every media dir.
14 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 completion (same day): Sonarr and Radarr root folders created via
API (
/tv,/movies→ 201). Lidarr/Readarr roots deferred to their first-run wizard (v1 API validators demand quality-profile ids that don't exist yet — two clicks in the UI, not an API guess). The blocker under all of it: LSIO images run asPUID=1000, which under rootless podman's userns maps to host uid 101000 — a phantom user owning nothing; Sonarr's own validator refused/tvwith "not writable by user 'abc'" (placeholder name for the unknown uid). Fix:PUID=0/PGID=0on the arr stack + qbittorrent + prowlarr (container-root = host'sdank, which owns every media dir; mapping- independent by construction). calibre-web and jellyfin untouched — not broken.
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