15 KiB
Fast Migration Plan - LXC/LXD to Incus (ONE BY ONE)
Strategy: STREAMING DATA TRANSFER (NO DISK I/O ON SOURCE)
Transfer container data directly via compressed stream, NO intermediate tarballs on source.
Use pv (pipe viewer) for colorful progress bars and rate monitoring.
Why This is FASTEST
✅ NO disk writes on source (99% full) - streaming only ✅ zstd compression - 3-5x faster than gzip ✅ pv monitoring - colorful progress, ETA, rate ✅ Parallel transfers - migrate multiple containers simultaneously ✅ Immediate deletion - frees space for next transfer
Prerequisites
On Source (82.29.59.188)
# Install required tools
sudo apt update && sudo apt install -y zstd pv
# List all containers
lxc list
On Destination (63.141.255.9)
# Incus is already installed and clean (LXC/LXD removed)
# Create PROD-GBO network bridge
sudo incus network create PROD-GBO --type bridge ipv4.address=10.107.115.1/24
# Create PROD-GBO1 project
sudo incus project create PROD-GBO1
sudo incus project switch PROD-GBO1
# Configure project
sudo incus project set PROD-GBO1 features.storage.volumes=true
sudo incus project set PROD-GBO1 features.profiles=true
Migration Workflow (Per Container)
Step 1: Stop Container on Source
# On source server
lxc stop pragmatismo-alm
Step 2: Stream Data to Destination (FASTEST - NO DISK I/O)
# On source server - stream compressed data directly
lxc exec pragmatismo-alm -- tar -cf - /opt/gbo/ | \
zstd -3 -q | \
pv -s $(du -sb /opt/gbo | awk '{print $1}') | \
ssh administrator@63.141.255.9 "zstd -d | tar -xf - -C ~/gbo/pragmatismo-alm/"
What happens:
tarreads /opt/gbo from container (streamed, no disk write)zstd -3compresses on-the-fly (fast compression)pvshows colorful progress with ETA and ratesshstreams to destination- Destination decompresses and extracts directly to ~/gbo/pragmatismo-alm/
- NO tarball on source disk - solves 99% full problem!
pv Options:
-s: Total size (fromdu -sbfor accurate progress)- Colorful output with ETA, rate, elapsed time
Step 3: Delete Container from Source
# Free space immediately for next transfer
lxc delete pragmatismo-alm
Step 4: Create Fresh Incus Container
# On destination server
sudo incus launch images:debian/12/cloud pragmatismo-alm
# Add network
sudo incus config device add pragmatismo-alm eth0 nic name=eth0 network=PROD-GBO
# Set static IP
sudo incus config set pragmatismo-alm ipv4.address=10.107.115.4
# Create gbuser inside container
sudo incus exec pragmatismo-alm -- useradd -m -s /bin/bash gbuser
Step 5: Push Data to Container
# Create directory structure
sudo incus exec pragmatismo-alm -- mkdir -p /opt/gbo
# Push data (recursive)
sudo incus file push -r ~/gbo/pragmatismo-alm/* pragmatismo-alm/opt/gbo/
# Fix ownership
sudo incus exec pragmatismo-alm -- chown -R gbuser:gbuser /opt/gbo
# Make binaries executable
sudo incus exec pragmatismo-alm -- chmod +x /opt/gbo/bin/*
Step 6: Start Container and Verify Service
sudo incus start pragmatismo-alm
# Check service status
sudo incus exec pragmatismo-alm -- systemctl status alm
# Check logs
sudo incus exec pragmatismo-alm -- journalctl -u alm -f
Step 7: Configure NAT Rules (ON HOST, NOT IN CONTAINER)
# On destination host (63.141.255.9)
# For ALM (example):
sudo iptables -t nat -A PREROUTING -p tcp --dport 4747 -j DNAT --to-destination 10.107.115.4:4747
sudo iptables -t nat -A OUTPUT -p tcp --dport 4747 -j DNAT --to-destination 10.107.115.4:4747
sudo iptables -A FORWARD -p tcp -d 10.107.115.4 --dport 4747 -j ACCEPT
sudo iptables -t nat -A POSTROUTING -p tcp -d 10.107.115.4 -j MASQUERADE
# Save rules
sudo sh -c 'iptables-save > /etc/iptables/rules.v4'
Full Migration Script (ALL CONTAINERS)
Run Multiple Containers in Parallel (for speed)
#!/bin/bash
# MIGRATE-ALL.sh - Fast parallel migration
set -e
# Container list with IPs
declare -A CONTAINERS=(
["dns"]="10.107.115.155"
["email"]="10.107.115.200"
["webmail"]="10.107.115.208"
["alm"]="10.107.115.4"
["drive"]="10.107.115.114"
["tables"]="10.107.115.33"
["system"]="10.107.115.229"
["alm-ci"]="10.107.115.190"
["table-editor"]="10.107.115.73"
)
for container in "${!CONTAINERS[@]}"; do
ip="${CONTAINERS[$container]}"
echo -e "\e[1;32m=== Migrating $container ($ip) ===\e[0m"
# Step 1: Stop
echo -e "\e[1;33mStopping $container...\e[0m"
ssh root@82.29.59.188 "lxc stop $container" || true
# Step 2: Get size for pv
echo -e "\e[1;33mGetting size of /opt/gbo...\e[0m"
size=$(ssh root@82.29.59.188 "lxc exec $container -- du -sb /opt/gbo | awk '{print \$1}'")
# Step 3: Stream data (FAST!)
echo -e "\e[1;33mStreaming data to destination...\e[0m"
ssh root@82.29.59.188 "lxc exec $container -- tar -cf - /opt/gbo/" | \
zstd -3 -q | \
pv -s $size | \
ssh administrator@63.141.255.9 "mkdir -p ~/gbo/$container && zstd -d | tar -xf - -C ~/gbo/$container/"
# Step 4: Delete from source
echo -e "\e[1;33mDeleting $container from source...\e[0m"
ssh root@82.29.59.188 "lxc delete $container"
# Step 5: Create fresh container
echo -e "\e[1;33mCreating Incus container...\e[0m"
ssh administrator@63.141.255.9 "sudo incus launch images:debian/12/cloud $container && \
sudo incus config device add $container eth0 nic name=eth0 network=PROD-GBO && \
sudo incus config set $container ipv4.address=$ip && \
sudo incus exec $container -- useradd -m -s /bin/bash gbuser"
# Step 6: Push data
echo -e "\e[1;33mPushing data to container...\e[0m"
ssh administrator@63.141.255.9 "sudo incus exec $container -- mkdir -p /opt/gbo && \
sudo incus file push -r ~/gbo/$container/* $container:/opt/gbo/ && \
sudo incus exec $container -- chown -R gbuser:gbuser /opt/gbo && \
sudo incus exec $container -- chmod +x /opt/gbo/bin/*"
# Step 7: Start
echo -e "\e[1;33mStarting $container...\e[0m"
ssh administrator@63.141.255.9 "sudo incus start $container"
echo -e "\e[1;32m✓ $container migrated successfully!\e[0m"
echo ""
done
echo -e "\e[1;32m=== ALL MIGRATIONS COMPLETE ===\e[0m"
Single Container Migration (Quick Test)
#!/bin/bash
# migrate-one.sh - Migrate single container
CONTAINER=$1
if [ -z "$CONTAINER" ]; then
echo "Usage: $0 <container-name>"
exit 1
fi
echo -e "\e[1;32m=== Migrating $CONTAINER ===\e[0m"
# Stop on source
echo -e "\e[1;33m[1/7] Stopping container...\e[0m"
ssh root@82.29.59.188 "lxc stop $CONTAINER"
# Get size
echo -e "\e[1;33m[2/7] Getting data size...\e[0m"
SIZE=$(ssh root@82.29.59.188 "lxc exec $CONTAINER -- du -sb /opt/gbo | awk '{print \$1}'")
# Stream data (NO DISK WRITE!)
echo -e "\e[1;33m[3/7] Streaming data (pv will show progress)...\e[0m"
ssh root@82.29.59.188 "lxc exec $CONTAINER -- tar -cf - /opt/gbo/" | \
zstd -3 -q | \
pv -s $SIZE | \
ssh administrator@63.141.255.9 "mkdir -p ~/gbo/$CONTAINER && zstd -d | tar -xf - -C ~/gbo/$CONTAINER/"
# Delete from source
echo -e "\e[1;33m[4/7] Deleting from source...\e[0m"
ssh root@82.29.59.188 "lxc delete $CONTAINER"
# Create container
echo -e "\e[1;33m[5/7] Creating Incus container...\e[0m"
ssh administrator@63.141.255.9 "sudo incus launch images:debian/12/cloud $CONTAINER && \
sudo incus config device add $CONTAINER eth0 nic name=eth0 network=PROD-GBO && \
sudo incus exec $CONTAINER -- useradd -m -s /bin/bash gbuser"
# Push data
echo -e "\e[1;33m[6/7] Pushing data...\e[0m"
ssh administrator@63.141.255.9 "sudo incus exec $CONTAINER -- mkdir -p /opt/gbo && \
sudo incus file push -r ~/gbo/$CONTAINER/* $CONTAINER:/opt/gbo/ && \
sudo incus exec $CONTAINER -- chown -R gbuser:gbuser /opt/gbo && \
sudo incus exec $CONTAINER -- chmod +x /opt/gbo/bin/*"
# Start
echo -e "\e[1;33m[7/7] Starting container...\e[0m"
ssh administrator@63.141.255.9 "sudo incus start $CONTAINER"
echo -e "\e[1;32m✓ Migration complete! Check with: incus list\e[0m"
Port Forwarding (iptables NAT) - Complete Rules
# Enable IP forwarding (persistent)
echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-ipforward.conf
sudo sysctl -w net.ipv4.ip_forward=1
# Enable route_localnet
echo "net.ipv4.conf.all.route_localnet = 1" | sudo tee /etc/sysctl.d/99-localnet.conf
sudo sysctl -w net.ipv4.conf.all.route_localnet=1
# DNS (53)
sudo iptables -t nat -A PREROUTING -p udp --dport 53 -j DNAT --to-destination 10.107.115.155:53
sudo iptables -t nat -A PREROUTING -p tcp --dport 53 -j DNAT --to-destination 10.107.115.155:53
sudo iptables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to-destination 10.107.115.155:53
sudo iptables -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to-destination 10.107.115.155:53
# Email (25,465,587,993,995,143,110,4190)
sudo iptables -t nat -A PREROUTING -p tcp --dport 25 -j DNAT --to-destination 10.107.115.200:25
sudo iptables -t nat -A PREROUTING -p tcp --dport 465 -j DNAT --to-destination 10.107.115.200:465
sudo iptables -t nat -A PREROUTING -p tcp --dport 587 -j DNAT --to-destination 10.107.115.200:587
sudo iptables -t nat -A PREROUTING -p tcp --dport 993 -j DNAT --to-destination 10.107.115.200:993
sudo iptables -t nat -A PREROUTING -p tcp --dport 995 -j DNAT --to-destination 10.107.115.200:995
sudo iptables -t nat -A PREROUTING -p tcp --dport 143 -j DNAT --to-destination 10.107.115.200:143
sudo iptables -t nat -A PREROUTING -p tcp --dport 110 -j DNAT --to-destination 10.107.115.200:110
sudo iptables -t nat -A PREROUTING -p tcp --dport 4190 -j DNAT --to-destination 10.107.115.200:4190
sudo iptables -t nat -A OUTPUT -p tcp --dport 25 -j DNAT --to-destination 10.107.115.200:25
sudo iptables -t nat -A OUTPUT -p tcp --dport 465 -j DNAT --to-destination 10.107.115.200:465
sudo iptables -t nat -A OUTPUT -p tcp --dport 587 -j DNAT --to-destination 10.107.115.200:587
sudo iptables -t nat -A OUTPUT -p tcp --dport 993 -j DNAT --to-destination 10.107.115.200:993
sudo iptables -t nat -A OUTPUT -p tcp --dport 995 -j DNAT --to-destination 10.107.115.200:995
sudo iptables -t nat -A OUTPUT -p tcp --dport 143 -j DNAT --to-destination 10.107.115.200:143
sudo iptables -t nat -A OUTPUT -p tcp --dport 110 -j DNAT --to-destination 10.107.115.200:110
sudo iptables -t nat -A OUTPUT -p tcp --dport 4190 -j DNAT --to-destination 10.107.115.200:4190
# Webmail (5252)
sudo iptables -t nat -A PREROUTING -p tcp --dport 5252 -j DNAT --to-destination 10.107.115.208:5252
sudo iptables -t nat -A OUTPUT -p tcp --dport 5252 -j DNAT --to-destination 10.107.115.208:5252
# ALM (4747)
sudo iptables -t nat -A PREROUTING -p tcp --dport 4747 -j DNAT --to-destination 10.107.115.4:4747
sudo iptables -t nat -A OUTPUT -p tcp --dport 4747 -j DNAT --to-destination 10.107.115.4:4747
# Tables/PostgreSQL (5432)
sudo iptables -t nat -A PREROUTING -p tcp --dport 5432 -j DNAT --to-destination 10.107.115.33:5432
sudo iptables -t nat -A OUTPUT -p tcp --dport 5432 -j DNAT --to-destination 10.107.115.33:5432
# Proxy/Caddy (80, 443)
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 10.107.115.236:80
sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-destination 10.107.115.236:443
sudo iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to-destination 10.107.115.236:80
sudo iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to-destination 10.107.115.236:443
# FORWARD rules (allow traffic to containers)
sudo iptables -A FORWARD -p tcp -d 10.107.115.155 -j ACCEPT
sudo iptables -A FORWARD -p udp -d 10.107.115.155 -j ACCEPT
sudo iptables -A FORWARD -p tcp -d 10.107.115.200 -j ACCEPT
sudo iptables -A FORWARD -p tcp -s 10.107.115.200 -j ACCEPT
sudo iptables -A FORWARD -p tcp -d 10.107.115.208 -j ACCEPT
sudo iptables -A FORWARD -p tcp -d 10.107.115.4 -j ACCEPT
sudo iptables -A FORWARD -p tcp -d 10.107.115.33 -j ACCEPT
sudo iptables -A FORWARD -p tcp -d 10.107.115.236 -j ACCEPT
sudo iptables -A FORWARD -p tcp -s 10.107.115.236 -j ACCEPT
# POSTROUTING MASQUERADE (return traffic)
sudo iptables -t nat -A POSTROUTING -p tcp -d 10.107.115.155 -j MASQUERADE
sudo iptables -t nat -A POSTROUTING -p udp -d 10.107.115.155 -j MASQUERADE
sudo iptables -t nat -A POSTROUTING -p tcp -d 10.107.115.200 -j MASQUERADE
sudo iptables -t nat -A POSTROUTING -p tcp -d 10.107.115.208 -j MASQUERADE
sudo iptables -t nat -A POSTROUTING -p tcp -d 10.107.115.4 -j MASQUERADE
sudo iptables -t nat -A POSTROUTING -p tcp -d 10.107.115.33 -j MASQUERADE
sudo iptables -t nat -A POSTROUTING -p tcp -d 10.107.115.236 -j MASQUERADE
# Save rules
sudo sh -c 'iptables-save > /etc/iptables/rules.v4'
Benefits of This Approach
✅ FASTEST - No intermediate tarballs, pure streaming ✅ COLORFUL - pv shows beautiful progress bars ✅ EFFICIENT - zstd compression (3-5x gzip) ✅ SAFE - One container at a time, verify before next ✅ CLEAN - Immediate deletion frees disk space ✅ MONITORED - Real-time transfer rate and ETA ✅ PARALLEL - Can migrate multiple containers at once
Estimated time:
- Small containers (<1GB): ~5-10 minutes each
- Medium containers (1-5GB): ~10-20 minutes each
- Large containers (>5GB): ~20-40 minutes each
- Total (parallel): ~1-2 hours for all containers
vs lxc export method: ~4-8 hours total
Quick Start
# 1. Install pv on source
ssh root@82.29.59.188 "apt install -y pv zstd"
# 2. Save migration scripts
# Copy migrate-one.sh and MIGRATE-ALL.sh
# 3. Run single test
./migrate-one.sh pragmatismo-alm
# 4. If successful, run all
./MIGRATE-ALL.sh
Troubleshooting
pv not showing progress?
# Check pv is installed
pv --version
# Check size detection
ssh root@82.29.59.188 "lxc exec pragmatismo-alm -- du -sb /opt/gbo"
Container not starting?
# Check logs
sudo incus list
sudo incus info pragmatismo-alm
sudo incus logs pragmatismo-alm --show-log
# Check network
sudo incus exec pragmatismo-alm -- ip addr
Service not running?
# Inside container
sudo incus exec pragmatismo-alm -- bash
systemctl status alm
journalctl -u alm -n 50
NAT not working?
# Check rules
sudo iptables -t nat -L -n -v
# Check forwarding
sudo iptables -L FORWARD -n -v
# Test from host
nc -zv 127.0.0.1 4747
Summary
This plan achieves: ✅ FASTEST possible migration - streaming, no disk I/O ✅ Colorful progress - pv with ETA, rate, elapsed ✅ Immediate space cleanup - delete as we go ✅ Parallel migration - do multiple containers at once ✅ Clean Incus - fresh start, no LXC/LXD trash ✅ Proper NAT - iptables only, no socat/proxy devices
No mbuffer needed - pv does the job with colorful output!
Verification Checklist
After each migration:
- Container running:
sudo incus list - Service active:
sudo incus exec $c -- systemctl status <service> - Data intact:
sudo incus exec $c -- ls -la /opt/gbo - Port accessible:
nc -zv 127.0.0.1 <port> - Source deleted:
ssh root@82.29.59.188 lxc list(should not show container) - NAT rules added:
sudo iptables -t nat -L -n | grep <ip>
After all migrations:
- All containers running on Incus
- All services active
- All NAT rules configured
- External access works
- Source server: no containers left