A reusable, privacy-safe migration toolkit for moving Docker + VM workloads from one Unraid server to another with resumable transfer and controlled cutover.
- Language: English (this file)
- Deutsch: docs/README.de.md
- Srpski: docs/README.sr.md
- Product roadmap: docs/ROADMAP.md
Traditional Unraid migrations are often stressful and fragile. This toolkit turns migration into a repeatable workflow with checkpoints.
Core goals:
- No deletion on source server
- Do not touch existing production containers on target server
- Pause/resume anytime (unstable links supported)
- Move data first, cut over later
This project is being prepared to become a full Unraid App Hub (Community Applications) app with:
- live transfer dashboard
- workflow buttons
- complete SSH and port configuration in-app
- migration safety checks and rollback-oriented cutover guidance
This repository intentionally removes all private names, hostnames, and paths from the real migration.
All examples use generic names like:
source-servertarget-server/mnt/user/MigrationShare/migration
Recommended model: target pulls from source.
Benefits:
- Logs and state are centralized on target
- Source remains unchanged
- Rollback remains simple
Stages:
inventory(read-only inventory)appdata(docker app data)domains(vm disks)boot_config(important Unraid config)
scripts/migration orchestration scriptsjobs/job configuration templatesexamples/User Scripts examples for Unraid GUI buttonsdeploy/deploy helper for pushing this repo to target serverdocs/localized documentation (DE/SR)
On target server:
bash,ssh,rsync,ionice,nice- SSH key access to source server
On source server:
- SSH enabled
- root access for migration reads
./scripts/create_job.sh my_source_to_target 100.100.100.10 2222 /mnt/user/MigrationShare/migrationEdit jobs/my_source_to_target.env.
ssh-keygen -t ed25519 -N '' -f /root/.ssh/migrate_my_source_to_target -C 'migration my_source_to_target'
cat /root/.ssh/migrate_my_source_to_target.pubAdd the generated public key to source server:
mkdir -p /root/.ssh
chmod 700 /root/.ssh
echo '<PASTE_PUBLIC_KEY_HERE>' >> /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys./scripts/preflight_ssh.sh my_source_to_target./scripts/start_job.sh my_source_to_target./scripts/status_job.sh my_source_to_target
./scripts/tail_job.sh my_source_to_target appdata./scripts/stop_job.sh my_source_to_target
./scripts/resume_job.sh my_source_to_targetRun separate jobs for different source servers or datasets:
./scripts/start_job.sh sourceA_to_target
./scripts/start_job.sh sourceB_to_targetUse separate SSH keys and separate destination folders per job.
In each job file:
RSYNC_BWLIMIT="20m"NICE_LEVEL="15"IONICE_CLASS="2"IONICE_LEVEL="7"
These settings keep migration as a background workload.
Many apps store data outside appdata.
Always discover bind mounts on source:
docker inspect $(docker ps -aq) --format '{{range .Mounts}}{{.Source}}{{"\n"}}{{end}}' | grep '^/mnt/user/' | sort -uAdd separate rsync tasks for such shares.
Check:
/usr/sbin/sshd -T | egrep 'permitrootlogin|pubkeyauthentication|authorizedkeysfile'
ls -ld /root/.ssh
ls -l /root/.ssh/authorized_keysA container may bind host port 22, so SSH does not reach Unraid sshd.
Detect:
docker ps --format '{{.Names}}\t{{.Ports}}' | grep -E '0\.0\.0\.0:22->|:::22->'Fix:
- set Unraid SSH to a dedicated port (e.g.
2222or2223) - update
SRC_SSH_PORTin your job config
Copied files do not auto-create running services.
After data sync:
- Recreate/import Docker templates on target
- Point mounts to copied paths
- Recreate/import VMs and point disks to copied
domains - Run functional tests internally (LAN/Tailscale)
- Only then switch Cloudflare / external routing
- Run final delta sync with source services briefly stopped
- Start services on target
- Validate app logins, DB writes, file uploads
- Switch external routing last
- Keep source untouched until stable
From local workstation:
./deploy/install_on_target.sh 100.100.100.20 /mnt/user/MigrationShare/migration/UnraidMigrationThis repository and documentation were built with AI-assisted engineering workflow:
- OpenAI Codex (GPT-5 family) for script scaffolding, architecture, and troubleshooting flow
- AI-assisted documentation drafting (multilingual DE/EN/SR)
- Human operator validation and command execution on real systems
AI did not replace operator responsibility. It accelerated structure, repeatability, and incident-safe process design.
Detailed background article:
Use at your own risk. Always test in non-production first and keep verified backups.