---
title: "Wave 2 Migration Results"
description: "Results from migrating docker-vpn (VM 121) to arr-stack LXC 221. Documents VPN elimination rationale, Overseerr-to-Jellyseerr switch, and arr stack (Sonarr/Radarr/Readarr/SABnzbd) deployment."
type: reference
domain: vm-management
tags: [proxmox, lxc, migration, docker, arr-stack, sonarr, radarr, jellyseerr, usenet]
---

# Wave 2 Migration Results - docker-vpn (VM 121 → LXC 221 arr-stack)

**Date**: 2025-12-05
**Status**: **SUCCESSFUL**
**Migration Time**: ~2 hours

---

## Summary

Successfully migrated and restructured docker-vpn VM (121) to arr-stack LXC (221). The migration involved a significant architecture simplification - eliminating the Mullvad VPN entirely since only Usenet is used (SSL to Usenet provider is sufficient, no torrents). Additionally replaced Overseerr with Jellyseerr for native Jellyfin support.

---

## Migration Details

### Source (VM 121 - docker-vpn)
- **OS**: Ubuntu (in VM)
- **Services**: Sonarr, Radarr, Readarr, Overseerr, SABnzbd, Mullvad VPN
- **Architecture**: All traffic routed through Mullvad VPN container
- **Complexity**: High (VPN routing, multiple network namespaces)

### Destination (LXC 221 - arr-stack)
- **OS**: Ubuntu 20.04 LTS (privileged LXC)
- **Resources**: 2 cores, 4GB RAM, 32GB disk
- **IP**: 10.10.0.221
- **Services**: Sonarr, Radarr, Readarr, Jellyseerr, SABnzbd
- **Architecture**: Direct network access (no VPN)
- **Complexity**: Low (standard Docker containers)

---

## Architecture Changes

### Before (docker-vpn)
```
Internet
    ↓
Mullvad VPN Container
    ↓ (all traffic tunneled)
├─ Sonarr
├─ Radarr
├─ Readarr
├─ Overseerr
└─ SABnzbd
```

### After (arr-stack)
```
Internet
    ↓ (direct, SSL encrypted to Usenet)
├─ Sonarr
├─ Radarr
├─ Readarr
├─ Jellyseerr (replaced Overseerr)
└─ SABnzbd
```

### Key Decision: VPN Elimination
**Rationale**:
- Only using Usenet (not torrents)
- Usenet providers support SSL encryption
- SSL to Usenet provider provides sufficient privacy
- VPN added complexity without meaningful benefit
- Simplified troubleshooting and maintenance

---

## Technical Implementation

### LXC Configuration
```
# /etc/pve/lxc/221.conf
arch: amd64
cores: 2
features: nesting=1,keyctl=1
hostname: arr-stack
memory: 4096
net0: name=eth0,bridge=vmbr0,gw=10.10.0.1,ip=10.10.0.221/24,type=veth
ostype: ubuntu
rootfs: local-lvm:vm-221-disk-0,size=32G
swap: 512
lxc.apparmor.profile: unconfined
```

### Docker Compose
```yaml
services:
  sonarr:
    image: linuxserver/sonarr:latest
    container_name: sonarr
    ports: ["8989:8989"]
    volumes:
      - ./config/sonarr:/config
      - /mnt/media:/media
    security_opt: [apparmor=unconfined]
    restart: unless-stopped

  radarr:
    image: linuxserver/radarr:latest
    container_name: radarr
    ports: ["7878:7878"]
    volumes:
      - ./config/radarr:/config
      - /mnt/media:/media
    security_opt: [apparmor=unconfined]
    restart: unless-stopped

  readarr:
    image: ghcr.io/hotio/readarr:latest
    container_name: readarr
    ports: ["8787:8787"]
    volumes:
      - ./config/readarr:/config
      - /mnt/media:/media
    security_opt: [apparmor=unconfined]
    restart: unless-stopped

  jellyseerr:
    image: fallenbagel/jellyseerr:latest
    container_name: jellyseerr
    ports: ["5055:5055"]
    volumes:
      - ./config/jellyseerr:/app/config
    security_opt: [apparmor=unconfined]
    restart: unless-stopped

  sabnzbd:
    image: linuxserver/sabnzbd:latest
    container_name: sabnzbd
    ports: ["8080:8080"]
    volumes:
      - ./config/sabnzbd:/config
      - ./downloads:/downloads
      - /mnt/media:/media
    security_opt: [apparmor=unconfined]
    restart: unless-stopped
```

### CIFS Mount
```fstab
//10.10.0.35/media /mnt/media cifs vers=3.0,uid=0,credentials=/root/.smbcredentials 0 0
```

---

## Issues Encountered & Solutions

