Skip to content

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ải ok)
  • Dùng km container -s development để xem containers hiện tại
  • Data source connectivity: Test từ dev → unraid services:
    ssh root@100.126.172.96 'nc -w2 100.68.251.84 5439 && echo PG_OK || echo PG_FAIL'  # Pigsty
    ssh root@100.126.172.96 'nc -w2 100.68.251.84 6379 && echo REDIS_OK || echo REDIS_FAIL'  # Redis
    
    Nếu SSH fail → deploy temp container trên dev để test:
    km-exec -s development alpine sh -c "nc -w2 100.68.251.84 5439 && echo PG_OK || echo PG_FAIL"
    
  • Dev Docker network: reverse-proxy network phải tồn tại trên dev:
    km-exec -s development --host 'docker network ls | grep reverse-proxy'
    
  • Image pull: Image phải pull được trên dev:
    km-exec -s development --host 'docker pull {image}:{tag}'
    

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 → host 5439
  • Redis: Docker 6379 → host 6379 (same)
  • RustFS: Docker 9000 → không expose host port

2b. TOML server tag

# BEFORE
server = "unraid"

# AFTER
server = "development"

2c. Caddy route

Dev server có Caddy không? Nếu không, expose port trực tiếp hoặc deploy Caddy.

km-exec -s development --host 'docker ps | grep 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)

# Only after Phase 4 all green
echo "" | km x destroy-stack {service}

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.md server 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.py stays on volume. Migrate /mnt/user/appdata/superset/ → dev equivalent.
  • Data sources: Update datasources.yaml host to 100.68.251.84, port to 5439.
  • Redis: 100.68.251.84:6379 (already exposed).
  • psycopg2 hack: Same entrypoint command needed on dev.
  • psycopg2 PYTHONPATH: Same command: override needed.