Skip to content

VYKAR BACKUP + ZFS

Sauvegarde chiffrée, dédupliquée et basée sur des snapshots ZFS vers un serveur REST dédié.


1. Architecture

┌─────────────────────┐     HTTPS/TLS      ┌───────────────────────────────┐
│  serveur-prod-1     │ ──────────────────►│  backup-prod-1.example.com    │
│                     │                    │  vykar-server :8585           │
│  stack: blog        │                    │  /var/lib/vykar/serveur-prod-1│
│  stack: shop        │                    │  token: prod-1-xxxx           │
│  /etc, /opt/stacks  │                    │  quota: 200G                  │
└─────────────────────┘                    └───────────────────────────────┘

┌─────────────────────┐     HTTPS/TLS       ┌───────────────────────────────┐
│  serveur-prod-2     │ ──────────────────► │  backup-prod-2.example.com    │
│                     │                     │  vykar-server :8586           │
│  stack: api         │                     │  /var/lib/vykar/serveur-prod-2│
│  stack: monitoring  │                     │  token: prod-2-xxxx           │
└─────────────────────┘                     │  quota: 150G                  │
                                            └───────────────────────────────┘

┌─────────────────────┐     HTTPS/TLS       ┌──────────────────────────────┐
│  serveur-staging    │ ──────────────────► │  backup-staging.example.com  │
│                     │                     │  vykar-server :8587          │
│  stack: blog-dev    │                     │  /var/lib/vykar/serveur-stag │
│  stack: shop-dev    │                     │  token: staging-xxxx         │
└─────────────────────┘                     │  quota: 50G                  │
                                            └──────────────────────────────┘

2. Serveur de destination

2.1 1. Préparer les partitions ZFS

# Installer ZFS
sudo apt install zfsutils-linux

# Créer un pool sur disque dédié (ou en miroir)
sudo zpool create tank /dev/sdb
# sudo zpool create tank mirror /dev/sdb /dev/sdc

# Créer les datasets
sudo zfs create tank/www
sudo zfs create tank/mysql
sudo zfs create tank/data

# Déf{ .ini .copy }r les points de montage
sudo zfs set mountpoint=/var/www   tank/www
sudo zfs set mountpoint=/var/lib/mysql tank/mysql

# Rendre les snapshots accessibles à Vykar
sudo zfs set snapdir=visible tank/www
sudo zfs set snapdir=visible tank/mysql
sudo zfs set snapdir=visible tank/data

2.2 2. Installer vykar-server

# Télécharger le binaire (adapter la version)
wget https://github.com/borgbase/vykar/releases/download/v0.12.1/vykar-v0.12.1-x86_64-unknown-linux-gnu.tar.gz
tar xzf vykar-v0.12.1-x86_64-unknown-linux-gnu.tar.gz
sudo mv vykar-server /usr/local/bin/

# Créer l'utilisateur dédié
sudo useradd -r -s /usr/sbin/nologin -d /var/lib/vykar vykar
sudo mkdir -p /var/lib/vykar
sudo chown vykar:vykar /var/lib/vykar

2.3 3. Configurer les tokens et répertoires

# Créer les répertoires par serveur
sudo mkdir -p /var/lib/vykar/serveur-prod-1
sudo mkdir -p /var/lib/vykar/serveur-prod-2
sudo mkdir -p /var/lib/vykar/serveur-staging
sudo chown -R vykar:vykar /var/lib/vykar/

# Générer un token unique par serveur
openssl rand -hex 32  # → token serveur-prod-1
openssl rand -hex 32  # → token serveur-prod-2
openssl rand -hex 32  # → token serveur-staging
Fichiers d'environnement — /etc/vykar/*.env
# /etc/vykar/serveur-prod-1.env
sudo tee /etc/vykar/serveur-prod-1.env << 'EOF'
VYKAR_TOKEN=token-prod-1-xxxxxxxxxxxxxxxx
VYKAR_PORT=8585
VYKAR_QUOTA=200G
EOF

