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

279 lines
7.6 KiB
Markdown

# 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
- [ ] 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)