| 00-migrate-root.sh | ||
| 01-migrate-user.sh | ||
| readme.md | ||
migration-guide
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
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 psshowswireguard) - Domain with DNS pointing to this server
- One subdomain per service (
api,legacy,cdn,newsor 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:
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:
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 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=1tells the installer to skip starting WireGuard. The02script starts it after injecting the legacy identity.
Step 02 — Migrate identity and peers
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 until02)01— Removesoperator-docker, restores Nginx and certs, restarts legacy02— Stops new WireGuard, restoreswg0.conf, restarts legacy
Manual rollback if needed:
# 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
02completes — 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
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 psmuestrawireguard) - Dominio con DNS apuntando a este servidor
- Un subdominio por servicio (
api,legacy,cdn,newso 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:
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:
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 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=1indica al instalador que omita el inicio de WireGuard. El script02lo inicia después de inyectar la identidad legacy.
Paso 02 — Migrar identidad y peers
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 el02)01— Eliminaoperator-docker, restaura Nginx y certs, reinicia legacy02— Detiene el nuevo WireGuard, restaurawg0.conf, reinicia legacy
Rollback manual si es necesario:
# 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.