Playbook: Migrate Stack Between Servers¶
Generic checklist cho việc migrate 1 service từ unraid → development (hoặc ngược lại). Verified infrastructure state: 2026-07-03.
Verified infrastructure (as of 2026-07-03)¶
| Component | Host | Access from dev | Port |
|---|---|---|---|
| Pigsty PostgreSQL | unraid (100.68.251.84) | Tailscale direct | 5439 |
| Redis | unraid (100.68.251.84) | Tailscale direct | 6379 |
| RustFS S3 | unraid (100.68.251.84) | Docker DNS only (reverse-proxy) | 9000 |
| Supabase PG | unraid (100.121.78.65) | Tailscale direct | 5432 |
| Komodo Core | dev (100.126.172.96:9120) | — | 9120 |
| SSH | dev: ssh development (user: lucndm) / unraid: ssh unraid (user: root) |
Tailscale | 22 |
| Komodo Periphery | both servers | Both ok in Komodo |
8120 |
Note: RustFS chỉ accessible qua Docker DNS (reverse-proxy network). Từ dev server, cần qua Caddy route http://s3.home (LAN) hoặc expose port.
Checklist¶
Phase 1: Pre-flight verify (TRƯỚC khi thay đổi gì)¶
- Dev server resources: SSH vào dev, check RAM/disk:
ssh root@100.126.172.96 'free -h; df -h' - Nếu SSH fail → verify periphery:
km list servers(cả 2 phảiok) - Dùng
km container -s developmentđể xem containers hiện tại - Data source connectivity: Test từ dev → unraid services: Nếu SSH fail → deploy temp container trên dev để test:
- Dev Docker network:
reverse-proxynetwork phải tồn tại trên dev: - Image pull: Image phải pull được trên dev:
Phase 2: Config changes¶
2a. Docker DNS → Tailscale IP¶
Mọi env var dùng Docker DNS (pigsty-postgres, redis, rustfs) phải đổi sang Tailscale IP:
# BEFORE (unraid)
DATABASE_SQLALCHEMY_URI: postgresql://user:pass@pigsty-postgres:5432/db
REDIS_HOST: redis
# AFTER (dev)
DATABASE_SQLALCHEMY_URI: postgresql://user:pass@100.68.251.84:5439/db
REDIS_HOST: 100.68.251.84
Port mapping khác nhau giữa Docker DNS và host port:
- Pigsty: Docker
5432→ host5439 - Redis: Docker
6379→ host6379(same) - RustFS: Docker
9000→ không expose host port
2b. TOML server tag¶
2c. Caddy route¶
Dev server có Caddy không? Nếu không, expose port trực tiếp hoặc deploy Caddy.
Nếu có Caddy trên dev → thêm route trong Caddy config trên dev. Nếu không → expose port trực tiếp trong compose.
2d. Datasource config (if Superset)¶
Update datasources.yaml credentials:
credentials:
host: 100.68.251.84 # Tailscale IP thay vì Docker DNS
port: "5439" # Host port thay vì Docker port
Phase 3: Deploy on dev¶
# 1. Push config changes
git add -A && git commit -m "feat({service}): migrate unraid → development" && git push
# 2. Sync TOML (picks up server tag change)
echo "" | km x run-sync {category}
# 3. Deploy on dev
echo "" | km x deploy-stack {service}
# 4. Stop on unraid (NOT destroy — keep for rollback)
echo "" | km x stop-stack {service}
Phase 4: Verify on dev¶
- Container running:
km container -s development | grep {service} - Health check:
curl http://{service}.{domain} - DB connection: check logs for DB errors
- Redis connection: check logs for cache errors
- Data source query (if applicable): SQL Lab or API test
- Functional test: login, create resource, verify persistence
Phase 5: Decommission on unraid (SAU khi verify OK)¶
Phase 6: Cleanup¶
- Update homepage
services.yaml(if domain changed) - Update Caddy routes (if moved Caddy route to dev)
- Update Cloudflare tunnel ingress (if domain moved)
- Sync Uptime Kuma:
uv run scripts/sync-uptime-kuma.py - Update
docs/codebase-summary.mdserver assignment
Rollback (if Phase 4 fails)¶
# 1. Stop on dev
echo "" | km x stop-stack {service}
# 2. Start on unraid (TOML still has old config cached)
echo "" | km x start-stack {service}
# 3. Revert git commit
git revert HEAD && git push
# 4. Re-sync + redeploy on unraid
echo "" | km x run-sync {category}
echo "" | km x deploy-stack {service}
Known constraints¶
| Constraint | Impact | Mitigation |
|---|---|---|
| RustFS chỉ trên Docker DNS | S3 clients từ dev phải qua Caddy s3.home hoặc expose port |
Add RustFS port mapping 9000:9000 or use http://s3.home (Caddy macvlan) |
| SSH to dev fails from workspace | Can't run direct diagnostics | Use km-exec -s development --host instead |
| Pigsty pg_hba auth | External connections need scram-sha-256 | Already configured for Docker subnet. Tailscale IPs may need additional rule. |
| Volume data | Local filesystem data doesn't auto-migrate | For metadata DBs (on Pigsty), no migration needed. For local storage (Nextcloud data), use rsync. |
Per-service migration notes¶
Superset → dev¶
- Metadata DB: Stays on Pigsty (no migration). URI changes to
100.68.251.84:5439. - Config file:
superset_config.pystays on volume. Migrate/mnt/user/appdata/superset/→ dev equivalent. - Data sources: Update
datasources.yamlhost to100.68.251.84, port to5439. - Redis:
100.68.251.84:6379(already exposed). - psycopg2 hack: Same entrypoint command needed on dev.
- psycopg2 PYTHONPATH: Same
command:override needed.