# /etc/vykar/serveur-prod-2.env
sudo tee /etc/vykar/serveur-prod-2.env << 'EOF'
VYKAR_TOKEN=token-prod-2-xxxxxxxxxxxxxxxx
VYKAR_PORT=8586
VYKAR_QUOTA=150G
EOF

# /etc/vykar/serveur-staging.env
sudo tee /etc/vykar/serveur-staging.env << 'EOF'
VYKAR_TOKEN=token-staging-xxxxxxxxxxxxxxxx
VYKAR_PORT=8587
VYKAR_QUOTA=50G
EOF

sudo chmod 600 /etc/vykar/*.env
sudo chown vykar:vykar /etc/vykar/*.env

2.4 4. Lancer les services systemd

Template systemd — /etc/systemd/system/vykar-server@.service
sudo tee /etc/systemd/system/vykar-server@.service << 'EOF'
[Unit]
Description=Vykar backup server - %i
After=network-online.target

[Service]
Type=simple
User=vykar
Group=vykar
EnvironmentFile=/etc/vykar/%i.env
ExecStart=/usr/local/bin/vykar-server \
    --data-dir /var/lib/vykar/%i \
    --append-only \
    --quota ${VYKAR_QUOTA}
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/vykar/%i

[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now vykar-server@serveur-prod-1
sudo systemctl enable --now vykar-server@serveur-prod-2
sudo systemctl enable --now vykar-server@serveur-staging

2.5 5. Reverse proxy TLS

# Serveur prod-1
server {
    listen 443 ssl http2;
    server_name backup-prod-1.example.com;

    ssl_certificate     /etc/letsencrypt/live/backup-prod-1.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/backup-prod-1.example.com/privkey.pem;

    client_max_body_size    600m;
    proxy_request_buffering off;
    proxy_read_timeout      300s;

    location / {
        proxy_pass http://127.0.0.1:8585;
    }
}

# Serveur prod-2
server {
    listen 443 ssl http2;
    server_name backup-prod-2.example.com;

    ssl_certificate     /etc/letsencrypt/live/backup-prod-2.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/backup-prod-2.example.com/privkey.pem;

    client_max_body_size    600m;
    proxy_request_buffering off;
    proxy_read_timeout      300s;

    location / {
        proxy_pass http://127.0.0.1:8586;
    }
}

# Serveur staging
server {
    listen 443 ssl http2;
    server_name backup-staging.example.com;

    ssl_certificate     /etc/letsencrypt/live/backup-staging.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/backup-staging.example.com/privkey.pem;

    client_max_body_size    600m;
    proxy_request_buffering off;

    location / {
        proxy_pass http://127.0.0.1:8587;
    }
}

3. Serveur source

3.1 1. Installer Vykar

wget https://github.com/borgbase/vykar/releases/download/v0.12.1/vykar-v0.12.1-x86_64-unknown-linux-gnu.tar.gz
tar xzf vykar-v0.12.1-x86_64-unknown-linux-gnu.tar.gz
sudo mv vykar /usr/local/bin/

# Permissions de lecture sans root complet (optionnel)
sudo setcap cap_dac_read_search+ep /usr/local/bin/vykar

3.2 2. Configuration Vykar

Fichier de configuration — /etc/vykar/vykar.yaml
repositories:
  - label: "backup-principal"
    url: "https://backup.example.com"
    access_token: "votre-token-secret-long"

encryption:
  mode: "auto"

compression:
  algorithm: lz4

limits:
  threads: 2
  nice: 19
  upload_mib_per_sec: 50

schedule:
  enabled: true
  every: "24h"        # ou cron : "0 2 * * *"

sources:

  # Fichiers web
  - label: "www"
    path: /var/www/.zfs/snapshot/vykar-tmp
    hooks:
      before: "zfs snapshot tank/www@vykar-tmp"
      after:  "zfs destroy tank/www@vykar-tmp"
    retention:
      keep_daily: 7
      keep_weekly: 4
      keep_monthly: 6

  # Base de données MySQL (dump streamé)
  - label: "mysql"
    command_dumps:
      - name: "all.dump"
        command: "mysqldump -u root -p\"$MYSQL_ROOT_PASSWORD\" --all-databases"
    retention:
      keep_hourly: 12
      keep_daily: 30
      keep_weekly: 12
      keep_monthly: 12

  # Données applicatives
  - label: "data"
    path: /var/data/.zfs/snapshot/vykar-tmp
    hooks:
      before: "zfs snapshot tank/data@vykar-tmp"
      after:  "zfs destroy tank/data@vykar-tmp"
    retention:
      keep_daily: 14
      keep_weekly: 8

  # Configuration système
  - label: "config"
    path: "/etc"
    retention:
      keep_daily: 30
      keep_monthly: 24

hooks:
  after_backup: |
    {
      echo "Serveur  : $(hostname)"
      echo "Date     : $(date)"
      echo "Statut   : ✅ Succès"
      echo ""
      vykar list | tail -10
    } | msmtp -a "Subject: ✅ Backup OK [$(hostname)]" admin@example.com

  failed: |
    {
      echo "Serveur  : $(hostname)"
      echo "Date     : $(date)"
      echo "Statut   : ⚠️ ÉCHEC"
      echo ""
      echo "Vérifiez les logs : journalctl -u vykar-backup"
    } | msmtp -a "Subject: ⚠️ Backup ÉCHOUÉ [$(hostname)]" admin@example.com

3.3 3. Initialisation et premier backup

# Initialiser le dépôt distant (une seule fois)
vykar { .ini .copy }t --config /etc/vykar/vykar.yaml

# Tester le premier backup manuellement
vykar backup --config /etc/vykar/vykar.yaml

# Vérifier les snapshots créés
vykar list --config /etc/vykar/vykar.yaml

3.4 4. Automatisation via systemd

Service — /etc/systemd/system/vykar-backup.service
[Unit]
Description=Vykar Backup
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/vykar backup --config /etc/vykar/vykar.yaml
User=root
StandardOutput=journal
StandardError=journal
Timer — /etc/systemd/system/vykar-backup.timer
[Unit]
Description=Vykar Backup quotidien

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target
Activer le timer
sudo systemctl enable --now vykar-backup.timer

# Vérifier le timer
sudo systemctl list-timers vykar-backup.timer

4. Commandes utiles

  • tip "Lister et inspecter les snapshots
# Lister les snapshots
vykar list

# Inspecter le contenu d'un snapshot
vykar snapshot list latest
vykar snapshot list a1b2c3d4

# Chercher un fichier dans les 7 derniers jours
vykar snapshot find --name '*.conf' --since 7d
  • Restaurer et monter
# Restaurer le dernier snapshot
vykar restore latest /tmp/restauration

# Restaurer un snapshot précis
vykar restore a1b2c3d4 /tmp/restauration

# Monter un snapshot en lecture seule (WebDAV)
vykar mount latest /mnt/snapshot
umount /mnt/snapshot
  • Vérifier l'intégrité et libérer de l'espace
# Vérifier l'intégrité du dépôt
vykar check
vykar check --verify-data   # plus complet, plus long

# Libérer l'espace manuellement
vykar prune
vykar compact

# Santé du serveur REST
curl https://backup.example.com/health

5. Sécurité

Points d'attention

  • Vykar tourne en root sur la source pour lire tous les fichiers localement
  • backupuser/vykar sur le serveur de destination a des droits limités à /var/lib/vykar
  • Le mode append-only empêche toute suppression ou écrasement des données depuis le client
  • Les données sont chiffrées côté client — le serveur ne voit que des blobs opaques
  • Pensez à sauvegarder la passphrase de chiffrement dans un endroit sûr séparé (gestionnaire de mots de passe, coffre-fort physique)

6. Annexes

Stack applicative à sauvegarder — compose.yml
services:
  app:
    image: monapp:latest
    volumes:
      - app-data:/var/www/html

  postgres:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - pg-data:/var/lib/postgresql/data

  redis:
    image: redis:7
    volumes:
      - redis-data:/data

volumes:
  app-data:
  pg-data:
  redis-data:
Configuration Vykar pour stack Docker — vykar.yaml
repositories:
  - label: "backup-distant"
    url: "https://backup.example.com"
    access_token: "votre-token"

sources:
  # App — snapshot ZFS direct (fichiers statiques, cohérence non critique)
  - label: "app-data"
    path: /var/lib/docker/volumes/app-data/_data/.zfs/snapshot/vykar-tmp
    hooks:
      before: "zfs snapshot tank/docker-volumes@vykar-tmp"
      after:  "zfs destroy tank/docker-volumes@vykar-tmp"
    retention:
      keep_daily: 7
      keep_weekly: 4

  # PostgreSQL — dump cohérent via docker exec
  - label: "postgres"
    command_dumps:
      - name: "all.dump"
        command: "docker exec postgres pg_dumpall -U postgres"
    retention:
      keep_hourly: 12
      keep_daily: 30
      keep_weekly: 12
      keep_monthly: 6

  # Redis — save + lecture du fichier
  - label: "redis"
    command_dumps:
      - name: "dump.rdb"
        command: |
          docker exec redis redis-cli SAVE &&
          docker exec redis cat /data/dump.rdb
    retention:
      keep_daily: 7
      keep_weekly: 4

hooks:
  after_backup: |
    {
      echo "Serveur  : $(hostname)"
      echo "Date     : $(date)"
      echo "Statut   : ✅ Succès"
      echo ""
      vykar list | tail -10
    } | msmtp -a "Subject: ✅ Backup OK [$(hostname)]" admin@example.com

  failed: |
    {
      echo "Serveur  : $(hostname)"
      echo "Date     : $(date)"
      echo "Statut   : ⚠️ ÉCHEC"
      echo ""
      echo "Vérifiez les logs : journalctl -u vykar-backup"
    } | msmtp -a "Subject: ⚠️ Backup ÉCHOUÉ [$(hostname)]" admin@example.com
Configuration msmtp — /etc/msmtprc
# Installer msmtp
sudo apt install msmtp msmtp-mta

# Configurer /etc/msmtprc
sudo tee /etc/msmtprc << 'EOF'
defaults
auth           on
tls            on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile        /var/log/msmtp.log

account        smtp-principal
host           smtp.gmail.com        # ou smtp.ovh.net, smtp.ionos.fr...
port           587
from           backup@example.com
user           backup@example.com
password       votre-mot-de-passe-app

account default : smtp-principal
EOF

sudo chmod 600 /etc/msmtprc

# Test
echo "Test backup" | msmtp admin@example.com
Restauration des données
# PostgreSQL
vykar restore latest /tmp/restauration
docker exec -i mon-postgres \
  psql -U postgres < /tmp/restauration/all.dump

# MySQL
docker exec -i mon-mysql \
  mysql -u root -p"${MYSQL_ROOT_PASSWORD}" \
  < /tmp/restauration/all.sql

# MongoDB
cat /tmp/restauration/all.archive.gz | \
  docker exec -i mon-mongodb \
  mongorestore --archive --gzip

# Redis
docker cp /tmp/restauration/dump.rdb mon-redis:/data/dump.rdb
docker restart mon-redis
Déploiement Docker — docker-compose.yml
services:
  vykar:
    image: ghcr.io/borgbase/vykar:latest
    hostname: my-server
    restart: unless-stopped
    environment:
      - VYKAR_PASSPHRASE=${VYKAR_PASSPHRASE}
      - TZ=UTC
    volumes:
      - ./vykar.yaml:/etc/vykar/config.yaml:ro
      - /home/user/documents:/data/documents:ro
      - ./vykar-cache:/cache
volumes:
  vykar-cache:

7. Documentation