claude-home/vm-management/wave2-migration-results.md
Cal Corum 11b96bce2c CLAUDE: Add LXC migration guides and scripts
- Add LXC migration plan and quick-start guide
- Add wave 1 and wave 2 migration results
- Add lxc-docker-create.sh for container creation
- Add fix-docker-apparmor.sh for AppArmor issues
- Add comprehensive LXC migration guide

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 00:48:30 -06:00

7.6 KiB

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

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

//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

  • Configure SABnzbd with Usenet provider
  • Connect arr apps to new SABnzbd
  • Update NPM reverse proxy entries
  • Test movie/show requests through Jellyseerr

After 48 Hours

  • 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)