Comment je suis passé de cinq VPS à un seul serveur dédié avec Proxmox et j'ai arrêté de nourrir les hébergeurs
TL;DR : Infrastructure éclatée de cinq VPS chez trois hébergeurs → un serveur dédié Ryzen 7 9700X / 64 Go ECC / 2x NVMe ZFS-mirror, sous Proxmox VE. À l'intérieur : VM/LXC par rôle, NetBird mesh au lieu de la redirection de ports, un nœud de sortie sur un VPS séparé pour contourner les blocages et la terminaison TLS, PBS pour les sauvegardes. Avantage financier, avantage en contrôle, avantage en sérénité. Cet article explique pourquoi, comment, et où j'ai trébuché, pour que vous ne fassiez pas les mêmes erreurs.
Pourquoi j'ai lancé tout ça
Fin de l'année dernière, je me suis rendu compte que je payais pour cinq VPS distincts chez trois hébergeurs. Un pour le forum Discourse, un autre pour un ancien forum PHP avec MySQL, un troisième pour la facturation et des bots Telegram, un quatrième pour le VPN/proxy, et un cinquième pour les statiques et divers petits outils. Il y avait aussi n8n, Vaultwarden, et quelques Uptime Kuma qui se surveillaient mutuellement (comment faire autrement).
Ce qui n'allait pas :
- Argent. Au total, cela coûtait à peu près autant qu'un seul serveur dédié avec des caractéristiques similaires (mais ici, c'était partagé, là, dédié).
- Aucune isolation. Si un client d'un bot consomme toute la mémoire, mon forum commence à ralentir. Sur le même serveur. Merveilleux.
- Sauvegardes à la noix. Chaque VPS avait son propre cron rsync vers S3, avec des rétentions différentes, pas d'incrémentation, et la restauration était une aventure.
- Réseau en salade. SSH via différents ports, redirigés via Cloudflare Tunnels, via WireGuard configuré manuellement entre deux VPS, avec des configurations à trois endroits. Chaque fois que j'ajoutais une nouvelle machine, il fallait une journée pour l'intégrer.
- Apocalypse des mises à jour. Sur cinq Ubuntu/Debian différents avec des versions et des paquets variés, les mises à niveau devaient être faites manuellement et jamais simultanément. Tous les six mois, je m'engageais héroïquement dans la quête "mettre à jour tout, sans rien casser".
- CPU et RAM inactifs. Chaque VPS était réservé "pour le pic", alors qu'en moyenne, il n'était utilisé qu'à 15-20 %. De l'argent jeté par les fenêtres.
Bref, un cas classique où l'infrastructure avait grandi selon le principe "oh, il faut encore un service – achetons un VPS". Il était temps de tout consolider.
Ce que j'ai choisi et pourquoi
Le matériel
J'ai opté pour un serveur dédié :
- CPU : AMD Ryzen 7 9700X (8 cœurs / 16 threads, Zen 5)
- RAM : 64 Go DDR5 ECC 5200 MHz
- Disques : 2x NVMe 512 Go enterprise → miroir ZFS
- Réseau : 1 Gbps non mesuré
- Prix : environ le prix de deux VPS moyens chez OVH
L'hyperviseur
Proxmox VE 9.x. J'ai examiné les alternatives, mais brièvement :
- Docker nu — pas d'isolation, pas de snapshots corrects, sauvegarde uniquement via les outils compose, disque — une poubelle unique.
- VMware ESXi — plus gratuit, la licence Broadcom est magnifique, merci.
- XCP-ng — correct, mais personnellement, je connais Proxmox par cœur et sa communauté est plus vivante.
- Kubernetes — non, je suis une seule personne, je n'ai pas besoin d'assembler un avion pour aller au magasin.
Proxmox m'offre tout ce dont j'ai besoin : des machines virtuelles KVM pour tout ce qui nécessite une isolation (Docker, noyaux spécifiques, distributions différentes) ; des conteneurs LXC pour économiser des ressources (bases de données, surveillance, petits services) ; PBS intégré pour les sauvegardes ; ZFS prêt à l'emploi ; snapshots ; migration à chaud (si jamais un deuxième serveur dédié apparaît) ; une interface web où je peux cliquer quand je ne veux pas écrire dans le terminal.
L'architecture : schéma général
Je vais d'abord montrer ce que j'ai obtenu, puis expliquer comment j'y suis parvenu.
La logique est la suivante :
- Sur le serveur dédié se trouve Proxmox. Il détient l'IP publique
Y.Y.Y.Ysurvmbr0. - À l'intérieur, un deuxième bridge
vmbr1est créé avec un réseau privé10.10.10.0/24. C'est l'équivalent d'un "LAN interne" — toutes les VM et LXC y sont connectés, sortant via le NAT de l'hôte, sans ports publics entrants. - Sur l'hôte lui-même ne tournent que trois choses :
Caddy(reverse proxy interne),nftables(pare-feu) etNetBird(agent VPN). Pas de Docker sur l'hôte, pas de logique applicative sur l'hôte. L'hôte est une vache sacrée, sa tâche est d'être un hyperviseur et de ne pas planter. - Les machines virtuelles sont séparées par rôle : une pour le forum, une pour les services d'arrière-plan et les bots, une pour Dokploy avec des applications utilisateur, etc. Il y a une visibilité directe entre elles via
10.10.10.x, et vers l'extérieur – uniquement via le Caddy de l'hôte. - Les conteneurs LXC – pour tout ce qui est "léger" : plusieurs instances de Postgres, Proxmox Backup Server, tableaux de bord de surveillance. Ils sont également dans
vmbr1. - Un nœud de sortie séparé ("Peer Caddy") – c'est un petit VPS chez un autre hébergeur, dans un réseau adapté à mon public. Il exécute Caddy, qui termine les connexions TLS (Let's Encrypt) et proxifie le HTTP vers le serveur dédié via le mesh NetBird. Le DNS de tous les domaines publics pointe vers ce VPS, pas vers le serveur dédié.
- Le mesh NetBird relie le serveur dédié, le nœud de sortie et mon ordinateur portable (ainsi que quelques anciens serveurs sur lesquels tout n'a pas encore été migré). C'est WireGuard basé sur l'authentification SSO, sans ports ouverts vers l'extérieur.
Pourquoi une telle isolation via un nœud de sortie est un sujet à part, auquel je reviendrai.
Installation de Proxmox : comment je l'ai configuré
J'ai commandé le serveur dédié, et au premier démarrage, j'ai installé Proxmox via le mode rescue/KVM (OVH propose les deux – je préfère KVM, on voit tout le processus). Lors de l'installation :
- ZFS RAID1 sur les deux NVMe (
ashift=12, compression=lz4 activée immédiatement) - Partitionnement par défaut, Proxmox crée lui-même
rpool/ROOT,rpool/data, swap
Ensuite – nettoyage de base après l'installation. C'est indispensable, sans cela Proxmox génère des erreurs d'abonnement et ne fonctionne pas de manière optimale.
1# 1. Supprimer le dépôt enterprise (pas d'abonnement)
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. Supprimer la fenêtre de notification "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. Nom d'hôte / fuseau horaire
13hostnamectl set-hostname dedik-waw
14timedatectl set-timezone Europe/Warsaw
Durcissement SSH
Immédiatement. Pas "plus tard". "Plus tard" n'arrive jamais.
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... votre-clé" >> ~/.ssh/authorized_keys
12chmod 600 ~/.ssh/authorized_keys
13systemctl restart sshd
J'ai fermé le port 22 dans le pare-feu, ne laissant que le port non standard. Ce n'est pas de la "sécurité par obscurité", mais une réduction du bruit de fond dans les logs – sur le port 22, on reçoit 50 000 tentatives de brute force dès la première heure, rendant les logs illisibles. Sur le port 22222 – le silence permet de surveiller réellement les anomalies.
ZFS – configuration pour NVMe et 64 Go de RAM
ZFS, par défaut, veut consommer la moitié de la RAM pour ARC. C'est normal pour un serveur de fichiers et absolument contre-indiqué pour un hyperviseur, où la RAM est nécessaire aux machines virtuelles. Nous allons réduire ARC à un niveau raisonnable de 16 Go :
1cat > /etc/modprobe.d/zfs.conf << 'EOF'
2options zfs zfs_arc_max=17179869184
3options zfs zfs_arc_min=4294967296
4EOF
5update-initramfs -u
Répartition de ma mémoire :
- ~16 Go — ZFS ARC
- ~44 Go — VM/LXC
- ~4 Go — système, buffers, overhead
Paramètres utiles du pool lui-même :
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 # pour les disques VM
8zfs set sync=standard rpool/data
9
10zpool set autotrim=on rpool # critique pour NVMe
compression=lz4 économise 20-30% d'espace presque gratuitement en CPU. recordsize=64K pour les disques bloc des VM – c'est le meilleur compromis entre performance et amplification d'écriture.
Réseau interne et pare-feu
J'ai créé un deuxième bridge pour le réseau privé avec NAT vers l'extérieur :
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
Maintenant, chaque VM/LXC dans le bridge vmbr1 obtient une adresse locale 10.10.10.x et sort sur Internet via l'hôte, mais n'est pas visible depuis l'extérieur.
nftables avec policy drop. Seul ce qui doit être ouvert l'est, le reste est silencieusement abandonné. Ensemble minimum :
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 (uniquement depuis NetBird, voir ci-dessous)
12 tcp dport { 80, 443, 8080 } accept # Caddy
13 udp dport 29899 accept # NetBird
14
15 iif vmbr1 accept # réseau interne – tout est autorisé
16 iif wt0 accept # interface NetBird – également de confiance
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'accès à l'interface Proxmox (port 8006) est physiquement fermé à Internet via CF/pare-feu et j'y accède uniquement via NetBird. L'interface publique ne répond pas du tout. Idem pour l'interface PBS, les tableaux de bord et tout ce qui est administratif – uniquement via le mesh. Seuls les ports réellement publics des services sont ouverts.
NetBird mesh : pourquoi pas WireGuard classique
J'ai longtemps utilisé WireGuard standard, et c'était correct jusqu'à ce que j'aie plus de trois serveurs. Après, gérer les configurations est devenu pénible : chaque ajout de pair transforme la tâche en "mettre à jour la configuration sur tous les nœuds, ne pas oublier les allowed_ips, redémarrer le démon, vérifier que vous n'avez pas cassé la route vers un autre pair".
NetBird est un plan de gestion au-dessus de WireGuard. Techniquement, sous le capot, vous avez toujours du wg, mais :
- les nœuds se trouvent via un serveur de signalisation, le NAT-traversal est automatique
- authentification via SSO (pour moi – via Authentik), sans partage de clés
- l'accès est géré dans l'interface web via des politiques, on peut créer des groupes de machines et des règles entre eux
- proxy SSH intégré : on peut se connecter via
ssh user@machine.netbird.cloudet obtenir une authentification SSO (avec approbation dans Authentik). Il n'est même pas nécessaire d'ouvrir le port 22 sur le nœud vers l'extérieur.
J'ai installé l'agent NetBird :
- sur l'hôte Proxmox
- sur chaque VM qui doit être visible par l'administrateur ou d'autres VM
- sur le nœud de sortie
- sur mon ordinateur portable
En conséquence, je me connecte depuis mon portable à n'importe quelle machine avec une seule commande, sans redirection de ports, sans failles de pare-feu, sans hôtes de bastion supplémentaires. Et il n'y a pas de SSH ouvert sur aucune des VM privées – elles sont toutes uniquement dans vmbr1 plus le wt0 du mesh.
Machines virtuelles vs conteneurs : comment j'ai résolu ça pour moi
Une règle simple qui fonctionne presque toujours :
| Quand | Quoi choisir |
|---|---|
| Charges Docker | VM (Docker dans LXC peut être capricieux, surtout avec overlay2) |
| Bases de données sans Docker | LXC (plus léger, plus rapide, accès disque direct via ZFS) |
| Services système (PBS, surveillance, petits outils) | LXC |
| Applications nécessitant leur propre noyau / astuces réseau | VM |
| Nœuds VPN (WG, AmneziaWG) | LXC (overhead minimal) |
Au final, j'ai obtenu à peu près ceci :
Machines virtuelles (KVM) :
forum— Discourse dans le conteneur lanceur standard. Docker à l'intérieur.services— beaucoup de petites choses : bots webhook, bot IA, panneau de facturation, Vaultwarden, Uptime Kuma. Tous en Docker compose, un dossier par service.legacy— ancien forum PHP (IPS) avec PHP-FPM natif et Caddy sur VM. Je ne voulais pas l'empaqueter dans Docker – trop de legacy, plus simple de le laisser comme c'était.dokploy— Docker Swarm + Dokploy pour les applications utilisateur (Next.js, Postgres, Redis), déploiement via Git.
LXC :
pbs— Proxmox Backup Server (voir ci-dessous).pg16,pg17,pg18— trois instances Postgres distinctes de différentes versions majeures. Raison : différentes applications nécessitent des versions majeures différentes, et je ne veux pas les mettre à jour chacune.dashboards— un conteneur avec Homarr (page de démarrage), Uptime Kuma et Beszel hub. Les trois dans le même compose, car ils traitent logiquement de la même chose – la surveillance.
Chaque VM reçoit une IP statique 10.10.10.x (par plages, c'est plus facile à retrouver), 2-8 cœurs vCPU et 2-8 Go de RAM selon la charge. Les cœurs peuvent être surprovisionnés en toute sécurité – au total, j'ai alloué plus de cœurs aux VM que je n'en ai physiquement, et cela fonctionne parfaitement tant que personne n'atteint le CPU simultanément.
Reverse proxy : Caddy à deux étages
Dans Proxmox, j'ai installé Caddy sur l'hôte, pas dans une VM. Pourquoi ? Parce qu'il doit écouter les ports publics du serveur dédié et router via l'en-tête Host vers la VM appropriée, et créer une VM séparée avec redirection de port pour cela serait une couche supplémentaire inutile. Caddy est léger, écrit en Go, un service systemd, configuration dans un seul fichier.
Ce Caddy hôte écoute uniquement le port 8080 HTTP et route vers les backends via 10.10.10.x. Il n'y a pas de TLS dessus.
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}
Et la terminaison TLS et les certificats – sur un nœud de sortie séparé, dans Docker, selon le même principe :
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 – c'est l'adresse NetBird du serveur dédié. La requête arrive sur le nœud de sortie en HTTPS, est déchiffrée, part en HTTP via le mesh NetBird vers le serveur dédié, où Caddy de Proxmox fait correspondre via le Host et route vers la VM interne. Entre le nœud de sortie et le serveur dédié, c'est du HTTP par conception – nous faisons confiance au mesh, aucun trafic externe n'y circule.
Pourquoi un nœud de sortie ?
Plusieurs raisons :
- Contournement des blocages. Certaines sous-réseaux OVH sont bloqués en Russie. Le nœud de sortie est chez un hébergeur dont l'IP n'est pas bloquée. Le DNS des domaines publics pointe là-bas.
- Terminaison TLS en un seul endroit. Seul lui émet les certificats, seule son IP est utilisée pour le challenge Let's Encrypt. Cela simplifie tous les contrôles DNS et permet au serveur dédié d'être complètement invisible depuis Internet sur les ports 80/443.
- Couche d'isolation supplémentaire. Si quelqu'un lance un DDoS, il attaque le nœud de sortie, pas le serveur dédié. Je dispose d'un minimum de données sur le nœud de sortie, le recréer prend 10 minutes.
- Séparation du front public et du back-end. Je peux tranquillement gérer les mises à jour de Caddy / expérimenter sur le serveur dédié, tout en ayant une interface stable et séparée vers Internet.
Le seul inconvénient : chaque requête prend environ 5-15 ms de plus à cause du saut supplémentaire. C'est imperceptible pour le web.
De plus, pour certains services, il y a un Caddy direct sur l'hôte sur les ports 80/443 sans le nœud de sortie – pour les domaines que je n'ai pas besoin de faire passer par le point de sortie (par exemple, points d'extrémité de statut, surveillance, services où le DNS pointe déjà vers le serveur dédié). Cela fonctionne en parallèle : Caddy sur l'hôte écoute à la fois :8080 (interne depuis le nœud de sortie) et :80/:443 (direct depuis Internet), les routes sont différentes.
Migration : comment j'ai déménagé sans larmes et presque sans interruption
C'était l'étape la plus effrayante. Cinq serveurs, une trentaine de services, un forum en production avec des utilisateurs actifs, une facturation avec des abonnements actifs, des bases de données qu'il ne fallait absolument pas perdre.
Stratégie – migration service par service, dans l'ordre "du moins critique au plus critique" :
- D'abord, les petits outils et les sites statiques ont été déplacés (si quelque chose arrive, personne ne le remarquera).
- Ensuite, les bots et les services d'arrière-plan (ils peuvent supporter une minute d'interruption).
- Ensuite, les bases de données (avec une restauration préalablement vérifiée).
- Ensuite, les applications qui dépendent de ces bases de données.
- Enfin, le forum principal avec une dernière synchronisation complète et un basculement DNS.
Canal de migration
Au début, j'ai simplement installé NetBird sur les anciens serveurs. Cela a résolu deux problèmes immédiatement : je peux me connecter en SSH en toute sécurité aux réseaux internes, et rsync passe par WireGuard via NetBird, sans exposer les données à Internet.
La commande utilisée pour chaque service était à peu près la suivante :
1# Depuis le nouveau serveur dédié, via l'IP NetBird de l'ancien serveur :
2rsync -avzP --delete \
3 -e "ssh -p 5322" \
4 root@100.76.108.210:/var/discourse/shared/standalone/ \
5 /target/discourse/shared/standalone/
Pour les bases de données – dump et restauration, pas de copie de fichiers. Ne copiez jamais les fichiers de bases de données de type Postgres/MySQL "à chaud", c'est un aller simple vers le désastre.
1# Sur l'ancien
2docker exec -it shm-vsem-mysql mysqldump -u root -p shm-vsem | \
3 gzip > /tmp/shm-vsem.sql.gz
4
5# Sur le nouveau, via 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
Pour Discourse – sauvegarde et restauration natives via discourse backup / discourse restore via ./launcher enter app. À l'intérieur, il collecte correctement le dump de Postgres + les uploads + les configurations, et les restaure de la même manière.
Changement DNS
Une fois le service lancé au nouvel emplacement et vérifié qu'il fonctionnait via l'adresse interne – j'ai lancé les deux installations en parallèle pendant 5-15 minutes pour observer la synchronisation des données, puis j'ai basculé le DNS vers le nouveau serveur. J'avais préalablement réduit le TTL des enregistrements à 60-300 secondes, un jour avant le basculement.
Pour Discourse, qui a des utilisateurs actifs postant constamment, j'ai procédé comme suit :
- Tout a été lancé au nouvel emplacement.
- J'ai effectué la validation (connexion, publication, upload de fichiers vers S3, recherche).
- Sur l'ancienne installation, j'ai activé le
read_only_mode(Discourse le permet nativement). - J'ai effectué une dernière synchronisation rsync des uploads + un dernier dump de la base de données.
- J'ai lancé sur le nouveau, désactivé le mode lecture seule.
- J'ai basculé le DNS.
- Je n'ai rien touché sur l'ancienne installation pendant encore une semaine – au cas où.
L'interruption réelle pour les utilisateurs – environ deux minutes par service.
Surprises en cours de route
- Permissions lors de
pct restore. LXC sousunprivileged 1mappe les UID avec un décalage de 100000. Si sur l'ancien serveur vos fichiers appartiennent à l'UID 1000, sur le nouveau, ils appartiendront à l'UID 101000, et l'application ne les verra pas. Cela se résout soit par unchownaprès la restauration, soit par--unprivileged 0si vous comprenez les risques. - Docker ipv6 dans les VMs OVH démarré parfois mal – résolu en désactivant ipv6 dans le démon Docker (
"ipv6": false). - Heure sur les VM. Plusieurs fois, j'ai constaté des décalages de l'heure système entre l'hôte et les VM, ce qui cassait TLS et les signatures. Remède –
systemd-timesyncdouchronysur chaque VM, ethost.use-timedans l'agent Proxmox. - Migration Discourse entre deux versions. Si le serveur actuel de Discourse est plus récent que celui que vous avez installé sur le nouveau – la restauration échouera. La version doit correspondre ou être supérieure sur la nouvelle installation.
- Registre d'images pour Dokploy. Lorsque j'ai transféré les métadonnées de Dokploy via le dump
dokploy-postgres, la base de données contenait des liens vers l'ancien registre local sur l'ancienne IP. Les services, en tentant de démarrer, cherchaient100.76.117.115:5000et plantaient avecNo such image. Solution – reconstruire chaque application dans l'interface Dokploy ; la compilation locale place l'image sur le nouveau serveur.
Sauvegardes : PBS sur le même serveur dédié + hors site
Ici, il y a eu une discussion philosophique séparée avec moi-même : faut-il sauvegarder sur le même matériel ou non. Réponse : oui et non.
Niveau 1 – Snapshots ZFS sur le pool lui-même. Ils sont presque gratuits (copy-on-write), instantanés, et la restauration est instantanée. Je conserve des snapshots automatiques de rpool/data toutes les 15 minutes avec une rétention de 24 heures, plus des snapshots quotidiens avec une rétention d'une semaine. Utilisation de zfs-auto-snapshot. Protection contre "oups, je viens de supprimer la base de données de production" :
1apt install zfs-auto-snapshot
2# Ensuite, cela se fait automatiquement via cron pour créer frequent/hourly/daily/weekly/monthly
Niveau 2 – Proxmox Backup Server dans un LXC séparé sur le même hôte. Ce sont des sauvegardes incrémentielles complètes de VM/LXC via vzdump, dédupliquées au niveau des chunks. PBS stocke les snapshots dans un dataset ZFS séparé, les voit comme un dépôt, chaque VM a sa propre chaîne d'incréments.
Configuration dans Proxmox : Datacenter → Backup → Add. Planification : tous les jours à 4h du matin, rétention keep-daily=7 keep-weekly=4 keep-monthly=3. Tout cela se fait à la souris.
Placer PBS dans un LXC sur le même hôte est un compromis. Avantage : pas besoin de matériel séparé, la sauvegarde se fait en localhost, vitesse comparable à un SSD local, la rétention/déduplication fonctionne parfaitement. Inconvénient : si le serveur dédié entier tombe en panne – les sauvegardes aussi. C'est pourquoi il y a...
Niveau 3 – synchronisation du dépôt PBS vers S3 hors site. PBS peut effectuer un sync job vers un stockage compatible S3. Chaque nuit, je transfère les snapshots vers un bucket séparé chez Selectel (on peut utiliser n'importe lequel – Backblaze, Wasabi, Cloudflare R2). La rétention y est de deux semaines, car plus n'est pas nécessaire : pour le long terme, il y a le PBS local, et le stockage hors site est une assurance contre "tout le datacenter a brûlé".
Niveau 4 – données des applications séparément. Discourse fait ses propres sauvegardes et les place dans S3 (c'est une fonctionnalité native). Ainsi, même si PBS et le serveur dédié entier disparaissent – j'ai toujours des dumps cohérents de Discourse dans leur cloud.
1# Restauration d'une VM entière depuis PBS – littéralement une seule commande :
2pvesm list backup-pbs # voir ce qui est disponible
3qmrestore backup-pbs:backup/vzdump-qemu-201-2026_04_06-04_00_03.vma.zst 999 \
4 --storage local-zfs
5# Et en une minute, vous avez une copie de la VM du forum au moment de 4h du matin sur le VMID 999.
C'est un point crucial : les sauvegardes que vous n'avez pas essayé de restaurer – ne sont pas des sauvegardes. Une fois par mois, je fais une restauration de test d'une VM aléatoire sur un VMID vide, je vérifie qu'elle démarre, que l'application fonctionne dedans, et je la supprime. C'est ennuyeux, mais une fois, c'est ainsi que j'ai découvert qu'un des cron écrivait dans /tmp/..., qui était ignoré lors de la sauvegarde, et que l'application nécessitait une intervention manuelle après restauration.
Surveillance
Je n'aime pas assembler des usines à gaz comme Prometheus + Grafana + Alertmanager + Loki quand j'ai 15 machines. J'ai donc opté pour trois outils légers dans un seul LXC :
- Beszel – collecte les métriques des agents sur chaque VM (CPU, RAM, disques, interfaces réseau, conteneurs Docker). Le hub réside dans LXC, les agents – sur chaque VM/LXC via un service systemd. Beszel a sa propre authentification, via PocketBase, ce qui est parfois gênant (voir ci-dessous pour les pièges), mais fonctionne globalement.
- Uptime Kuma – tests par HTTP/HTTPS/Ping/TCP. J'y ai configuré tout le public (domaines), tous les services internes (via NetBird), et les pings vers tous les nœuds du mesh. Alertes – vers Telegram.
- Homarr – page de démarrage avec des liens vers toutes les interfaces d'administration. Pour ne pas avoir à me souvenir sur quel port se trouve l'interface PBS, sur quel Dokploy, sur quel Vaultwarden. J'ouvre simplement Homarr et je clique.
Les trois sont dans le même Docker compose, dans le même LXC, accessibles uniquement via NetBird.
Piège avec Beszel, pour que vous ne tombiez pas dedans : Beszel a deux tables d'utilisateurs dans PocketBase –
_superusers(pour CLI/API) etusers(pour l'interface web). Si vous réinitialisez le mot de passe via la CLIsuperuser upsert– vous ne réinitialisez que_superusers, et pour l'interface web, vous vous connectez viauserset le mot de passe ne correspond pas. Se corrige par une requête PATCH sur/api/collections/users/records/<id>via l'API REST.
Ce que j'ai obtenu au final
Après environ trois semaines de migration, lorsque les derniers services se sont stabilisés, j'ai fait le bilan :
| Paramètre | Avant | Après |
|---|---|---|
| Serveurs / Factures | 5 chez 3 hébergeurs | 1 serveur dédié + 1 micro-VPS |
| Factures mensuelles | ~$X | ~$X/2 |
| Ressources disponibles | "ça suffit à peu près" | 8 vCPU et 30 Go de RAM en réserve |
| Sauvegardes | cron rsync vers S3 sur chaque VPS | PBS + hors site + snapshots ZFS |
| Restauration | "eh bien, une journée environ" | 2-5 minutes par VM depuis PBS |
| Accès SSH | 5 ports et clés différents | un seul mesh NetBird avec SSO |
| Isolation des services | poubelle commune | chaque service dans sa propre VM/LXC |
| Snapshot avant mise à jour | "prie" | qm snapshot 201 pre-update |
| Interface web pour les tâches routinières | quelle interface web ? | UI Proxmox |
Le principal bénéfice émotionnel que cela m'a apporté – j'ai arrêté d'avoir peur de toucher à quoi que ce soit. Toute action dangereuse (mise à jour, migration, expérimentation) commence maintenant par un snapshot et se termine soit par un commit, soit par une annulation en 30 secondes. J'ai commencé à essayer de nouvelles choses plus souvent, car le coût de l'erreur a diminué d'un ordre de grandeur.
Checklist, si vous voulez répéter
Si vous vous retrouvez avec les mêmes symptômes que moi – voici une courte checklist, dans quel ordre il est logique de procéder :
- Calculez combien vous payez pour toutes vos VPS combinées, et comparez avec les prix des serveurs dédiés chez OVH/Hetzner/LeaseWeb. Vous serez surpris.
- Prenez de la RAM ECC, si vous prévoyez d'utiliser ZFS. N'économisez pas.
- Prenez au moins deux disques en miroir. Un seul disque n'est pas une option pour la production.
- Installez Proxmox via KVM/IPMI, pas via rescue + debootstrap. Moins de soucis.
- Immédiatement, configurez les clés SSH, un port non standard, désactivez les mots de passe, installez fail2ban.
- Immédiatement, limitez ZFS ARC. Par défaut, il consommera la moitié de la RAM.
- Créez un deuxième bridge
vmbr1pour le réseau privé avec NAT. Toutes les VM/LXC y vont. Pas d'IP publiques sur les machines virtuelles. - Installez NetBird (ou Tailscale, ou Headscale) avant de commencer la migration. C'est votre canal de migration et votre accès administrateur.
- N'ouvrez pas l'UI Proxmox vers l'extérieur. Uniquement via le mesh VPN.
- Un petit VPS de sortie chez un autre hébergeur pour la terminaison TLS et le contournement des blocages – pas obligatoire, mais très pratique. Coût dérisoire, nombreux avantages.
- PBS dans un LXC séparé + synchronisation hors site vers S3. Les sauvegardes doivent être automatiques.
- Au moins une fois par mois, faites une restauration de test. Sinon, vous n'avez pas de sauvegardes, mais des fichiers pour vous rassurer.
- Migrez un service à la fois, par ordre de criticité croissante. N'essayez pas de "tout déplacer pendant le week-end".
- Réduisez le TTL DNS un jour avant le basculement, pas une heure avant.
- Tenez un document pour chaque service : où se trouvent les configurations, comment démarrer, comment sauvegarder, comment restaurer. Dans six mois, vous vous remercierez.
Ce qui reste à faire
Par souci de complétude : ma migration n'est pas encore terminée à 100 %. Il reste :
- Quelques panneaux Remnawave de l'ancien serveur (prévu pour le week-end prochain).
- Migration de Caddy avec des plugins (il y a une compilation personnalisée), fonctionne temporairement pour l'instant.
- Ancien CrowdSec – je l'installe séparément à partir de zéro, sans migrer.
Mais tout ce qui est critique (forums, facturation, bots, bases de données) – est déjà sur le serveur dédié, fonctionne de manière stable, est sauvegardé et surveillé.
Si vous avez des questions sur les étapes spécifiques, les configurations ou les pièges sur lesquels je suis tombé plus en détail – écrivez dans les commentaires, j'essaierai de développer. J'aimerais particulièrement savoir comment vous résolvez des problèmes similaires sur d'autres hyperviseurs (XCP-ng, ESXi, ou carrément sur du Docker Swarm nu) – peut-être que je rate quelque chose.
Bonne chance pour la consolidation de vos infrastructures. Moins de factures, plus de contrôle – ça en vaut la peine.