### Issue 1: linuxserver.io Registry (lscr.io) Pull Failures
**Problem**: `no matching manifest for linux/amd64` errors from lscr.io registry
**Solution**: Switched to Docker Hub images directly (`linuxserver/sonarr` instead of `lscr.io/linuxserver/sonarr`)

### Issue 2: Readarr Image Not Available
**Problem**: linuxserver/readarr:develop tag not available for amd64
**Solution**: Switched to hotio image (`ghcr.io/hotio/readarr:latest`)

### Issue 3: Jellyseerr Tag Validation Error
**Problem**: Radarr rejecting requests with "Label: Allowed characters a-z, 0-9 and -"
**Cause**: Jellyseerr sending tags with invalid characters to Radarr
**Solution**: Disabled tags in Jellyseerr Radarr integration settings

---

## Data Migration

### Configs Migrated
- **Sonarr**: ~1.4GB (database, MediaCover cache, backups)
- **Radarr**: ~1.6GB (database, MediaCover cache, backups)
- **Readarr**: ~88MB (database, backups)
- **Overseerr**: ~7.7MB (database, settings) - Not used, replaced with Jellyseerr

### Fresh Configuration Required
- **SABnzbd**: Fresh install (user configured Usenet provider)
- **Jellyseerr**: Fresh install (connected to Jellyfin)

---

## Validation Results

| Service | Port | Status | Test |
|---------|------|--------|------|
| Sonarr | 8989 | HTTP 200 | Database loaded, shows configured |
| Radarr | 7878 | HTTP 200 | Database loaded, movie requests working |
| Readarr | 8787 | HTTP 200 | Database loaded, shows configured |
| Jellyseerr | 5055 | HTTP 307 | Connected to Jellyfin, requests working |
| SABnzbd | 8080 | HTTP 303 | Configured with Usenet provider |
| CIFS Mount | - | Working | Media accessible in containers |

---

## Resource Comparison

### Before (VM 121)
- **Memory**: Full VM overhead (~1-2GB for OS)
- **Disk**: Larger allocation for VM image
- **Complexity**: VPN routing, multiple network namespaces
- **Maintenance**: VPN updates, connection monitoring

### After (LXC 221)
- **Memory**: ~100MB LXC overhead
- **Disk**: 32GB (minimal)
- **Complexity**: Standard Docker containers
- **Maintenance**: Standard container updates only

### Efficiency Gains
- **~1.5GB RAM saved** (VM overhead eliminated)
- **Simplified networking** (no VPN routing)
- **Reduced attack surface** (fewer services)
- **Faster boot time** (LXC vs VM)

---

## NPM/Reverse Proxy Updates

Updated Nginx Proxy Manager entries to point to new IP:
- sonarr.manticorum.com → 10.10.0.221:8989
- radarr.manticorum.com → 10.10.0.221:7878
- readarr.manticorum.com → 10.10.0.221:8787
- jellyseerr.manticorum.com → 10.10.0.221:5055 (new, replaces overseerr)
- sabnzbd.manticorum.com → 10.10.0.221:8080

---

## Rollback Capability

- **VM 121 preserved**: Can be restarted if issues arise
- **Rollback time**: <5 minutes
- **Recommendation**: Keep VM 121 stopped for 48 hours, then decommission

---

## Key Learnings

### 1. VPN Complexity Often Unnecessary
For Usenet-only setups, VPN adds complexity without meaningful benefit. SSL to the Usenet provider is sufficient.

### 2. Image Registry Issues
lscr.io can have availability issues. Docker Hub images work as fallback.

### 3. Application Substitution
Jellyseerr is a drop-in replacement for Overseerr with native Jellyfin support - worth the switch if using Jellyfin.

### 4. Tag/Label Validation
When connecting Jellyseerr to arr apps, be careful with tag configurations - invalid characters cause silent failures.

---

## Next Steps

### Immediate
- [x] Configure SABnzbd with Usenet provider
- [x] Connect arr apps to new SABnzbd
- [x] Update NPM reverse proxy entries
- [x] Test movie/show requests through Jellyseerr

### After 48 Hours
- [x] Decommission VM 121 (docker-vpn)
- [ ] Clean up local migration temp files (`/tmp/arr-config-migration/`)

---

## Files Created/Modified

### On LXC 221
- `/opt/arr-stack/docker-compose.yml`
- `/opt/arr-stack/config/` (all service configs)
- `/root/.smbcredentials`
- `/etc/fstab` (CIFS mount)

### Documentation Updated
- `vm-management/lxc-migration-plan.md` - Wave 2 status
- `networking/server-inventory.md` - Added arr-stack entry
- `vm-management/wave2-migration-results.md` - This file

---

**Status**: **Wave 2 Complete - Ready for Wave 3**
**Contact**: Cal Corum (cal.corum@gmail.com)
