Vue lecture

Proxmox Backup Server : Stockage ZFS

Un mémo sur la mise en place d’un stockake ZFS pour l’hébergement des sauvegardes d’un Proxmox Backup Server.
L’objectif premier était de concevoir une architecture de stockage à la fois performante, résiliente et facile à maintenir.

Le serveur à ma disposition dispose de 12 disques HDD de 8 To (7.3 To nets) et d’un RAID1 pour le système.

NB : Cet article se concentre exclusivement sur la configuration de ZFS. Il ne couvre pas l’intégration dans proxmox, ni les fonctionnalités avancées telles que les politiques de rétention (Prune), la collecte des données obsolètes (Garbage Collection), ou d’autres options spécifiques à PBS.

Pourquoi ZFS et RAIDZ2 ?

ZFS est un système de fichiers avec comme fonctions :

  • Protection contre la corruption de données
  • Compression native
  • Snapshots incrémentaux
  • Et une gestion avancée des volumes et disques.

RAIDZ2 est l’équivalent du RAID6 : il permet de tolérer la perte de deux disques par vdev sans perte de données.

Architecture retenue

Configuration :

  • 2 vdevs de 5 disques en RAIDZ2
  • 2 disques en spare
  • Détails :
    • Disques actifs : 10 (5+5 + 2×parité RAIDZ2)
    • Disques spare : 2 (remplacement automatique en cas de panne)
    • Tolérance aux pannes : jusqu’à 2 disques HS par vdev
    • Capacité utilisable : environ 58.4 To nets (8 disques × 7.3 To)

Pourquoi deux vdevs RAIDZ2 au lieu d’un seul ?

Choisir 2 vdevs RAIDZ2 au lieu d’un seul vdev de 12 disques RAIDZ2 présente plusieurs avantages :

  • Performance accrue : les deux vdevs fonctionnent en parallèle → plus d’IOPS.
  • Resilvering plus rapide : une reconstruction de disque touche seulement un vdev (6 disques), pas 12.
  • Risque réduit : 3 disques HS ne sont pas fatal si répartis sur les 2 vdevs.
  • Évolutivité : possibilité d’ajouter un 3e vdev plus tard sans casser le pool.

Création du pool ZFS avec 2 disques en spares

  • Création du pool :
