Skip to content

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

ssh root@10.89.97.50
cd /opt/arr-stack

View Services

ssh root@10.89.97.50 "cd /opt/arr-stack && docker compose ps"

View Logs

ssh root@10.89.97.50 "cd /opt/arr-stack && docker compose logs -f <service>"

Restart Service

ssh root@10.89.97.50 "cd /opt/arr-stack && docker compose restart <service>"

Update All Services

ssh root@10.89.97.50 "cd /opt/arr-stack && docker compose pull && docker compose up -d"

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:

ssh root@10.89.97.50 "cd /opt/arr-stack && docker compose logs gluetun"

Verify VPN is working (should show VPN IP, not host IP):

ssh root@10.89.97.50 "docker exec deluge curl -s ifconfig.me"

Service Can't Access Downloads

Verify volume mounts:

ssh root@10.89.97.50 "docker exec sonarr ls -la /data/downloads"

Check permissions:

ssh root@10.89.97.50 "ls -la /mnt/downloads"

Container Won't Start

Check logs for specific service:

ssh root@10.89.97.50 "cd /opt/arr-stack && docker compose logs <service>"

Recreate container:

ssh root@10.89.97.50 "cd /opt/arr-stack && docker compose up -d --force-recreate <service>"

General Config Issues

Most *arr apps store configs in INI or XML format. To edit directly:

  1. Stop the container: docker compose stop <service>
  2. Edit config: nano configs/<service>/<config-file>
  3. 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:

ssh root@10.89.97.50 "cd /opt/arr-stack && docker compose restart radarr sonarr"

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:

ssh root@10.89.97.50 "cd /opt/arr-stack && docker compose restart radarr"

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:

  1. Torrent seeding: Deluge keeps files until seed ratio is met (default 2:1)
  2. Orphaned downloads: Failed imports leave files behind
  3. Duplicate downloads: SABnzbd retries create .1, .2, .3 suffix 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:

  1. Sonarr/Radarr/Lidarr Web UI:
  2. Settings → Media Management → Permissions
  3. Enable "Set Permissions"
  4. Set "chmod Folder" to 777

  5. 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:

  1. Remote streaming: 15 Mbps upload means 4K must transcode anyway → better to grab 1080p
  2. No hardware transcode: Without GPU, 4K→1080p + tone mapping strains CPU
  3. Storage: 4K files are 3-5x larger than 1080p
  4. 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):

radarr4k.bogocat.com → new Radarr container
sonarr4k.bogocat.com → new Sonarr container
- Add to docker-compose (copy existing config) - Configure Recyclarr with uhd-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

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:

  1. Compare new releases against existing files using:
  2. Quality (resolution/source)
  3. Custom Format score (release group tier, streaming service, etc.)

  4. Download upgrade if new release scores higher

  5. Replace old file - the old file is deleted automatically after successful import

  6. Upgrade Until settings control when to stop:

  7. Upgrade Until Quality: Stop at this quality level
  8. 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

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.