# migration-guide [🇺🇸English](#english) · [🇪🇸Español](#español) --- # English Zero-downtime migration from the legacy WireGuard + Go API stack to operator-docker. Existing VPN clients reconnect automatically — no new configuration required on their end. --- ## How it works ```text Before migration Legacy stack (sp-env-wireguard-ipv6) ├── wireguard (linuxserver/wireguard) ├── wireguard-api (Go) └── nginx-certbot After migration operator-docker ├── wireguard (same identity — same public key) ├── operator-api (FastAPI) ├── marzban ├── hysteria2 └── mysql ``` The server's WireGuard identity (private key → public key) is preserved. All peers are migrated via the new API. Clients reconnect without any config change. --- ## Prerequisites - Legacy stack running (`docker ps` shows `wireguard`) - Domain with DNS pointing to this server - One subdomain per service (`api`, `legacy`, `cdn`, `news` or similar) - SSH key authorized by Simplified Privacy (generated in step 00) - Port 80/TCP reachable externally (required by Let's Encrypt) --- ## Migration steps | Script | Run as | Description | | :----- | :----- | :---------- | | `00-migrate-root.sh` | root | Backup, shutdown legacy, clean system | | `01-migrate-user.sh` | user | Clone repo, install operator-docker | | `02-migrate-peers.sh` | user | Inject identity, migrate peers | --- ## Usage Scripts can be run from any directory: ```bash sudo bash ~/migration/00-migrate-root.sh bash ~/migration/01-migrate-user.sh bash ~/migration/02-migrate-peers.sh ``` --- ## Step 00 — Backup and cleanup Run as root: ```bash sudo bash 00-migrate-root.sh ``` What it does: | Action | Detail | | :----- | :----- | | Detects legacy WireGuard container | By image or name | | Backs up private key and public key | Saved to `~/.wg-migration/` | | Backs up all peers | From `wg showconf wg0` | | Backs up Nginx configs and SSL certs | Full `/etc/nginx` and `/etc/letsencrypt` | | Backs up UFW rules | Snapshot only | | Generates SSH key | For repo access | | Shuts down legacy stack | `docker compose down` | | Cleans Nginx | Removes all sites for fresh install | | Verifies port 51820 is free | Fails if still in use | At the end, the script prints the SSH public key. Send it to Simplified Privacy before running `01`. --- ## Step 01 — Install operator-docker Once Simplified Privacy authorizes the SSH key, run as your Linux user: ```bash bash 01-migrate-user.sh ``` What it does: | Action | Detail | | :----- | :----- | | Validates backups exist | Fails early if `00` was not run | | Cleans any failed previous install | Detects corrupt `.env`, incomplete repo | | Clones private repo | Via SSH | | Runs `install.sh` in migration mode | WireGuard is NOT started yet | | Creates `wg0.conf` placeholder | `02` will inject the real private key | | Restores external Nginx configs | e.g. mail server vhosts | > `MIGRATION_MODE=1` tells the installer to skip starting WireGuard. The `02` script starts it after injecting the legacy identity. --- ## Step 02 — Migrate identity and peers ```bash bash 02-migrate-peers.sh ``` What it does: | Action | Detail | | :----- | :----- | | Stops legacy WireGuard | Via `docker compose stop` in legacy dir | | Injects legacy private key | Into `wg0.conf` and server keyfiles | | Starts new WireGuard | With the legacy identity | | Verifies public key matches | Fails and rolls back if it doesn't | | Verifies API is responding | `GET /wireguard/peers` must return 200 | | Migrates all peers | `POST /wireguard/peers` for each peer | | Destroys private key from disk | `shred` or `rm` | --- ## Rollback Each script has automatic rollback on failure: - `00` — No rollback needed (legacy stays running until `02`) - `01` — Removes `operator-docker`, restores Nginx and certs, restarts legacy - `02` — Stops new WireGuard, restores `wg0.conf`, restarts legacy Manual rollback if needed: ```bash # Restore SSL certificates sudo cp -r ~/.wg-migration/letsencrypt/. /etc/letsencrypt/ # Restore Nginx sudo cp -r ~/.wg-migration/nginx/sites-available/. /etc/nginx/sites-available/ sudo cp -r ~/.wg-migration/nginx/sites-enabled/. /etc/nginx/sites-enabled/ sudo systemctl restart nginx # Remove operator-docker rm -rf ~/operator-docker # Restart legacy stack LEGACY_DIR=$(cat ~/.wg-migration/legacy_compose_dir) cd "$LEGACY_DIR" && docker compose up -d ``` WireGuard identity and peers are never modified in the legacy stack — they remain intact. --- ## Backup location All backups are stored in `~/.wg-migration/`: | File | Content | | :--- | :------ | | `private_key` | WireGuard private key (deleted after `02`) | | `public_key` | WireGuard public key | | `wg0-legacy.conf` | Full peer list | | `wg0-legacy.conf.original` | Unmodified copy | | `legacy.env` | Legacy stack `.env` | | `legacy_compose_dir` | Path to legacy stack | | `nginx/` | Nginx sites and config | | `letsencrypt/` | SSL certificates | | `ufw-snapshot.txt` | UFW rules | | `network_info` | IPv4/IPv6 detection result | | `ssh_pubkey` | SSH public key for repo access | | `migration.log` | Full log of all steps | --- ## Notes - Existing VPN clients reconnect automatically after `02` completes — no config changes needed. - The private key is destroyed from disk after successful peer migration. - If port 80 is blocked externally, SSL certificate issuance will fail at step 01. Contact your VPS provider or use DNS challenge manually. - IPv6 is detected and enabled automatically. --- # Español Migración sin tiempo de inactividad desde el stack legacy WireGuard + Go API hacia operator-docker. Los clientes VPN existentes se reconectan automáticamente — no requieren ningún cambio de configuración. --- ## Cómo funciona ```text Antes de la migración Stack legacy (sp-env-wireguard-ipv6) ├── wireguard (linuxserver/wireguard) ├── wireguard-api (Go) └── nginx-certbot Después de la migración operator-docker ├── wireguard (misma identidad — misma clave pública) ├── operator-api (FastAPI) ├── marzban ├── hysteria2 └── mysql ``` La identidad WireGuard del servidor (clave privada → clave pública) se preserva. Todos los peers se migran vía la nueva API. Los clientes se reconectan sin cambios. --- ## Requisitos - Stack legacy corriendo (`docker ps` muestra `wireguard`) - Dominio con DNS apuntando a este servidor - Un subdominio por servicio (`api`, `legacy`, `cdn`, `news` o similar) - SSH key autorizada por Simplified Privacy (generada en el paso 00) - Puerto 80/TCP accesible externamente (requerido por Let's Encrypt) --- ## Pasos de migración | Script | Ejecutar como | Descripción | | :----- | :------------ | :---------- | | `00-migrate-root.sh` | root | Backup, apaga legacy, limpia sistema | | `01-migrate-user.sh` | usuario | Clona repo, instala operator-docker | | `02-migrate-peers.sh` | usuario | Inyecta identidad, migra peers | --- ## Uso Los scripts se pueden ejecutar desde cualquier directorio: ```bash sudo bash ~/migration/00-migrate-root.sh bash ~/migration/01-migrate-user.sh bash ~/migration/02-migrate-peers.sh ``` --- ## Paso 00 — Backup y limpieza Ejecutar como root: ```bash sudo bash 00-migrate-root.sh ``` Acciones: | Acción | Detalle | | :----- | :------ | | Detecta el contenedor WireGuard legacy | Por imagen o nombre | | Respalda clave privada y pública | Guardadas en `~/.wg-migration/` | | Respalda todos los peers | Desde `wg showconf wg0` | | Respalda Nginx y certificados SSL | `/etc/nginx` y `/etc/letsencrypt` completos | | Respalda reglas UFW | Solo snapshot | | Genera SSH key | Para acceso al repo | | Apaga el stack legacy | `docker compose down` | | Limpia Nginx | Elimina todos los sites para instalación limpia | | Verifica que el puerto 51820 esté libre | Falla si sigue en uso | Al finalizar, el script muestra la clave SSH pública. Envíala a Simplified Privacy antes de ejecutar el `01`. --- ## Paso 01 — Instalar operator-docker Una vez que Simplified Privacy autorice la SSH key, ejecutar como usuario Linux: ```bash bash 01-migrate-user.sh ``` Acciones: | Acción | Detalle | | :----- | :------ | | Valida que existan los backups | Falla si no se ejecutó el `00` | | Limpia instalación anterior fallida | Detecta `.env` corrupto, repo incompleto | | Clona el repo privado | Vía SSH | | Ejecuta `install.sh` en modo migración | WireGuard NO se inicia todavía | | Crea placeholder de `wg0.conf` | El `02` inyectará la clave privada real | | Restaura configs Nginx externos | Por ejemplo, vhosts del servidor de correo | > `MIGRATION_MODE=1` indica al instalador que omita el inicio de WireGuard. El script `02` lo inicia después de inyectar la identidad legacy. --- ## Paso 02 — Migrar identidad y peers ```bash bash 02-migrate-peers.sh ``` Acciones: | Acción | Detalle | | :----- | :------ | | Detiene WireGuard legacy | Vía `docker compose stop` en el directorio legacy | | Inyecta la clave privada legacy | En `wg0.conf` y keyfiles del servidor | | Inicia el nuevo WireGuard | Con la identidad legacy | | Verifica que la clave pública coincida | Falla y hace rollback si no coincide | | Verifica que la API responda | `GET /wireguard/peers` debe devolver 200 | | Migra todos los peers | `POST /wireguard/peers` por cada peer | | Destruye la clave privada del disco | `shred` o `rm` | --- ## Rollback Cada script tiene rollback automático en caso de fallo: - `00` — Sin rollback necesario (el legacy sigue corriendo hasta el `02`) - `01` — Elimina `operator-docker`, restaura Nginx y certs, reinicia legacy - `02` — Detiene el nuevo WireGuard, restaura `wg0.conf`, reinicia legacy Rollback manual si es necesario: ```bash # Restaurar certificados SSL sudo cp -r ~/.wg-migration/letsencrypt/. /etc/letsencrypt/ # Restaurar Nginx sudo cp -r ~/.wg-migration/nginx/sites-available/. /etc/nginx/sites-available/ sudo cp -r ~/.wg-migration/nginx/sites-enabled/. /etc/nginx/sites-enabled/ sudo systemctl restart nginx # Eliminar operator-docker rm -rf ~/operator-docker # Reiniciar stack legacy LEGACY_DIR=$(cat ~/.wg-migration/legacy_compose_dir) cd "$LEGACY_DIR" && docker compose up -d ``` La identidad WireGuard y los peers nunca se modifican en el stack legacy — permanecen intactos. --- ## Ubicación del backup Todos los backups se almacenan en `~/.wg-migration/`: | Archivo | Contenido | | :------ | :-------- | | `private_key` | Clave privada WireGuard (eliminada tras el `02`) | | `public_key` | Clave pública WireGuard | | `wg0-legacy.conf` | Lista completa de peers | | `wg0-legacy.conf.original` | Copia sin modificar | | `legacy.env` | `.env` del stack legacy | | `legacy_compose_dir` | Ruta al stack legacy | | `nginx/` | Sites y configuración de Nginx | | `letsencrypt/` | Certificados SSL | | `ufw-snapshot.txt` | Reglas UFW | | `network_info` | Resultado de detección IPv4/IPv6 | | `ssh_pubkey` | Clave SSH pública para acceso al repo | | `migration.log` | Log completo de todos los pasos | --- ## Notas - Los clientes VPN existentes se reconectan automáticamente al finalizar el `02` — no requieren cambios de configuración. - La clave privada se destruye del disco tras la migración exitosa de peers. - Si el puerto 80 está bloqueado externamente, la emisión de certificados SSL fallará en el paso 01. Contacta a tu proveedor VPS o usa DNS challenge manualmente. - IPv6 se detecta y habilita automáticamente.