zpool create -o ashift=12 -o autotrim=on \
  -O compression=lz4 -O atime=off -O xattr=sa -O acltype=posixacl \
  pbs_pool \
  raidz2 /dev/sd[a-e] \
  raidz2 /dev/sd[f-j] \
  spare /dev/sdk /dev/sdl
  • Détail des options :
    • -o ashift=12 :
    • Définit la taille minimale d’allocation à 4 Ko (2^12 = 4096).
      Une fois définie, cette valeur ne peut pas être changée.

    • -O compression=lz4
    • Active la compression transparente avec l’algorithme LZ4 (rapide, efficace).
      Réduit l’espace utilisé sans impacter les performances.

    • -O atime=off
    • Désactive la mise à jour automatique de l’horodatage d’accès à chaque lecture.
      Réduit significativement les écritures inutiles → plus de performance.

    • -O xattr=sa
    • Stocke les attributs étendus (xattr) dans des structures ZFS internes (plutôt qu’en fichiers séparés).
      Améliore les performances, notamment avec PBS.

    • -O acltype=posixacl
    • Permet de gérer des ACL POSIX (permissions avancées).
      Important si PBS gère plusieurs utilisateurs ou scripts avec droits précis.

    • pbs_pool
    • Nom du pool ZFS, ici pbs_pool

    • raidz2 /dev/sd[a-e]
    • Crée un vdev RAIDZ2 avec 6 disques (ici sda à sde).
      Tolère la perte de 2 disques dans ce groupe.

    • raidz2 /dev/sd[f-j]
    • Deuxième vdev RAIDZ2 identique au premier.
      Les deux vdevs forment un pool unique avec une performance en lecture/écriture parallèle.

    • spare /dev/sdk /dev/sdl
    • Définit deux disques de secours.
      ZFS les utilise automatiquement si un disque actif tombe en panne (resilvering automatique).

    • Lister le pool :
    NAME       SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
    pbs_pool  72.8T  1.37M  72.7T        -         -     0%     0%  1.00x    ONLINE  -
    
  • petite précision sur la taille du pool :
    • zpool list affiche la taille brute du pool
      Ici 2 vdevs en RAIDZ2 de 6 disques de 7.3 To.
      RAIDZ2 utilise 2 disques pour la parité par vdev, donc :
      • 6 disques – 2 parités = 4 disques utiles × 2 vdevs = 8 disques utiles.
      • 8 × 7.3 To = ≈ 58.4 To utilisables.

    C’est la capacité effective, celle réellement disponible pour les données.

    Pourquoi zpool list indique 72.8 To ?
    Explication :

    • ZFS additionne tous les disques du pool, même ceux réservés à la parité.
    • 12 disques × 7.3 To ≈ 87.6 To physiques.
    • Deux disques sont hot spares, donc non comptés ici.
    • 10 disques actifs × 7.3 To = ≈ 72.8 To ➜ c’est bien ce que ZFS affiche le SIZE.

    Important à retenir :

    • SIZE ≠ capacité utilisable.

    Pour connaître l’espace réel du stockage, faut retirer les disques de parité.

  • Afficher le status du pool ZFS :
  • zpool status
      pool: pbs_pool
     state: ONLINE
    config:
    
    	NAME        STATE     READ WRITE CKSUM
    	pbs_pool    ONLINE       0     0     0
    	  raidz2-0  ONLINE       0     0     0
    	    sda     ONLINE       0     0     0
    	    sdb     ONLINE       0     0     0
    	    sdc     ONLINE       0     0     0
    	    sdd     ONLINE       0     0     0
    	    sde     ONLINE       0     0     0
    	  raidz2-1  ONLINE       0     0     0
    	    sdf     ONLINE       0     0     0
    	    sdg     ONLINE       0     0     0
    	    sdh     ONLINE       0     0     0
    	    sdi     ONLINE       0     0     0
    	    sdj     ONLINE       0     0     0
    	spares
    	  sdk       AVAIL   
    	  sdl       AVAIL   
    
    errors: No known data errors
    
    • Création du dataset pour PBS :
    zfs create -o mountpoint=/mnt/datastore/pbs pbs_pool/pbs
  • Intégration dans PBS via l’interface Web :
    • Menu Datastore → Add
    • Chemin : /mnt/datastore/pbs
  • Vue du Datastore dans l’interface web de Proxmox Backup Server :
  • Pourquoi l’interface Web PBS affiche 47.20 TB ?

    L’écart entre la capacité brute ZFS et celle exposée dans PBS s’explique en trois points :

    • Unités To vs TB :
      ZFS indique en tébioctets (1 To = 2¹⁰ GiB), PBS en téraoctets décimaux (1 TB = 10¹² octets).
      ~58.4 To ZFS ≃ 64.2 TB décimaux.
    • Overhead et réserves ZFS :
      ZFS réserve slack space et métadonnées pour maintenir les perfs (80–85 % d’usage max recommandé).
    • Datastore PBS :
      PBS ne compte que l’espace réellement assigné à son point de montage, en arrondissant et en gardant une marge pour ses opérations internes.
    Élément Valeur approximative
    Disques utiles (8 × 7.3 To) ≈ 58.4 To
    Conversion To → TB 58.4 × 1.0995 ≃ 64.2 TB
    Overhead ZFS + réserves PBS – 15–20 %
    Capacité visible dans PBS ≈ 47.2 TB

    Cette valeur reflète l’espace réellement exploitable et sécurisé pour les sauvegardes PBS.

    Bonus : Resilvering (reconstruction de disque)

    Le resilvering est le processus par lequel ZFS reconstruit les données d’un disque défaillant ou remplacé dans un pool RAIDZ, en utilisant les autres disques et les données redondantes (parité).

    C’est l’équivalent du rebuild dans les RAID classiques.

    Contrairement aux RAID matériels, ZFS ne recopie pas tout le disque, mais uniquement les blocs réellement utilisés, ce qui rend le resilvering souvent plus rapide et plus sûr.

    Ressources

    •  

    Proxmox : utiliser un miroir local pour l’installation de Ceph

    Un petit mémo pour expliquer comment forcer l’utilisation d’un miroir local lors de l’installation de Ceph sur Proxmox.

    Par défaut, que ce soit via l’interface web de Proxmox ou la commande pveceph, l’installation de Ceph s’appuie sur le script Perl pveceph.pm, qui impose l’utilisation du dépôt officiel https://enterprise.proxmox.com ou http://download.proxmox.com.

    Cela pose problème lorsqu’on souhaite utiliser un miroir local, par exemple avec Proxmox Offline Mirror. En effet, même si un miroir local est disponible sur le système, il ne sera pas pris en compte : le script pveceph.pm remplace automatiquement les dépôts configurés par ceux qu’il contient en dur.

    Configurer et utiliser un dépôt local Ceph pour Proxmox

    Comme indiqué en début d’article, les urls des dépots sont renseignées dans le script perl pveceph.pm :

    grep proxmox.com /usr/share/perl5/PVE/CLI/pveceph.pm
    	my $cdn = $enterprise_repo ? 'https://enterprise.proxmox.com' : 'http://download.proxmox.com';
    
    sed -i 's/download\.proxmox\.com/mirrors\.local/g' /usr/share/perl5/PVE/CLI/pveceph.pm
    
  • Attention aussi au chemin complet du dépôt local :
    sed -i 's/debian\/ceph/ceph\/latest\/ceph/g' /usr/share/perl5/PVE/CLI/pveceph.pm
    
  • Installation de Ceph via le dépôt local

    • Cliquer dans le menu Ceph de Proxmox pour l’installation :
    • Sélectionner la bonne version de Ceph et le dépôt No-Subscription
    • Et si tout va bien :
    • Sur la capture ci-dessous, l’url du dépôt de Ceph est bien celle du dépôt local :
    •  

    Installer et configurer Authelia pour Proxmox

    Un mémo sur comment installer, configurer et intégrer Authelia à Proxmox pour l’authentification unique et à deux facteurs.

    Présentation d’Authelia

    Authelia est une solution d’authentification et d’autorisation open-source destinée à sécuriser l’accès aux applications web. Elle agit comme un reverse proxy d’authentification centralisé, offrant une gestion avancée des utilisateurs et des stratégies d’accès.
    Principales fonctionnalités :

    ✅ Authentification à deux facteurs (2FA) : Supporte TOTP, Duo, WebAuthn (FIDO2).
    ✅ Intégration avec OpenID Connect : Permet l’authentification unique (SSO).
    ✅ Gestion fine des accès : Basée sur les règles configurables (ACL).
    ✅ Compatibilité avec les reverse proxies : Fonctionne avec Traefik, Nginx, Caddy, etc.
    ✅ Stockage flexible : Supporte SQLite, PostgreSQL et MySQL pour la gestion des utilisateurs.
    ✅ Déploiement facile : Disponible via Docker, Kubernetes et installation classique.
    Cas d’usage

    🔹 Sécuriser des services auto-hébergés (GitLab, Nextcloud, Home Assistant…)
    🔹 Mettre en place un portail SSO centralisé pour plusieurs applications
    🔹 Renforcer la sécurité des accès avec la double authentification

    Informations globales et installation des dépendances nécessaires

    Pour le mémo, voici les informations utilisées :

    • L’OS du serveur Authelia : Debian 12
    • L’installation d’Authelia se fait sans docker
    • Pas de serveur SMTP sur Authelia
    • nom d’hôtes :
      • Serveur Proxmox : proxmox.local
      • Serveur Authelia : authelia.local
    • Utilisateur de test :
      • login: testuser
      • Mot de passe : authelia
    • Installation des dépendances nécessaires :
    apt install install nginx openssl apt-transport-https curl gnupg -y

    Installation de Authelia via le dépôt

    • Importez la clé de signature :
    curl -fsSL https://apt.authelia.com/organization/signing.asc | sudo gpg --dearmor -o /etc/apt/keyrings/authelia.gpg
  • Ajout du dépôt Authelia :
  • echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/authelia.gpg] https://apt.authelia.com/stable/debian/debian all main" | sudo tee /etc/apt/sources.list.d/authelia.list > /dev/null
  • Mise à jour des dépôts :
  • apt update
  • Installation de Authelia :
  • apt install authelia -y

    Configuration de Authelia

    • Configuration de base :
      • Génération d’un certificat et d’une clé privé pour Authelia :
      mkdir -p /etc/authelia/ssl
      cd /etc/authelia/ssl
      authelia crypto pair rsa generate
      
    • Création du fichier de configuration (attention, ici j’intègre de suite la partie client de Proxmox ) :
      nano /etc/authelia/configuration.yml
      ---
      # Configuration du serveur Authelia
      server:
        address: "tcp://0.0.0.0:9091/"  # Écoute sur toutes les interfaces sur le port 9091
      
      # Configuration des logs
      log:
        level: debug  # Niveau de log : debug pour plus de détails
      
      # Configuration de la validation d'identité
      identity_validation:
        reset_password:
          jwt_secret: "ba820cfdc0c587eff1a23b96a3896ec7a076c384c09ad10bfc1b74788eea39631a4d9cfa22717645a396f5d45b18d632602e848ecb8c967b7854d5ebc4446b8a"  # Clé secrète pour le JWT utilisé dans la réinitialisation de mot de passe
      
      # Configuration des sessions
      session:
        name: authelia_session  # Nom du cookie de session
        same_site: lax  # Politique SameSite pour le cookie
        expiration: 1h  # Durée de vie de la session
        inactivity: 5m  # Temps d'inactivité avant expiration de la session
        remember_me: 1M  # Durée de la session en mode "Se souvenir de moi"
        secret: "8938ce8b853e74b35c05e0f10a904bd6ce4849d2aed8fb1b23b2916dd70c2af487a9ae5bf9672fa82411a3b171d351c08a0b75aa151939be45427174c26d5d60"  # Clé secrète pour la session
        cookies:
          - domain: "authelia.local"  # Domaine du cookie
            authelia_url: "https://authelia.local"  # URL d'Authelia
            same_site: lax  # Politique SameSite du cookie
      
      # Configuration du contrôle d'accès
      access_control:
        default_policy: deny  # Politique par défaut : refusé
        rules:
          - domain: "authelia.local"  # Domaine protégé
            policy: two_factor  # Exige une authentification à deux facteurs
          - domain: "proxmox.local"  # Domaine protégé
            policy: two_factor  # Exige une authentification à deux facteurs
      
      # Backend d'authentification (fichier YAML)
      authentication_backend:
        file:
          path: "/etc/authelia/users.yml"  # Chemin du fichier contenant les utilisateurs
      
      # Configuration du TOTP (authentification à deux facteurs par application OTP)
      totp:
        issuer: authelia.local  # Émetteur pour les codes OTP
        algorithm: sha256  # Algorithme utilisé pour le TOTP
        digits: 6  # Nombre de chiffres dans le code OTP
        period: 30  # Durée de validité du code en secondes
        skew: 1  # Tolérance de synchronisation en périodes
        secret_size: 32  # Taille du secret généré
      
      # Configuration du fournisseur OpenID Connect
      identity_providers:
        oidc:
          jwks:
            - key: |
                -----BEGIN PRIVATE KEY-----
                (clé privée pour la signature des tokens JWT. Voir plus bas  "Pour générer la clé privé de identity_providers")
                -----END PRIVATE KEY-----
          clients:
            - client_id: proxmox  # Identifiant du client OpenID Connect
              client_name: "proxmox.local"  # Nom du client
              client_secret: "$pbkdf2-sha512$310000$..."  # Secret du client (hashé)
              redirect_uris:
                - https://proxmox.local:8006  # URI de redirection après authentification
              scopes:
                - openid  # Activation du scope OpenID
                - profile  # Activation du scope profil
                - email  # Activation du scope email
              userinfo_signed_response_alg: none  # Réponse des infos utilisateur non signée
              require_pkce: false  # Désactive l'utilisation de PKCE
              authorization_policy: two_factor  # Exige une authentification à deux facteurs
      
      # Configuration du stockage\storage:
        encryption_key: "ae5060901aaf3172cc87b896c92c30961b3734fc9a97be5c1da77b04dd4b754433f5cad3f679140d70ccc1a31743194231be04c5922dba34c275f89ac0bb42ce"  # Clé de chiffrement des données stockées
        local:
          path: "/var/lib/authelia/db.sqlite3"  # Utilisation d'une base de données SQLite pour le stockage local
      
      # Configuration des notifications
      notifier:
        filesystem:
          filename: "/var/log/authelia/notifications.txt"  # Fichier où sont stockées les notifications
      
      • Pour générer la clé privé de identity_providers :
      authelia crypto pair rsa generate
      cat private.pem
    • Pour jwt_secret, session.secret et encryption_key :
    openssl rand -hex 64
  • Pour client_secret :
  • authelia crypto hash generate pbkdf2 --password toto
  • Créer un fichier de base de données utilisateur :
    • Pour commencer, créer un mot de passe chiffré :
    authelia crypto hash generate --password authelia
  • Créer le fichier de configuration des utilisateurs :
  • nano /etc/authelia/users.yml
    users:
      testuser:
        displayname: "Test User"
        password: "$argon2id$v=19$m=32768,t=1,p=8$eUhVT1dQa082YVk2VUhDMQ$E8QI4jHbUBt3EdsU1NFDu4Bq5jObKNx7nBKSn1EYQxk"
    
  • Pour vérifier la validation de la configuration :
  • authelia validate-config -c /etc/authelia/configuration.yml
    Configuration parsed and loaded successfully without errors.
  • Création d’un service systemd
  • cp /tmp/authelia.service /etc/systemd/system/
    systemctl daemon-reload
    systemctl enable --now authelia
    systemctl status authelia
    
  • Pour avoir les journaux de logs en temps réel :
  • journalctl -u authelia -f

    Configuration du serveur web d’Authelia

    Attention, ici c’est une proposition de configuration nginx de base fonctionnelle

    • Génération du certificat SSL autosigné :
    mkdir -p /etc/nginx/ssl
    cd /etc/nginx/ssl
    openssl req -x509 -nodes -days 365 -newkey rsa:4096 -keyout authelia.key -out authelia.crt -subj "/CN=authelia.local"
    chmod 600 authelia.key authelia.crt
    
  • Créer le fichier de configuration du serveur web popur AUthelia :
  • nano /etc/nginx/site-enable/authelia.conf
    server {
        listen 443 ssl;
        server_name authelia.local;
    
        ssl_certificate /etc/nginx/ssl/authelia.crt;
        ssl_certificate_key /etc/nginx/ssl/authelia.key;
    
        location / {
            proxy_pass http://localhost:9091;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto https;
        }
    }
    
    # Redirection HTTP -> HTTPS
    server {
        listen 80;
        server_name authelia.local;
        return 301 https://$host$request_uri;
    }
    
  • test de la configuration :
  • nginx -t
  • Redémarrer le serveur web :
  • systemctl restart nginx

    Configuration de la double authentification de Authelia avec TOTP

    • Sur le smartphone, installer l’application libre et open-source Aegis Authenticator -> https://f-droid.org/fr/packages/com.beemdevelopment.aegis/
    • Sur le PC, ouvrir le navigateur Internet et saisir l’URL du serveur Authelia :
    • Cliquer sur « Enregistrer l’appareil » :
    • Cliquer sur Ajouter :
    • Saisir le mot de passe à usage unique :
      • Mais je n’ai pas de serveur SMTP de configurer ???
        Le mot de passe unique, se trouve dans /var/log/authelia/notifications.txt
      cat /var/log/authelia/notifications.txt
      Date: 2025-03-19 10:40:29.407130819 +0100 CET m=+5967.802203980
      Recipient: {testuser testuser@example.com}
      Subject: Confirm your identity
      A ONE-TIME CODE HAS BEEN GENERATED TO COMPLETE A REQUESTED ACTION
      
      Hi testuser,
      
      This notification has been sent to you in order to verify your identity to
      change security details for your account at authelia.local.
      
      Do not share this notification or the content of this notification with anyone.
      
      The following one-time code should only be used in the prompt displayed in your
      browser.
      
      --------------------------------------------------------------------------------
      
      B6LAMWY4
      
      --------------------------------------------------------------------------------
      
  • Une fois le code saisi, cliquer sur Suivant :
  • Avec l’application Aegis Authenticator, scanner le QR Code, puis cliquer sur suivant :
  • Pour confirmer, saisir le code temporaire afficher dans l’application Aegis Authenticator :
  • Le nouvel utilisateur a bien été ajouté à Authelia :
  • Intégration d’Authelia à Proxmox

    • Première chose, importer le certificat autosigné d’Authelia dans le magasin de certificat de Proxmox :
    scp root@authelia.local:/etc/nginx/ssl/authelia.crt /usr/local/share/ca-certificates/
    update-ca-certificates
  • Ouvrir Proxmox, puis Datacenter, Realms puis cliquer sur « Add »
  • Sélectioner OpenID Connect Server :
  • Renseigner comme suit :
  • Pour éviter l’erreur 401, ajouter de suite l’utilisateur testuser :
  • tester l’authentification sur Proxmox

    • Ouvrir Proxmox et sélectionner authelia comme système d’authentification :
    • Redirection vers le serveur Authelia, saisir le login et mot de passe :
    • La double authentification avec le code temporaire :
    • Accepter le consentement :
    • Et voilà, l’utilisateur testuser est connecté à Proxmox (évidemment, faudra configurer ses droits) :

    Ressources

    •