Arr-Stack¶
Dockerized media automation stack running on VM 100.
Overview¶
| Property | Value |
|---|---|
| Location | VM 100 at 10.89.97.50 |
| Path | /opt/arr-stack/ |
| Network | Download clients route through Mullvad VPN (Gluetun) |
Services¶
Download Clients (VPN-routed)¶
| Service | Port | Purpose |
|---|---|---|
| SABnzbd | 8080 | Usenet downloads |
| Deluge | 8112 | Torrent downloads |
Media Management¶
| Service | Port | Purpose |
|---|---|---|
| Sonarr | 8989 | TV shows |
| Radarr | 7878 | Movies |
| Lidarr | 8686 | Music |
| Bazarr | 6767 | Subtitles |
| Prowlarr | 9696 | Indexer manager |
Request Management¶
| Service | Port | Purpose |
|---|---|---|
| Overseerr | 5055 | Media requests (Plex) |
| Jellyseerr | 5056 | Media requests (Jellyfin) |
Other¶
| Service | Port | Purpose |
|---|---|---|
| ErsatzTV | 8409 | IPTV channel management |
| Tdarr | 8265-8266 | Media transcoding |
| xTeVe | 34400 | IPTV proxy |
Architecture¶
┌─────────────────────────────────────────┐
│ Gluetun VPN Container │
│ (Network mode for downloads) │
│ ┌──────────────┐ ┌────────────────┐ │
│ │ SABnzbd │ │ Deluge │ │
│ │ (Usenet DL) │ │ (Torrent DL) │ │
│ └──────────────┘ └────────────────┘ │
└─────────────────────────────────────────┘
↓
/mnt/downloads
↓
┌─────────────────────────────────────────┐
│ *arr Stack │
│ ┌─────────┐ ┌─────────┐ ┌──────────┐ │
│ │ Sonarr │ │ Radarr │ │ Lidarr │ │
│ │ (TV) │ │ (Movies)│ │ (Music) │ │
│ └─────────┘ └─────────┘ └──────────┘ │
│ ┌─────────┐ ┌───────────────────────┐ │
│ │ Bazarr │ │ Prowlarr │ │
│ │ (Subs) │ │ (Indexer Manager) │ │
│ └─────────┘ └───────────────────────┘ │
└─────────────────────────────────────────┘
↓
/mnt/media/{tv,movies,music}
Access URLs¶
All services accessible at http://10.89.97.50:<port>:
- Sonarr: http://10.89.97.50:8989
- Radarr: http://10.89.97.50:7878
- Lidarr: http://10.89.97.50:8686
- Bazarr: http://10.89.97.50:6767
- Prowlarr: http://10.89.97.50:9696
- Overseerr: http://10.89.97.50:5055
- Jellyseerr: http://10.89.97.50:5056
- SABnzbd: http://10.89.97.50:8080
- Deluge: http://10.89.97.50:8112
- ErsatzTV: http://10.89.97.50:8409
- Tdarr: http://10.89.97.50:8265
Common Operations¶
SSH Access¶
View Services¶
View Logs¶
Restart Service¶
Update All Services¶
Backup Configurations¶
ssh root@10.89.97.50 "cd /opt/arr-stack && tar -czf configs-backup-\$(date +%Y%m%d).tar.gz configs/"
File Structure¶
/opt/arr-stack/
├── docker-compose.yml
├── configs/
│ ├── gluetun/
│ ├── sabnzbd/
│ ├── deluge/
│ ├── prowlarr/
│ ├── sonarr/
│ ├── radarr/
│ ├── lidarr/
│ ├── bazarr/
│ ├── overseerr/
│ ├── jellyseerr/
│ ├── ersatztv/
│ └── tdarr/
└── README.md
/mnt/
├── downloads/ # Download staging area
│ └── incomplete/ # Incomplete downloads
└── media/ # Final media library
├── tv/ # TV shows (Sonarr)
├── movies/ # Movies (Radarr)
└── music/ # Music (Lidarr)
Troubleshooting¶
SABnzbd 502 Bad Gateway After Enabling HTTPS¶
Symptom: Enabled HTTPS in SABnzbd web UI settings, now getting 502 Bad Gateway.
Cause: The reverse proxy connects to SABnzbd over HTTP internally. When HTTPS is enabled in SABnzbd, it stops accepting HTTP connections.
Fix: Disable HTTPS in the config file:
# Stop container, edit config, restart
ssh root@10.89.97.50 "cd /opt/arr-stack && \
docker compose stop sabnzbd && \
sed -i 's/^enable_https = 1/enable_https = 0/' configs/sabnzbd/sabnzbd.ini && \
docker compose start sabnzbd"
Verify:
ssh root@10.89.97.50 "grep '^enable_https' /opt/arr-stack/configs/sabnzbd/sabnzbd.ini"
# Should show: enable_https = 0
VPN Connection Issues¶
Check Gluetun logs:
Verify VPN is working (should show VPN IP, not host IP):
Service Can't Access Downloads¶
Verify volume mounts:
Check permissions:
Container Won't Start¶
Check logs for specific service:
Recreate container:
General Config Issues¶
Most *arr apps store configs in INI or XML format. To edit directly:
- Stop the container:
docker compose stop <service> - Edit config:
nano configs/<service>/<config-file> - Start the container:
docker compose start <service>
Config file locations:
- SABnzbd: configs/sabnzbd/sabnzbd.ini
- Deluge: configs/deluge/core.conf
- Sonarr/Radarr/etc: configs/<service>/config.xml
Downloads Stuck "Waiting to Import"¶
Downloads can get stuck in importPending or importBlocked state for several reasons:
1. Missing Destination Folder¶
Symptom: Import silently fails, logs show DirectoryNotFoundException
Cause: Radarr/Sonarr expect the destination folder to exist before importing.
Fix: Enable "Create empty folders" in Settings → Media Management → Root Folders. - Radarr: Settings → Media Management → check "Create empty series folders" - Sonarr: Settings → Media Management → check "Create empty series folders" - Lidarr: Settings → Media Management → check "Create empty artist folders"
2. Download Client Connection Lost¶
Symptom: Downloads show importPending after SABnzbd/Deluge restart
Cause: When download client restarts, *arr apps lose tracking of completed downloads.
Fix: Restart the *arr app to re-establish connection:
3. Series/Movie ID Mismatch (Common with Anime)¶
Symptom: importBlocked with message "release was matched to series by ID. Automatic import is not possible."
Cause: Release naming doesn't match how the *arr app identifies the series (common with anime that has multiple naming conventions).
Fix: Use Manual Import in the UI: Activity → Queue → click item → Manual Import
4. Stuck Command Queue¶
Symptom: Imports queued but never process
Cause: A background task (like ProcessMonitoredDownloads) is stuck.
Fix: Restart the affected *arr app:
5. Failed/Empty Downloads¶
Symptom: SABnzbd shows "Completed" but files are missing or empty
Cause: NZB was bad, incomplete, or download failed silently.
Fix: 1. Delete the empty download folder 2. Trigger a new search in Radarr/Sonarr
Downloads Folder Filling Up¶
The /mnt/downloads/ folder accumulates files because:
- Torrent seeding: Deluge keeps files until seed ratio is met (default 2:1)
- Orphaned downloads: Failed imports leave files behind
- Duplicate downloads: SABnzbd retries create
.1,.2,.3suffix folders
Current Deluge settings:
- remove_seed_at_ratio: true - Removes torrent from Deluge at ratio
- stop_seed_ratio: 2.0 - Seed until 2:1 ratio
Important: remove_seed_at_ratio only removes the torrent from Deluge management — it does NOT delete the files from disk.
Cleanup commands:
# Remove duplicate/failed SABnzbd downloads (numbered suffixes)
ssh root@10.89.97.50 "find /mnt/downloads -maxdepth 1 -type d \( -name '*.[0-9]' -o -name '*.[0-9].[0-9]' \) -exec rm -rf {} \;"
# Remove incomplete unpack folders
ssh root@10.89.97.50 "find /mnt/downloads -maxdepth 1 -type d -name '_UNPACK_*' -exec rm -rf {} \;"
# Remove empty folders
ssh root@10.89.97.50 "find /mnt/downloads -maxdepth 1 -type d -empty -delete"
# Check current size
ssh root@10.89.97.50 "du -sh /mnt/downloads/ && ls /mnt/downloads/ | wc -l"
Note: Be careful not to delete actively seeding torrents. Files older than 30 days are generally safe to remove if not in the *arr queue.
Media Folder Permissions¶
The Problem¶
By default, Sonarr/Radarr/Lidarr create media folders with 755 permissions (owner=rwx, group=rwx, others=r-x). This causes issues for other services that need write access:
- Plex DVR (UID 999) can't write recordings to folders created by Sonarr
- Error: "Could not move recorded media to destination"
Root Cause¶
Docker compose sets UMASK_SET=002:
- Folders get 775 permissions (777 - 002)
- Owner (UID 1000): full access
- Group (GID 1000): full access
- Others (Plex UID 999): read-only
Solution¶
Enable explicit permission settings in each *arr app:
- Sonarr/Radarr/Lidarr Web UI:
- Settings → Media Management → Permissions
- Enable "Set Permissions"
-
Set "chmod Folder" to
777 -
Or via API:
# Sonarr curl -X PUT "http://10.89.97.50:8989/api/v3/config/mediamanagement" \ -H "X-Api-Key: $(grep -oP '(?<=<ApiKey>)[^<]+' /opt/arr-stack/configs/sonarr/config.xml)" \ -H "Content-Type: application/json" \ -d '{"setPermissionsLinux": true, "chmodFolder": "777"}' # Radarr curl -X PUT "http://10.89.97.50:7878/api/v3/config/mediamanagement" \ -H "X-Api-Key: $(grep -oP '(?<=<ApiKey>)[^<]+' /opt/arr-stack/configs/radarr/config.xml)" \ -H "Content-Type: application/json" \ -d '{"setPermissionsLinux": true, "chmodFolder": "777"}' # Lidarr curl -X PUT "http://10.89.97.50:8686/api/v3/config/mediamanagement" \ -H "X-Api-Key: $(grep -oP '(?<=<ApiKey>)[^<]+' /opt/arr-stack/configs/lidarr/config.xml)" \ -H "Content-Type: application/json" \ -d '{"setPermissionsLinux": true, "chmodFolder": "777"}'
Fix Existing Folders¶
One-time fix from Proxmox host:
# Fix all media folders
find "/vault/subvol-101-disk-0/media/tv" -type d ! -perm -002 -exec chmod 777 {} \;
find "/vault/subvol-101-disk-0/media/movies" -type d ! -perm -002 -exec chmod 777 {} \;
find "/vault/subvol-101-disk-0/media/music" -type d ! -perm -002 -exec chmod 777 {} \;
Service UID Reference¶
| Service | Location | UID | Needs Write Access |
|---|---|---|---|
| Sonarr/Radarr/Lidarr | VM 100 | 1000 | Owner |
| Plex | LXC 111 | 999 | DVR recordings |
| Jellyfin | LXC 113 | 999 | - |
VPN Configuration¶
- Provider: Mullvad
- Type: WireGuard
- Server: Boston, MA
- Container: Gluetun provides network namespace for SABnzbd and Deluge
Download clients use network_mode: "service:gluetun" to route all traffic through VPN.
Recyclarr (TRaSH Guides Sync)¶
Recyclarr automatically syncs TRaSH Guides recommended settings to Sonarr/Radarr.
Installation¶
| Property | Value |
|---|---|
| Version | 7.5.2 |
| Location | /opt/recyclarr/ |
| Config | /root/.config/recyclarr/configs/arr-stack.yml |
| Auto-sync | Daily at 4 AM (cron) |
| Logs | /var/log/recyclarr.log |
Quality Profiles¶
| App | Profile | Use Case | x265 Policy |
|---|---|---|---|
| Radarr | HD Bluray + WEB | General movies | Allowed (score 0) |
| Radarr | Remux-1080p - Anime | Anime movies | Allowed |
| Sonarr | WEB-1080p | General TV | Allowed (score 0) |
| Sonarr | Remux-1080p - Anime | Anime TV | Allowed |
Legacy profiles (kept for compatibility): Any, Streaming (<11GB), <30GB, <3GB, etc.
x265 Policy¶
Our configuration prefers x265 for space efficiency while blocking garbage re-encodes:
| Custom Format | Score | Rationale |
|---|---|---|
| x265 (HD) | +500 | Preferred - smaller files, same quality |
| x265 (no HDR/DV) | -10000 | Blocked - garbage re-encodes |
| HEVC x265 | 0 | Neutral (legacy format) |
Why block "no HDR/DV"? If an x265 encode doesn't have HDR, it was likely re-encoded from an x264 source (double-lossy) rather than encoded from a proper 4K/HDR master.
Space savings: x265 preference typically reduces file sizes by 25-40% compared to x264 at equivalent quality.
Size Limits¶
Quality definitions set hard limits on file sizes (MB per minute of runtime):
Radarr (Movies):
| Quality | Max | Preferred | ~2hr Movie |
|---|---|---|---|
| Bluray-1080p | 125 MB/min | 85 MB/min | Max 15GB, prefer ~10GB |
| WEB-DL 1080p | 100 MB/min | 65 MB/min | Max 12GB, prefer ~8GB |
| Bluray-720p | 80 MB/min | 50 MB/min | Max 10GB, prefer ~6GB |
Sonarr (TV Episodes):
| Quality | Max | Preferred | ~45min Episode |
|---|---|---|---|
| Bluray-1080p | 90 MB/min | 45 MB/min | Max 4GB, prefer ~2GB |
| WEB-DL 1080p | 70 MB/min | 35 MB/min | Max 3GB, prefer ~1.5GB |
| Bluray-720p | 50 MB/min | 30 MB/min | Max 2.2GB, prefer ~1.3GB |
HDR Handling¶
Philosophy: Keep HDR content as HDR, let clients handle tone mapping.
For playback on SDR screens (abroad, mobile): - Plex/Jellyfin automatically tone-map HDR → SDR during transcoding - No need to download separate SDR versions - Requires: Plex Transcoder "Tone mapping" enabled, or Jellyfin with hardware transcoding
Home setup (4K OLED + HDR/DV): - Direct play HDR/DV content natively - No transcoding needed
TRaSH HDR Custom Formats (for 4K profiles):
| Custom Format | Score | Purpose |
|---|---|---|
| HDR | +500 | Prefer any HDR |
| DV-Boost | +1000 | Prefer Dolby Vision |
| HDR10+ Boost | +100 | Slight HDR10+ preference |
| DV (w/o HDR fallback) | -10000 | Block DV without HDR10 fallback |
| SDR | -10000 | Block SDR for 4K content |
Reference: TRaSH Guides - HDR Formats, Plex Tone Mapping
4K Strategy¶
TRaSH Recommendation: Run separate Radarr/Sonarr instances for 4K content because: - Radarr/Sonarr can only manage ONE file per movie/show - You often want both 1080p AND 4K versions - 4K has different scoring priorities (HDR/DV matter more)
Our Decision: Single instance with hybrid approach
| Factor | Our Setup | Impact |
|---|---|---|
| Upload speed | 15 Mbps | 4K can't direct play remotely (needs 40-80 Mbps) |
| Plex GPU | None (LXC 111) | 4K transcode = CPU-heavy, may buffer |
| Home display | 4K OLED + HDR/DV | Direct play works great locally |
Why we don't run separate 4K instances:
- Remote streaming: 15 Mbps upload means 4K must transcode anyway → better to grab 1080p
- No hardware transcode: Without GPU, 4K→1080p + tone mapping strains CPU
- Storage: 4K files are 3-5x larger than 1080p
- Complexity: Two libraries to manage, sync Overseerr, etc.
Hybrid approach instead:
For occasional 4K content (blockbusters, reference-quality films): 1. Manually set specific movie to "Ultra-HD" profile in Radarr 2. It grabs 4K version 3. Direct play on OLED at home 4. Accept CPU-heavy transcode for rare remote 4K viewing
When to reconsider: - Add GPU to Plex (Intel Arc A380 ~$100 recommended) - Upgrade to 50+ Mbps upload - Need simultaneous 4K streams
If adding 4K instances later (~1 hour lift):
- Add to docker-compose (copy existing config) - Configure Recyclarr withuhd-bluray-web template
- Add to Prowlarr sync
- Configure Overseerr for 4K server option
- Separate root folder: /mnt/media/movies4k/
Custom Formats (76 total)¶
Key categories synced from TRaSH Guides:
Release Group Tiers: - HD Bluray Tier 01-03 (1800/1750/1700) - WEB Tier 01-03 (1700/1650/1600) - Anime BD Tier 01-08 (SeaDex-based)
Streaming Services: AMZN, NF, DSNP, HMAX, ATVP (+75 each)
Blocked (-10000): - LQ (low quality groups) - BR-DISK, 3D, AV1 - Scene, Obfuscated, No-RlsGroup - Upscaled, Extras
Naming Conventions (TRaSH Recommended)¶
Radarr:
File: {Movie CleanTitle} ({Release Year}) {edition-{Edition Tags}} {[Custom Formats]}{[Quality Full]}{[MediaInfo AudioCodec}{ Mediainfo AudioChannels]}{[MediaInfo VideoDynamicRangeType]}{[Mediainfo VideoCodec]}{-Release Group}
Folder: {Movie CleanTitle} ({Release Year}) {tmdb-{TmdbId}}
Sonarr:
File: {Series TitleYear} - S{season:00}E{episode:00} - {Episode CleanTitle} [{Quality Full}]{[MediaInfo AudioCodec}{ Mediainfo AudioChannels]}{[MediaInfo VideoDynamicRangeType]}{[Mediainfo VideoCodec]}{-Release Group}
Series: {Series TitleYear} {tvdb-{TvdbId}}
Season: Season {season:00}
Common Operations¶
# Manual sync
ssh root@10.89.97.50 "cd /opt/recyclarr && ./recyclarr sync"
# Preview changes without applying
ssh root@10.89.97.50 "cd /opt/recyclarr && ./recyclarr sync --preview"
# View sync logs
ssh root@10.89.97.50 "cat /var/log/recyclarr.log"
# List available templates
ssh root@10.89.97.50 "cd /opt/recyclarr && ./recyclarr config list templates"
Configuration File¶
Location: /root/.config/recyclarr/configs/arr-stack.yml
radarr:
movies:
base_url: http://localhost:7878
api_key: <redacted>
include:
- template: radarr-quality-definition-movie
- template: radarr-quality-profile-hd-bluray-web
- template: radarr-custom-formats-hd-bluray-web
- template: radarr-quality-profile-anime
- template: radarr-custom-formats-anime
custom_formats:
# x265 tolerance override
- trash_ids:
- dc98083864ea246d05a42df0d05f81cc # x265 (HD)
assign_scores_to:
- name: HD Bluray + WEB
score: 0
sonarr:
tv:
base_url: http://localhost:8989
api_key: <redacted>
include:
- template: sonarr-quality-definition-series
- template: sonarr-v4-quality-profile-web-1080p
- template: sonarr-v4-custom-formats-web-1080p
- template: sonarr-quality-definition-anime
- template: sonarr-v4-quality-profile-anime
- template: sonarr-v4-custom-formats-anime
custom_formats:
# x265 tolerance override
- trash_ids:
- 47435ece6b99a0b477caf360e79ba0bb # x265 (HD)
assign_scores_to:
- name: WEB-1080p
score: 0
Upgrading Existing Media¶
How Upgrades Work¶
When a profile has Upgrades Allowed = Yes, Sonarr/Radarr will:
- Compare new releases against existing files using:
- Quality (resolution/source)
-
Custom Format score (release group tier, streaming service, etc.)
-
Download upgrade if new release scores higher
-
Replace old file - the old file is deleted automatically after successful import
-
Upgrade Until settings control when to stop:
- Upgrade Until Quality: Stop at this quality level
- Upgrade Until Score: Stop at this custom format score (default: 10000)
Current Profile Settings¶
| Profile | Upgrades | Upgrade Until Quality | Upgrade Until Score |
|---|---|---|---|
| HD Bluray + WEB | Yes | Bluray-1080p | 10000 |
| WEB-1080p | Yes | WEB 1080p | 10000 |
| Remux-1080p - Anime | Yes | Remux-1080p | 10000 |
Steps to Trigger Upgrades¶
Option 1: Automatic (Recommended)¶
Upgrades happen automatically when: - RSS sync finds a better release - Indexers are searched on schedule
Enable in Settings → Indexers: - RSS Sync Interval: 15-60 minutes - Automatic Search: On (for new additions)
Option 2: Manual Search (Existing Library)¶
Radarr - Single Movie: 1. Go to movie → click search icon (magnifying glass) 2. Review results, click download on better release
Radarr - Bulk Search: 1. Movies → Mass Editor → Select movies 2. Click "Search Selected" or use Wanted → Cutoff Unmet
Sonarr - Single Series: 1. Go to series → Season → click search icon 2. Or: Series → click search icon for all episodes
Sonarr - Bulk Search: 1. Wanted → Cutoff Unmet → shows episodes below quality cutoff 2. Click "Search All" or select specific episodes
Option 3: Wanted → Cutoff Unmet¶
This view shows all media that: - Has a file, but - File quality/score is below the profile's "Upgrade Until" settings
Radarr: Movies → Wanted → Cutoff Unmet Sonarr: Wanted → Cutoff Unmet
File Deletion Behavior¶
| Scenario | Old File | New File |
|---|---|---|
| Upgrade succeeds | Deleted | Imported with new name |
| Upgrade fails (import error) | Kept | Stays in download folder |
| Manual delete in UI | Deleted | N/A |
Important: Upgrades delete old files immediately. No recycle bin by default.
To enable recycle bin:
1. Settings → Media Management → File Management
2. Set "Recycling Bin" path (e.g., /mnt/media/.trash)
3. Set "Recycling Bin Cleanup" (e.g., 7 days)
Assigning New Profiles to Existing Media¶
Radarr: 1. Movies → Mass Editor 2. Select movies (or Select All) 3. Set "Quality Profile" dropdown to "HD Bluray + WEB" 4. Click "Apply Changes"
Sonarr: 1. Series → Mass Editor 2. Select series (or Select All) 3. Set "Quality Profile" dropdown to "WEB-1080p" 4. Click "Apply Changes"
For Anime content: - Use "Remux-1080p - Anime" profile instead
Monitoring Upgrades¶
Activity → Queue: Shows active downloads including upgrades
History: Shows all imports, including upgrades (look for "Upgrade" tag)
Logs: Settings → General → Log Level = Debug for detailed upgrade decisions
Space Considerations¶
With x265-tolerant profiles, expect: - Movies: ~6-7 GB avg (down from ~10 GB with x264) - TV: ~0.7-0.9 GB/episode (down from ~1.2 GB) - Potential savings: 25-35% on upgraded content
Upgrades will temporarily use extra space during download before old file is deleted.