Replica e Failover di un Ambiente Docker: Dal Container Proxmox al Cloud

Gestire un sito web su un server locale (on-premises) offre molti vantaggi in termini di controllo e personalizzazione, ma porta con sé un rischio importante: la continuità operativa.
Un server in casa o in ufficio non può garantire uptime del 100% — basta un blackout, un problema hardware o, come nel mio caso, la lontananza durante le vacanze, e il sito potrebbe restare offline per ore o giorni.

Per questo ho deciso di implementare una soluzione di Replica + Failover su Cloud, che permette di:

  • Replicare periodicamente i contenuti e il database di WordPress dal server locale al cloud
  • Eseguire un failover automatico (o semi-automatico) nel caso il server locale sia offline
  • Avere comunque la possibilità di gestire e aggiornare i servizi anche da remoto

Come funziona la mia soluzione?

  1. Replica Locale → Cloud
    • Ogni notte vengono eseguiti script di backup dei webserver e del database WordPress
    • I file vengono trasferiti via scp al server cloud con autenticazione tramite SSH key
  2. Restore sul Cloud
    • Al mattino, cronjob sul server cloud eseguono gli script di restore: i container vengono aggiornati e il database ripristinato
  3. Failover
    • Se il server locale è online, Cloudflare bilancia il traffico
    • Se il server locale è offline, il traffico passa al server cloud senza interventi manuali
  4. Gestione Cloud
    • Portainer per gestire Docker
    • Fail2Ban e hardening base per la sicurezza

Quando il container locale è UP:

✅ Gestisce le richieste normalmente

Quando il container locale è DOWN:

✅ Cloudflare indirizza le richieste alla VM cloud
✅ Il sito rimane online, i servizi continuano a funzionare

Tutorial:

OnPremise:

a) Backup dei Volumi Docker dei Webserver

Per ogni servizio dockerizzato (come NGINX o altri), creo un backup dei volumi usando un container Alpine temporaneo.
Alla fine, trasferisco tutto al cloud tramite SCP.

Esempio — WebServer di esempio:

#!/bin/bash

DATE=$(date +"%Y%m%d-%H%M")
BACKUP_DIR="/root/backups"
CLOUD_USER="inserisci_username"
CLOUD_IP="inserisci_ip_cloud"
SSH_KEY="inserisci_chiave_ssh"
REMOTE_PATH="/home/inserisci_username/webserver_backup_${DATE}.tar.gz"

mkdir -p ${BACKUP_DIR}
cd ${BACKUP_DIR}

# Backup volumi Docker
docker run --rm -v inserisci_volume_id1:/volume -v $(pwd):/backup alpine sh -c "cd /volume && tar czf /backup/nginx_backup.tar.gz ."
docker run --rm -v inserisci_volume_id2:/volume -v $(pwd):/backup alpine sh -c "cd /volume && tar czf /backup/html_backup.tar.gz ."

# Crea archivio unico e trasferisce al cloud
tar czf webserver_backup_${DATE}.tar.gz nginx_backup.tar.gz html_backup.tar.gz
scp -i ${SSH_KEY} webserver_backup_${DATE}.tar.gz ${CLOUD_USER}@${CLOUD_IP}:${REMOTE_PATH}

rm -f nginx_backup.tar.gz html_backup.tar.gz

b) Dump del Database WordPress

Eseguo un dump SQL dal container MySQL/MariaDB e lo trasferisco al cloud:

#!/bin/bash

DATE=$(date +"%Y%m%d-%H%M")
LOCAL_DUMP="/root/wordpress_db_backup_${DATE}.sql"
CLOUD_USER="inserisci_username"
CLOUD_IP="inserisci_ip_cloud"
SSH_KEY="inserisci_chiave_ssh"
DB_USER="inserisci_db_user"
DB_PASS="inserisci_db_password"
DB_NAME="inserisci_db_name"

docker exec inserisci_nome_container_db mysqldump --no-tablespaces -u ${DB_USER} -p"${DB_PASS}" ${DB_NAME} > ${LOCAL_DUMP}

scp -i ${SSH_KEY} ${LOCAL_DUMP} ${CLOUD_USER}@${CLOUD_IP}:/home/inserisci_username/

c) Automazione con Cronjob

Esempio di crontab:

0 3 * * * /root/scripts/replica_webserver.sh
0 4 * * * /root/scripts/replica_wordpress.sh

Cloud:

a) Ripristino dei Volumi dei Webserver

Sul cloud, scompatto i backup ricevuti e li ripristino sui volumi Docker:

#!/bin/bash

BACKUP_FILE=$(ls -t /home/inserisci_username/webserver_backup_*.tar.gz | head -n 1)
RESTORE_DIR="/root/restore_temp"

mkdir -p ${RESTORE_DIR}
tar xzf ${BACKUP_FILE} -C ${RESTORE_DIR}

docker run --rm -v inserisci_volume_id1:/data -v ${RESTORE_DIR}:/backup alpine sh -c "rm -rf /data/* && tar xzf /backup/nginx_backup.tar.gz -C /data"
docker run --rm -v inserisci_volume_id2:/data -v ${RESTORE_DIR}:/backup alpine sh -c "rm -rf /data/* && tar xzf /backup/html_backup.tar.gz -C /data"

rm -rf ${RESTORE_DIR}

b) Ripristino del Database WordPress

#!/bin/bash

DUMP_PATH=$(ls -t /home/inserisci_username/wordpress_db_backup_*.sql | head -n 1)
CONTAINER_DB="inserisci_nome_container_db"
DB_USER="inserisci_db_user"
DB_PASS="inserisci_db_password"
DB_NAME="inserisci_db_name"

docker cp "$DUMP_PATH" "$CONTAINER_DB:/wordpress_db_backup.sql"

docker exec -i "$CONTAINER_DB" mysql -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "
SET FOREIGN_KEY_CHECKS=0;
DROP TABLE IF EXISTS wp_commentmeta, wp_comments, wp_links, wp_options, wp_postmeta, wp_posts, wp_term_relationships, wp_terms, wp_term_taxonomy, wp_usermeta, wp_users;
SET FOREIGN_KEY_CHECKS=1;"

docker exec -i "$CONTAINER_DB" sh -c "mysql -u $DB_USER -p\"$DB_PASS\" $DB_NAME < /wordpress_db_backup.sql"

c) Automazione con Cronjob sul Cloud

Esempio di crontab:

0 5 * * * /root/scripts/restore_webserver.sh
0 6 * * * /root/scripts/restore_wordpress.sh

Cloudflare:

Su entrambe le macchine (Proxmox e Cloud), attivo il tunnel Cloudflare:

cloudflared service install inserisci_token_tunnel

Cloudflare gestisce automaticamente il traffico in base alla disponibilità del container on-premises o della VM cloud.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *