~/ziphub — zsh
ZipHub·~/catalog~/articles~/feed~/sellers~/hire
auth login
[article]category · network

Come sono passato da cinque VPS a un unico server dedicato con Proxmox

@dignezzz · author17 min read2026-05-05free

TL;DR: TL;DR: Infrastruttura frammentata da cinque VPS presso tre provider → un server dedicato Ryzen 7 9700X / 64GB ECC / mirror ZFS 2x NVMe, sopra Proxmox VE. All'interno — VM/LXC per ruolo, mesh NetBird invece del port forwarding, nodo di uscita su un VPS separato per aggirare blocchi e terminazione TLS, PBS per i backup. Soldi in attivo, controllo in attivo, nervi in attivo. In questo articolo — perché, come e dove ho inciampato lungo la strada, in modo che tu non inciampi.

Come sono passato da cinque VPS a un unico server dedicato con Proxmox e ho smesso di alimentare gli hoster

TL;DR: Infrastruttura frammentata da cinque VPS presso tre provider → un server dedicato Ryzen 7 9700X / 64GB ECC / mirror ZFS 2x NVMe, sopra Proxmox VE. All'interno — VM/LXC per ruolo, mesh NetBird invece del port forwarding, nodo di uscita su un VPS separato per aggirare blocchi e terminazione TLS, PBS per i backup. Soldi in attivo, controllo in attivo, nervi in attivo. In questo articolo — perché, come e dove ho inciampato lungo la strada, in modo che tu non inciampi.

Perché ho intrapreso tutto questo

Verso la fine dell'anno scorso, mi sono ritrovato a pagare per cinque VPS differenti presso tre provider. Uno — per il forum Discourse, il secondo — per un forum legacy su PHP con MySQL, il terzo — per il billing e i bot Telegram, il quarto — VPN/proxy, il quinto — statiche e vari piccoli tool. E da qualche parte lì giravano anche n8n e Vaultwarden, e un paio di Uptime Kuma che si monitoravano reciprocamente (come altrimenti).

Cosa c'era di sbagliato:

  • Soldi. In totale usciva circa lo stesso importo che costa un server dedicato decente con caratteristiche simili (ma lì era condiviso, qui invece è dedicato).
  • Nessuna isolazione. Se la memoria di un bot di un cliente inizia a fuoriuscire, il mio forum inizia a rallentare. Sulla stessa macchina. Fantastico.
  • Backup — attraverso il culo. Ogni VPS aveva il suo rsync-cron su S3, retention diversi ovunque, nessuna incrementalità, ripristinare — un'impresa.
  • Rete come un insalata. SSH attraverso porte diverse, inoltrate tramite Cloudflare Tunnels, tramite WireGuard sollevato manualmente tra due VPS, con configurazioni in tre posti. Ogni volta che aggiungevo una nuova macchina, ci voleva un giorno per l'integrazione.
  • Apocalisse degli aggiornamenti. Su cinque diverse Ubuntu/Debian con versioni e pacchetti diversi, gli aggiornamenti andavano fatti manualmente e mai contemporaneamente. Una volta ogni sei mesi, ero eroicamente eroico nel completare la missione "aggiorna tutto, non rompere nulla".
  • CPU e RAM inutilizzate. Ogni VPS era prenotata "al picco", e in media veniva utilizzata al 15-20%. Soldi buttati nel vento.

In generale — un caso classico in cui l'infrastruttura è cresciuta secondo il principio "oh, serve un altro servizio — compro una VPS". Era ora di consolidare tutto questo.

Cosa ho scelto e perché

Hardware

Ho preso un server dedicato:

  • CPU: AMD Ryzen 7 9700X (8 core / 16 thread, Zen 5)
  • RAM: 64 GB DDR5 ECC 5200 MHz
  • Dischi: 2× NVMe 512 GB enterprise → mirror ZFS
  • Rete: 1 Gbps unmetered
  • Prezzo: circa come due VPS medie presso lo stesso OVH

Hypervisor

Proxmox VE 9.x. Ho considerato le alternative, ma brevemente:

  • Docker nudo — nessuna isolazione, nessuno snapshot normale, backup solo tramite compose, disco — un unico calderone.
  • VMware ESXi — non più gratuito, la licenza Broadcom è fantastica, grazie.
  • XCP-ng — ok, ma personalmente conosco Proxmox a memoria e la sua community è più viva.
  • Kubernetes — no, sono una persona sola, non ho bisogno di costruire un aereo per andare al negozio.

Proxmox mi dà tutto ciò di cui ho bisogno: VM KVM per tutto ciò che richiede isolazione (Docker, kernel specifici, diverse distribuzioni); container LXC dove si possono risparmiare risorse (DB, monitoraggio, piccoli servizi); PBS integrato per i backup; ZFS out-of-the-box; snapshot; live-migrazione (se mai apparisse un secondo server dedicato); interfaccia web su cui si può cliccare quando non si ha voglia di scrivere nel terminale.

Architettura: schema generale

Prima mostrerò cosa è venuto fuori, poi spiegherò come ci sono arrivato.

La logica è questa:

  1. Sul server dedicato vive Proxmox. Gestisce l'IP pubblico Y.Y.Y.Y su vmbr0.
  2. All'interno è stato creato un secondo bridge vmbr1 con una rete privata 10.10.10.0/24. È un analogo di "LAN interna" — tutte le VM e gli LXC sono lì, verso l'esterno tramite NAT dall'host, non hanno porte pubbliche in entrata.
  3. Sull'host stesso girano solo tre cose: Caddy (reverse proxy interno), nftables (firewall) e NetBird (agente VPN). Nessun Docker sull'host, nessuna logica applicativa sull'host. L'host è una vacca sacra, il suo compito è essere un hypervisor e non cadere.
  4. Le VM sono divise per ruoli: una per il forum, una per i servizi in background e i bot, una per Dokploy con le applicazioni utente, ecc. Tra di loro c'è visibilità diretta tramite 10.10.10.x, verso l'esterno — solo tramite il Caddy dell'host.
  5. I container LXC — per tutto ciò che è "leggero": istanze Postgres di diverse versioni, Proxmox Backup Server, dashboard di monitoraggio. Anch'essi in vmbr1.
  6. Un nodo di uscita separato ("Peer Caddy") — è una piccola VPS presso un altro provider, in una rete adeguata per il mio pubblico. Su di esso gira Caddy, che termina TLS (Let's Encrypt) e fa proxy HTTP verso l'interno del server dedicato tramite la mesh NetBird. Il DNS di tutti i domini pubblici punta a questa VPS, non al server dedicato.
  7. La mesh NetBird collega il server dedicato, il nodo di uscita e il mio laptop (e anche un paio di vecchi server da cui non tutto si è ancora spostato). È WireGuard sopra l'autenticazione SSO, senza porte aperte verso l'esterno.

Perché una tale isolazione tramite nodo di uscita è un discorso a parte, a cui tornerò ancora.

Installazione Proxmox: come l'ho configurato

Ho ordinato il server dedicato, al primo avvio ho installato Proxmox tramite modalità rescue/KVM (OVH ha entrambe — per me è più comodo KVM, si vede tutto il processo). Durante l'installazione:

  • ZFS RAID1 su entrambi gli NVMe (ashift=12, compression=lz4 abilitata subito)
  • partizionamento di default, Proxmox fa da sé rpool/ROOT, rpool/data, swap

Successivamente — pulizia di base dopo l'installazione. È un must, senza di esso Proxmox darà errori di sottoscrizione e non funzionerà in modo ottimale.

bash
1# 1. Rimuovere il repository enterprise (nessuna sottoscrizione)
2sed -i 's/^deb/#deb/' /etc/apt/sources.list.d/pve-enterprise.list
3echo "deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription" \
4  > /etc/apt/sources.list.d/pve-no-subscription.list
5apt update && apt full-upgrade -y
6
7# 2. Rimuovere la finestra di avviso "No valid subscription"
8sed -Ezi.bak "s/(Ext\.Msg\.show\(\{[^}]+?title: gettext\('No valid sub)/void\(\{ \/\/\1/g" \
9  /usr/share/javascript/proxmox-widget-toolkit/proxmoxlib.js
10systemctl restart pveproxy
11
12# 3. Hostname / timezone
13hostnamectl set-hostname dedik-waw
14timedatectl set-timezone Europe/Warsaw

Indurimento SSH

Subito. Non "dopo". Il dopo non arriva mai.

bash
1cat > /etc/ssh/sshd_config.d/hardening.conf << 'EOF'
2Port 22222
3PermitRootLogin prohibit-password
4PasswordAuthentication no
5MaxAuthTries 3
6ClientAliveInterval 300
7ClientAliveCountMax 2
8EOF
9
10mkdir -p ~/.ssh
11echo "ssh-ed25519 AAAA... your-key" >> ~/.ssh/authorized_keys
12chmod 600 ~/.ssh/authorized_keys
13systemctl restart sshd

Ho chiuso la porta 22 nel firewall, lasciando solo quella non standard. Questa non è sicurezza tramite oscurità, ma riduzione del rumore di fondo nei log — sulla porta 22 nelle prime ore arrivano 50 mila tentativi di brute force, nei log non si vede nulla. Sulla 22222 — silenzio e si possono monitorare davvero le anomalie.

ZFS — configurazione per NVMe e 64GB RAM

ZFS per impostazione predefinita vuole consumare metà della RAM per ARC. Questo va bene per un file server e è assolutamente sconsigliato per un hypervisor, dove la memoria serve alle VM. Riduciamo ARC a un ragionevole 16 GB:

bash
1cat > /etc/modprobe.d/zfs.conf << 'EOF'
2options zfs zfs_arc_max=17179869184
3options zfs zfs_arc_min=4294967296
4EOF
5update-initramfs -u

Distribuzione della mia memoria:

  • ~16 GB — ZFS ARC
  • ~44 GB — VM/LXC
  • ~4 GB — sistema, buffer, overhead

Impostazioni utili del pool stesso:

bash
1zfs set compression=lz4 rpool
2zfs set atime=off rpool
3zfs set xattr=sa rpool
4zfs set dnodesize=auto rpool
5zfs set relatime=on rpool
6
7zfs set recordsize=64K rpool/data    # per dischi VM
8zfs set sync=standard rpool/data
9
10zpool set autotrim=on rpool          # critico per NVMe

compression=lz4 risparmia il 20-30% di spazio quasi gratuitamente in termini di CPU. recordsize=64K per i dispositivi a blocchi delle VM è il miglior compromesso tra prestazioni e amplificazione della scrittura.

Rete interna e firewall

Ho creato un secondo bridge per la rete privata con NAT verso l'esterno:

1auto vmbr1
2iface vmbr1 inet static
3    address 10.10.10.1/24
4    bridge-ports none
5    bridge-stp off
6    bridge-fd 0
7    post-up   echo 1 > /proc/sys/net/ipv4/ip_forward
8    post-up   iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -o vmbr0 -j MASQUERADE
9    post-down iptables -t nat -D POSTROUTING -s 10.10.10.0/24 -o vmbr0 -j MASQUERADE

Ora ogni VM/LXC nel bridge vmbr1 riceve un indirizzo locale 10.10.10.x e esce su Internet tramite l'host, ma dall'esterno non è visibile.

nftables con policy drop. È aperto solo ciò che deve esserlo, il resto viene silenziosamente scartato. Set minimo:

nft
1table inet filter {
2    chain input {
3        type filter hook input priority 0; policy drop;
4
5        iif lo accept
6        ct state established,related accept
7        ip protocol icmp accept
8        ip6 nexthdr icmpv6 accept
9
10        tcp dport 22222 accept           # SSH
11        tcp dport 8006 accept            # UI Proxmox (solo da NetBird, vedi sotto)
12        tcp dport { 80, 443, 8080 } accept   # Caddy
13        udp dport 29899 accept           # NetBird
14
15        iif vmbr1 accept                 # rete interna — tutto permesso
16        iif wt0 accept                   # interfaccia NetBird — anch'essa fidata
17    }
18
19    chain forward {
20        type filter hook forward priority 0; policy drop;
21        iif vmbr1 oif vmbr0 accept
22        ct state established,related accept
23    }
24}

L'accesso all'UI di Proxmox (porta 8006) è fisicamente chiuso da Internet tramite CF/firewall e vi si accede solo tramite NetBird. Tramite IP pubblico l'interfaccia non risponde affatto. Lo stesso vale per l'UI di PBS, le dashboard e tutto ciò che è amministrativo — solo tramite la mesh. Dall'esterno sono aperte solo le porte pubbliche reali dei servizi.

NetBird mesh: perché non WireGuard classico

Ho usato WireGuard normale per molto tempo, ed era ok, finché i server non sono diventati più di tre. Dopo — gestire le configurazioni è diventato doloroso: ogni aggiunta di un peer si trasforma in "aggiorna la configurazione su tutti i nodi, non dimenticare allowed_ips, riavvia il demone, controlla di non aver rotto il routing verso un altro peer".

NetBird — è un piano di gestione sopra WireGuard. Tecnicamente sotto il cofano hai sempre lo stesso wg, ma:

  • i nodi si trovano tra loro tramite un server di segnalazione, NAT-traversal automatico
  • autenticazione tramite SSO (per me — tramite Authentik), senza condivisione di chiavi
  • l'accesso è gestito nell'interfaccia web tramite policy, si possono creare gruppi di macchine e regole tra di loro
  • proxy SSH integrato: si può accedere tramite ssh user@machine.netbird.cloud e ottenere autenticazione SSO (con approvazione in Authentik). Sulla nodo non è nemmeno necessario aprire la porta 22 verso l'esterno.

Ho installato l'agente NetBird:

  • sull'host Proxmox
  • su ogni VM che deve essere visibile dall'amministratore o da altre VM
  • sul nodo di uscita
  • sul mio laptop

Il risultato è che accedo da laptop a qualsiasi macchina con un solo comando, senza port forwarding, senza falle nel firewall, senza bastion-host aggiuntivi. E non c'è SSH aperto su nessuna delle VM private — sono tutte solo in vmbr1 più la mesh wt0.

VM vs container: come ho risolto per me stesso

Una regola semplice che funziona quasi sempre:

QuandoCosa scegliere
Carichi DockerVM (Docker in LXC può essere capriccioso, specialmente con overlay2)
Database senza DockerLXC (più leggero, più veloce, accesso diretto al disco tramite ZFS)
Servizi di sistema (PBS, monitoraggio, piccoli tool)LXC
Applicazioni che necessitano di un proprio kernel / trucchi di reteVM
Nodi VPN (WG, AmneziaWG)LXC (minimo overhead)

Alla fine, ho ottenuto circa questo:

VM (KVM):

  • forum — Discourse nel container launcher standard. Docker all'interno.
  • services — un sacco di piccole cose: bot webhook, bot AI, pannello billing, Vaultwarden, Uptime Kuma. Tutto in Docker compose, per cartella per servizio.
  • legacy — vecchio forum PHP (IPS) con PHP-FPM nativo e Caddy su VM. Non volevo impacchettarlo in Docker — troppo legacy, più facile lasciarlo com'era.
  • dokploy — Docker Swarm + Dokploy per applicazioni utente (Next.js, Postgres, Redis), deploy tramite Git.

LXC:

  • pbs — Proxmox Backup Server (vedi sotto).
  • pg16, pg17, pg18 — tre Postgres separati di diverse versioni maggiori. Nota: diverse applicazioni richiedono versioni maggiori diverse, e non voglio doverle gestire tutte insieme.
  • dashboards — un container con Homarr (pagina di avvio), Uptime Kuma e Beszel hub. Tutti e tre nello stesso compose, perché sono logicamente correlati — osservare.

Ogni VM riceve un IP statico in 10.10.10.x (per intervalli, così è più facile cercare), 2-8 core vCPU e 2-8 GB di RAM a seconda del carico. I core possono essere sovraprovisionati in sicurezza — in totale ho assegnato più core alle VM di quanti ne abbia fisicamente, e funziona perfettamente, finché nessuno non raggiunge contemporaneamente il limite della CPU.

Reverse proxy: Caddy a due piani

All'interno di Proxmox ho installato Caddy sull'host, non in una VM. Perché? Perché deve ascoltare le porte pubbliche del server dedicato e instradare in base all'Host-header alla VM corretta, e creare una VM separata con port forwarding per questo sarebbe uno strato aggiuntivo inutile. Caddy è leggero, scritto in Go, unit systemd, configurazione in un unico file.

Questo Caddy host ascolta solo la porta 8080 HTTP e fa proxy verso i backend su 10.10.10.x. Non ha TLS su di esso.

caddy
1:8080 {
2    @forum host forum.example.com www.forum.example.com
3    handle @forum {
4        reverse_proxy http://10.10.10.111:80 {
5            header_up X-Forwarded-Proto https
6            header_up X-Real-IP {header.X-Real-IP}
7            header_up Host {host}
8        }
9    }
10
11    @panel host panel.example.com api.panel.example.com
12    handle @panel {
13        reverse_proxy http://10.10.10.111:8081 {
14            header_up X-Forwarded-Proto https
15            header_up X-Real-IP {header.X-Real-IP}
16            header_up Host {host}
17        }
18    }
19
20    @dokploy host app1.example.com app2.example.com
21    handle @dokploy {
22        reverse_proxy http://10.10.10.114:80 {
23            header_up X-Forwarded-Proto https
24            header_up X-Real-IP {header.X-Real-IP}
25            header_up Host {host}
26        }
27    }
28}

E la terminazione TLS e i certificati — su un nodo di uscita separato, in Docker, con lo stesso principio:

caddy
1{
2    email me@example.com
3}
4
5forum.example.com {
6    reverse_proxy http://100.x.y.z:8080 {
7        header_up X-Forwarded-Proto {scheme}
8        header_up X-Forwarded-For {remote_host}
9        header_up X-Real-IP {remote_host}
10        header_up Host {host}
11    }
12}

100.x.y.z — questo è l'indirizzo NetBird del server dedicato. La richiesta arriva al nodo di uscita via HTTPS, viene decifrata, passa nella mesh NetBird in HTTP verso il server dedicato, lì il Caddy di Proxmox fa il matching per Host e instrada alla VM interna. Tra il nodo di uscita e il server dedicato, HTTP è per design — ci fidiamo della mesh, non c'è traffico esterno qui.

Perché il nodo di uscita

Diverse ragioni:

  1. Aggirare i blocchi. Alcune sottoreti OVH in Russia sono bloccate. Il nodo di uscita si trova presso un provider il cui IP non è bloccato. Il DNS dei domini pubblici punta lì.
  2. Terminazione TLS in un unico posto. Solo esso emette i certificati, solo il suo IP è nelle challenge di Let's Encrypt. Questo semplifica tutti i controlli DNS e permette al server dedicato di essere completamente invisibile da Internet sulle porte 80/443.
  3. Strato aggiuntivo di isolazione. Se qualcuno inizia un DDoS, DDoS-a il nodo di uscita, non il server dedicato. Sul nodo di uscita ho dati minimi, ricrearlo — 10 minuti.
  4. Separazione del frontend pubblico dal backend. Posso tranquillamente eseguire aggiornamenti di Caddy / sperimentare sul server dedicato, mentre l'interfaccia reale verso Internet è separata e stabile.

Unico svantaggio: si aggiungono circa 5-15 ms a ogni richiesta a causa di un hop aggiuntivo. Per il web è impercettibile.

Inoltre, per alcuni servizi, c'è un Caddy diretto sull'host sulle porte 80/443 senza il nodo di uscita — per quei domini che non ho bisogno di inoltrare attraverso il punto di uscita (ad esempio, endpoint di stato, monitoraggio, servizi dove il DNS punta già al server dedicato). Questo funziona in parallelo: Caddy sull'host ascolta sia :8080 (interno dal nodo di uscita), sia :80/:443 (diretto da Internet), i percorsi sono diversi.

Migrazione: come ho traslocato senza lacrime e quasi senza downtime

Questa è stata la fase più spaventosa. Cinque server, circa trenta servizi, un forum in produzione con utenti attivi, un sistema di billing con abbonamenti attivi, database che in nessun caso potevano essere persi.

Strategia — migrazione di un servizio alla volta, in ordine "dal meno critico al più critico":

  1. Prima sono stati spostati piccoli tool e siti statici (se qualcosa va storto — nessuno se ne accorgerà).
  2. Poi bot e servizi in background (anch'essi sopportano un minuto di downtime).
  3. Poi database (con ripristino preventivamente verificato).
  4. Poi applicazioni che dipendono da questi DB.
  5. Alla fine — il forum principale con un lungo ciclo finale di sincronizzazione e cambio DNS.

Canale di migrazione

All'inizio ho semplicemente attivato NetBird sui vecchi server. Questo ha risolto subito due cose: posso accedere in sicurezza tramite SSH alle reti interne, e rsync passa su WireGuard tramite NetBird, senza esporre i dati su Internet aperto.

Il comando di battaglia per ogni servizio era più o meno questo:

bash
1# Dal nuovo server dedicato, tramite IP NetBird del vecchio server:
2rsync -avzP --delete \
3  -e "ssh -p 5322" \
4  root@100.76.108.210:/var/discourse/shared/standalone/ \
5  /target/discourse/shared/standalone/

Per i database — dump + restore, non copia di file. Non copiate mai file Postgres/MySQL "a caldo", è un biglietto per l'aldilà.

bash
1# Sul vecchio
2docker exec -it shm-vsem-mysql mysqldump -u root -p shm-vsem | \
3  gzip > /tmp/shm-vsem.sql.gz
4
5# Sul nuovo, tramite NetBird
6scp -P 5322 root@100.76.108.210:/tmp/shm-vsem.sql.gz /tmp/
7zcat /tmp/shm-vsem.sql.gz | docker exec -i shm-vsem-mysql mysql -u root -p shm-vsem

Per Discourse — discourse backup / discourse restore nativi tramite ./launcher enter app. All'interno raccoglie correttamente il dump di Postgres + upload + configurazioni, e ripristina esattamente allo stesso modo.

Cambio DNS

Dopo aver avviato il servizio nella nuova posizione e verificato che funzionasse con l'indirizzo interno — ho avviato entrambe le installazioni in parallelo per 5-15 minuti, per osservare la sincronizzazione dei dati, e poi ho cambiato il DNS sul nuovo server. Avevo precedentemente ridotto il TTL delle voci a 60-300 secondi un giorno prima del cambio.

Per Discourse, dove gli utenti attivi postano continuamente, ho fatto così:

  1. Ho configurato tutto nella nuova posizione.
  2. Ho eseguito la validazione (login, posting, upload di file su S3, ricerca).
  3. Sull'installazione vecchia ho attivato read_only_mode (Discourse lo supporta nativamente).
  4. Ho fatto un rsync finale degli upload + un dump finale del DB.
  5. Ho avviato sul nuovo, disattivato read-only.
  6. Ho cambiato il DNS.
  7. Sulla vecchia non ho toccato nulla per un'altra settimana — in caso di "e se poi".

Downtime effettivo per gli utenti — circa due minuti per servizio.

Sorprese lungo la strada

  • Permessi durante pct restore. LXC sotto unprivileged 1 mappa gli UID con uno spostamento di 100000. Se sul vecchio server i tuoi file sono sotto UID 1000, sul nuovo saranno sotto UID 101000, e l'applicazione non li vedrà. Si risolve o con chown dopo il restore, o con --unprivileged 0 se si comprendono i rischi.
  • Docker ipv6 nelle VM OVH a volte si attivava male — ho risolto disattivando ipv6 nel demone Docker ("ipv6": false).
  • Ora sulle VM. Diverse volte ho riscontrato una discrepanza nell'ora di sistema tra host e VM, che rompeva TLS e firme. Rimedio — systemd-timesyncd o chrony su ogni VM, e host.use-time nell'agente Proxmox.
  • Migrazione di Discourse tra due versioni. Se sul vecchio server Discourse è più recente di quello che hai installato sul nuovo — il restore fallirà. La versione deve coincidere o essere superiore sulla nuova installazione.
  • Registry delle immagini per Dokploy. Quando ho spostato i metadati di Dokploy tramite il dump dokploy-postgres, nel DB sono rimasti riferimenti al vecchio registry locale sull'IP vecchio. Le applicazioni, tentando di avviarsi, cercavano in 100.76.117.115:5000 e fallivano con No such image. Soluzione — ricompilare ogni applicazione nell'interfaccia utente di Dokploy; la compilazione locale inserisce l'immagine già sul nuovo server.

Backup: PBS all'interno dello stesso server dedicato + offsite

Qui c'è stata un'apposita discussione filosofica con me stesso: fare il backup sullo stesso hardware o no. Risposta: sia sì che no.

Livello 1 — snapshot ZFS sul pool stesso. Sono quasi gratuiti (copy-on-write), vengono creati istantaneamente, ripristinati istantaneamente. Mantengo snapshot automatici di rpool/data ogni 15 minuti con retention di 24 ore, più snapshot giornalieri con retention di una settimana. Viene usato zfs-auto-snapshot. Protezione da "oh, ho appena cancellato il DB di produzione":

bash
1apt install zfs-auto-snapshot
2# Poi fa da sé tramite cron creando frequent/hourly/daily/weekly/monthly

Livello 2 — Proxmox Backup Server in un LXC separato sullo stesso host. Questi sono backup incremental completi di VM/LXC tramite vzdump, deduplicati a livello di chunk. PBS memorizza gli snapshot in un dataset ZFS separato, li vede come repository, ogni VM ha la sua catena di incrementali.

Configurazione in Proxmox: Datacenter → Backup → Add. Programmazione: ogni giorno alle 4 del mattino, retention keep-daily=7 keep-weekly=4 keep-monthly=3. Tutto questo tramite mouse.

Posizionare PBS in LXC sullo stesso host è un compromesso. Pro: non serve hardware separato, il backup avviene tramite localhost, la velocità è come quella di un SSD locale, retention/dedup funziona perfettamente. Contro: se muore l'intero server dedicato, muoiono anche i backup. Per questo c'è...

Livello 3 — sincronizzazione del repository PBS in S3 offsite. PBS supporta il sync job in uno storage compatibile con S3. Ogni notte copio gli snapshot su un bucket separato nello S3 di Selectel (puoi usare qualsiasi — Backblaze, Wasabi, Cloudflare R2). La retention lì è di due settimane, perché non serve di più: per la conservazione a lungo termine c'è PBS locale, e offsite — è un'assicurazione contro il "tutto il data center è andato a fuoco".

Livello 4 — dati delle applicazioni separatamente. Discourse fa da sé i propri backup e li carica su S3 (questa è una sua funzionalità nativa). Quindi, anche se PBS e l'intero server dedicato dovessero sparire, avrò ancora backup consistenti di Discourse nel loro cloud.

bash
1# Ripristino di un'intera VM da PBS — letteralmente un comando:
2pvesm list backup-pbs    # vedere cosa c'è
3qmrestore backup-pbs:backup/vzdump-qemu-201-2026_04_06-04_00_03.vma.zst 999 \
4  --storage local-zfs
5# e dopo un minuto hai una copia della VM del forum sul momento delle 4 del mattino con VMID 999.

Questo è un punto critico: i backup che non hai provato a ripristinare — non sono backup. Una volta al mese faccio un restore di test di una VM casuale su un VMID vuoto, verifico che si avvii, che l'applicazione al suo interno funzioni, e la cancello. Noioso, ma una volta proprio così ho scoperto che uno dei cron scriveva in /tmp/..., che durante il backup veniva saltato, e l'applicazione dopo il restore richiedeva un passaggio manuale.

Monitoraggio

Non mi piace raccogliere conglomerati come Prometheus + Grafana + Alertmanager + Loki quando ho 15 macchine. Quindi mi sono fermato a tre strumenti leggeri in un unico LXC:

  • Beszel — raccoglie metriche dagli agenti su ogni VM (CPU, RAM, dischi, interfacce di rete, container Docker). L'hub vive in LXC, gli agenti — su ogni VM/LXC tramite unit systemd. L'autenticazione di Beszel è propria, tramite PocketBase, che a volte è scomodo (vedi sotto per le insidie), ma nel complesso funziona.
  • Uptime Kuma — controlli via HTTP/HTTPS/Ping/TCP. Ci ho collegato tutto il pubblico (domini), tutti i servizi interni (tramite NetBird), e i ping su tutti i nodi della mesh. Alert — in Telegram.
  • Homarr — pagina di avvio con link a tutte le interfacce amministrative. Per non ricordare su quale porta si trova l'UI di PBS, su quale Dokploy, su quale Vaultwarden. Apro semplicemente Homarr e clicco.

Tutti e tre nello stesso Docker compose, nello stesso LXC, accessibili solo tramite NetBird.

Insidia con Beszel, affinché tu non ci inciampi: Beszel ha due tabelle utente in PocketBase — _superusers (per CLI/API) e users (per l'interfaccia web). Se resettate la password tramite CLI superuser upsert — resettate solo _superusers, e nell'UI accedete tramite users e la password non funziona. Si risolve con una richiesta PATCH a /api/collections/users/records/<id> tramite API REST.

Cosa ho ottenuto alla fine

Dopo circa tre settimane di migrazione, quando si sono stabilizzati gli ultimi servizi, ho tirato le somme:

ParametroPrimaDopo
Server / fatture5 presso 3 provider1 server dedicato + 1 micro-VPS
Pagamenti al mese~$X~$X/2
Risorse libere"sembra sufficiente"8 vCPU e 30 GB di RAM in riserva
Backuprsync-cron in S3 su ogni VPSPBS + offsite + snapshot ZFS
Ripristino"beh, un giorno o l'altro"2-5 minuti per VM da PBS
Accesso SSH5 porte e chiavi diverseuna mesh NetBird con SSO
Isolazione servizicalderone comuneognuno nella propria VM/LXC
Snapshot prima dell'aggiornamento"prega"qm snapshot 201 pre-update
Interfaccia web per compiti di routinequale interfaccia webUI Proxmox

La cosa principale che mi ha dato emotivamente — ho smesso di aver paura di toccare qualcosa. Ogni azione pericolosa (aggiornamento, migrazione, esperimento) ora inizia con uno snapshot e finisce o con un commit, o con un rollback in 30 secondi. Ho iniziato a provare più spesso cose nuove, perché il costo dell'errore è diminuito di un ordine di grandezza.

Checklist, se volete ripetere

Se ti ritrovi con gli stessi sintomi miei — ecco una breve checklist, in quale ordine ha senso procedere:

  1. Calcola quanto paghi per tutte le VPS insieme, e confrontalo con il prezzo dei server dedicati di OVH/Hetzner/LeaseWeb. Ti sorprenderai.
  2. Prendi RAM ECC, se pianifichi ZFS. Non risparmiare.
  3. Prendi almeno due dischi in mirror. Un disco solo — non è un'opzione per la produzione.
  4. Installa Proxmox tramite KVM/IPMI, non tramite rescue + debootstrap. Meno dolore.
  5. Subito configura chiavi SSH, porta non standard, disabilita password, installa fail2ban.
  6. Subito limita ZFS ARC. Di default consumerà metà della RAM.
  7. Crea un secondo bridge vmbr1 per la rete privata con NAT. Tutte le VM/LXC lì. Nessun IP pubblico sulle VM.
  8. Attiva NetBird (o Tailscale, o Headscale) prima di iniziare a migrare. Questo è il tuo canale di migrazione e accesso amministrativo.
  9. Non aprire l'UI di Proxmox all'esterno. Solo tramite la mesh VPN.
  10. Una piccola VPS di uscita presso un altro provider per la terminazione TLS e l'aggiramento dei blocchi — non è obbligatorio, ma molto comodo. Il prezzo è irrisorio, i vantaggi molti.
  11. PBS in un LXC separato + sync offsite in S3. I backup devono essere automatici.
  12. Almeno una volta al mese fai un restore di test. Altrimenti non hai backup, ma file per auto-rassicurarti.
  13. Migra un servizio alla volta, in ordine di criticità crescente. Non cercare di "traslocare tutto nel weekend".
  14. Riduci il TTL del DNS un giorno prima del cambio, non un'ora prima.
  15. Tieni la documentazione per ogni servizio: dove sono le configurazioni, come avviarlo, come fare il backup, come ripristinarlo. Tra sei mesi ti ringrazierai da solo.

Cosa resta da fare

Per completezza: la migrazione non è ancora finita al 100%. Restano:

  • Un paio di pannelli Remnawave dal vecchio server (pianificati per il prossimo weekend).
  • Spostamento di Caddy con plugin (c'è una build custom), al momento funziona temporaneamente.
  • Vecchio CrowdSec — lo installo da zero separatamente, non lo trasferisco.

Ma tutto ciò che è critico (forum, billing, bot, database) — è già sul server dedicato, funziona stabilmente, viene backuppato e monitorato.

Se hai domande sui passaggi specifici, configurazioni o insidie su cui sono inciampato più nel dettaglio — scrivi nei commenti, cercherò di approfondire. Particolarmente interessante sentire come risolvete compiti simili su altri hypervisor (XCP-ng, ESXi, o anche su Docker Swarm nudo) — forse mi sfugge qualcosa.

In bocca al lupo con il consolidamento delle tue infrastrutture. Meno fatture, più controllo — ne vale la pena.

~17 min read · scroll to continue ↓

## discussion

$ topics --entity=article0
sign in to start or join a discussion
No discussions yet — start one to break the ice.
↑↓ nav open⌘K palettei install? help