
Pri väčšom množstve Docker služieb a Linux serverov som potreboval vytvoriť jednotný spôsob zálohovania na lokálny Synology NAS.
Cieľom bolo vytvoriť riešenie, ktoré:
- automaticky zálohuje Linux server,
- používa šifrované Restic repository,
- ukladá dáta na Synology NAS cez NFS,
- vytvára konzistentné dumpy databáz,
- používa deduplikáciu,
- automaticky maže staré snapshoty,
- spúšťa sa cez systemd timer,
- po dokončení odošle e-mail
BACKUP OKaleboBACKUP FAILED.
Použitá retention politika:
7 denných snapshotov
4 týždenné snapshoty
6 mesačných snapshotov
Čo budeme potrebovať?
Linux server
Synology NAS
NFS
Restic
systemd
msmtp
SMTP server
V tomto návode budeme používať ukážkové hodnoty:
Linux server: 192.0.2.10
Synology NAS: 192.0.2.20
NAS share:
/volume1/NetBackup
Lokálny mount:
/mnt/nas-backup
Restic repository:
/mnt/nas-backup/BACKUP/server01/restic
Reálne IP adresy a názvy si samozrejme nahraďte vlastnými.
Príprava Synology NAS
Na Synology vytvoríme zdieľaný priečinok, napríklad:
NetBackup
Výsledná cesta môže byť:
/volume1/NetBackup
Pre daný Linux server následne povolíme NFS prístup.
Odporúčam povoliť prístup iba konkrétnej IP adrese alebo subnetu, z ktorého sa bude backup vykonávať.
Pripojenie NAS cez NFS
Na Linux serveri vytvoríme mount point:
sudo mkdir -p /mnt/nas-backup
Nainštalujeme NFS klienta:
sudo apt update
sudo apt install nfs-common
Do:
sudo nano /etc/fstab
Pridáme:
192.0.2.20:/volume1/NetBackup /mnt/nas-backup nfs4 rw,vers=4.1,_netdev,nofail,x-systemd.automount 0 0
Aplikujeme:
sudo systemctl daemon-reload
Mount môžeme aktivovať napríklad:
ls /mnt/nas-backup
Kontrola:
mountpoint /mnt/nas-backup
Správny výsledok:
/mnt/nas-backup is a mountpoint
Inštalácia Restic
Na Ubuntu:
sudo apt update
sudo apt install restic
Verziu skontrolujeme:
restic version
Vytvorenie Restic hesla
Najprv vytvoríme adresár:
sudo mkdir -p /root/.config/restic
sudo chmod 700 /root/.config/restic
Vygenerujeme silné náhodné heslo:
openssl rand -base64 48
Výsledné heslo uložíme:
sudo nano /root/.config/restic/server01.pass
Nastavíme práva:
sudo chmod 600 /root/.config/restic/server01.pass
Toto heslo je kritické. Bez neho nie je možné Restic repository obnoviť.
Je preto potrebné uložiť jeho kópiu aj mimo samotného servera.
Vytvorenie Restic repository
Na NAS vytvoríme adresár:
sudo mkdir -p /mnt/nas-backup/BACKUP/server01/restic
Nastavíme heslo:
export RESTIC_PASSWORD_FILE=/root/.config/restic/server01.pass
A inicializujeme repository:
restic -r /mnt/nas-backup/BACKUP/server01/restic init
Prvý manuálny backup
Napríklad:
restic -r /mnt/nas-backup/BACKUP/server01/restic backup \
/etc \
/home \
--tag server01
Po úspešnom backupe Restic vytvorí nový snapshot.
Snapshoty zobrazíme:
restic -r /mnt/nas-backup/BACKUP/server01/restic snapshots
Ako Restic funguje
Restic nevytvára pri každom spustení kompletnú fyzickú kópiu všetkých dát.
Používa:
- snapshoty
- deduplikáciu
- kompresiu
- šifrovanie
Ak sa teda medzi dvoma backupmi väčšina súborov nezmenila, Restic znovu neuloží identické bloky dát.
Nový snapshot preto môže reprezentovať napríklad niekoľko GB dát, ale fyzicky do repository pribudne iba niekoľko MB.
Príklad:
processed 22000 files, 4.6 GiB
Added to repository: 25 MiB
Backup databáz
Databázový adresár by sme nemali jednoducho kopírovať počas behu databázového servera.
Pre MariaDB vytvoríme pred Restic snapshotom konzistentný SQL dump.
Príklad:
docker exec aplikacia-db sh -lc '
DUMP="$(command -v mariadb-dump || command -v mysqldump)"
"$DUMP" \
-u"$MYSQL_USER" \
-p"$MYSQL_PASSWORD" \
--single-transaction \
--quick \
"$MYSQL_DATABASE"
' | gzip -1 > /var/backups/aplikacia.sql.gz
Integritu gzip súboru môžeme skontrolovať:
gzip -t /var/backups/aplikacia.sql.gz
Ak príkaz nič nevypíše a skončí exit code 0, archív je v poriadku.
Automatický backup skript
Vytvoríme:
sudo nano /usr/local/sbin/backup-server01.sh
Príklad kompletného skriptu:
#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
REPO="/mnt/nas-backup/BACKUP/server01/restic"
PASSWORD_FILE="/root/.config/restic/server01.pass"
TAG="server01"
NAS="/mnt/nas-backup"
STAGE="/var/backups/server01"
LOCK_FILE="/run/lock/backup-server01.lock"
export RESTIC_PASSWORD_FILE="$PASSWORD_FILE"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
}
# Zabránenie súbežnému spusteniu
exec 9>"$LOCK_FILE"
if ! flock -n 9; then
log "ERROR: Backup už beží."
exit 1
fi
# Kontrola Restic hesla
if [[ ! -r "$PASSWORD_FILE" ]]; then
log "ERROR: Restic password file neexistuje."
exit 1
fi
# Aktivácia systemd automountu
ls "$NAS" >/dev/null 2>&1 || true
# Kontrola NAS
if ! mountpoint -q "$NAS"; then
log "ERROR: NAS nie je pripojený."
exit 1
fi
# Kontrola repository
if [[ ! -d "$REPO" ]]; then
log "ERROR: Restic repository neexistuje."
exit 1
fi
mkdir -p "$STAGE"
chmod 700 "$STAGE"
log "=== Restic backup ==="
restic -r "$REPO" backup \
/etc \
/home \
"$STAGE" \
--exclude='/home/*/.cache/**' \
--tag "$TAG"
log "=== Retention ==="
restic -r "$REPO" forget \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
--group-by host,tags \
--tag "$TAG" \
--prune
log "============================================"
log "Backup úspešne dokončený."
log "============================================"
Nastavíme práva:
sudo chmod 750 /usr/local/sbin/backup-server01.sh
Syntax skontrolujeme:
sudo bash -n /usr/local/sbin/backup-server01.sh
Retention politika
V našom skripte používame:
restic -r "$REPO" forget \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
--group-by host,tags \
--tag "$TAG" \
--prune
To znamená:
7 posledných denných backupov
4 týždenné backupy
6 mesačných backupov
Parameter:
--prune
následne odstráni dátové bloky, ktoré už nepoužíva žiadny zachovaný snapshot.
Systemd service
Vytvoríme:
sudo nano /etc/systemd/system/backup-server01.service
Obsah:
[Unit]
Description=Restic backup SERVER01
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/backup-server01.sh
User=root
Group=root
Systemd timer
Vytvoríme:
sudo nano /etc/systemd/system/backup-server01.timer
Napríklad backup každý deň približne o 02:30:
[Unit]
Description=Daily Restic backup SERVER01
[Timer]
OnCalendar=*-*-* 02:30:00
RandomizedDelaySec=300
Persistent=true
[Install]
WantedBy=timers.target
Načítame konfiguráciu:
sudo systemctl daemon-reload
Timer aktivujeme:
sudo systemctl enable --now backup-server01.timer
Kontrola:
systemctl list-timers --all | grep backup-server01
Manuálny test
Service môžeme spustiť ručne:
sudo systemctl start backup-server01.service
Stav:
sudo systemctl status backup-server01.service
Log:
sudo journalctl -u backup-server01.service -n 100 --no-pager
E-mailové notifikácie
Na odosielanie informácie o stave backupu môžeme použiť msmtp.
Inštalácia:
sudo apt install msmtp msmtp-mta
Konfigurácia:
sudo nano /etc/msmtprc
Príklad:
defaults
auth on
tls on
tls_starttls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
account backup
host mail.example.com
port 587
from backup@example.com
user backup@example.com
passwordeval "cat /root/.config/msmtp/backup.pass"
account default : backup
Nastavíme:
sudo chmod 600 /etc/msmtprc
SMTP heslo:
sudo nano /root/.config/msmtp/backup.pass
Práva:
sudo chmod 600 /root/.config/msmtp/backup.pass
Test:
printf 'Subject: Backup test\n\nSMTP funguje.\n' \
| msmtp admin@example.com
Backup OK / FAILED e-mail
Do backup skriptu môžeme doplniť:
MAIL_TO="admin@example.com"
MAIL_FROM="backup@example.com"
SERVER_NAME="SERVER01"
send_backup_mail() {
local SUBJECT="$1"
local BODY="$2"
{
printf 'From: %s\n' "$MAIL_FROM"
printf 'To: %s\n' "$MAIL_TO"
printf 'Subject: %s\n' "$SUBJECT"
printf 'Date: %s\n' "$(date -R)"
printf 'MIME-Version: 1.0\n'
printf 'Content-Type: text/plain; charset=UTF-8\n'
printf '\n%s\n' "$BODY"
} | msmtp "$MAIL_TO"
}
A následne EXIT trap:
backup_exit_notification() {
local RC=$?
trap - EXIT
set +e
local HOST
local NOW
HOST="$(hostname -f 2>/dev/null || hostname)"
NOW="$(date '+%Y-%m-%d %H:%M:%S %Z')"
if [[ "$RC" -eq 0 ]]; then
send_backup_mail \
"[BACKUP OK] ${SERVER_NAME}" \
"Backup bol úspešne dokončený.
Server: ${SERVER_NAME}
Hostname: ${HOST}
Čas: ${NOW}
Status: SUCCESS"
else
send_backup_mail \
"[BACKUP FAILED] ${SERVER_NAME}" \
"Backup servera zlyhal.
Server: ${SERVER_NAME}
Hostname: ${HOST}
Čas: ${NOW}
Exit code: ${RC}"
fi
exit "$RC"
}
trap backup_exit_notification EXIT
Tak dostaneme po každom spustení napríklad:
[BACKUP OK] SERVER01
alebo:
[BACKUP FAILED] SERVER01
Kontrola posledného snapshotu
sudo env \
RESTIC_PASSWORD_FILE=/root/.config/restic/server01.pass \
restic \
-r /mnt/nas-backup/BACKUP/server01/restic \
snapshots \
--latest 1 \
--tag server01
Kontrola obsahu snapshotu
Najprv získame ID snapshotu:
restic -r "$REPO" snapshots
Napríklad:
ID Time Host
ef739d4d 2026-08-27 02:30 server01
Obsah:
restic -r "$REPO" ls ef739d4d
Vyhľadanie konkrétneho backupu:
restic -r "$REPO" ls ef739d4d \
| grep database.sql.gz
Obnova jednotlivého súboru
Napríklad:
mkdir -p /tmp/restic-restore
restic -r "$REPO" restore latest \
--target /tmp/restic-restore \
--include /etc/fstab
Výsledok bude napríklad:
/tmp/restic-restore/etc/fstab
Obnova celého snapshotu
restic -r "$REPO" restore ef739d4d \
--target /tmp/server-restore
Pred kopírovaním obnovených dát späť do produkčného systému je vhodné ich najprv skontrolovať.
Kontrola integrity Restic repository
Priebežne môžeme spustiť:
restic -r "$REPO" check
Dôkladnejšia kontrola dát:
restic -r "$REPO" check --read-data
Pri veľkom repository môže táto kontrola trvať výrazne dlhšie.
Príklad zálohovania Docker aplikácie
Pri Docker aplikácii je vhodné zálohovať:
docker-compose.yml
.env
databázový dump
persistentné volumes
aplikačné kľúče
SSL certifikáty
Príklad:
restic -r "$REPO" backup \
/var/backups/aplikacia \
/home/user/aplikacia \
/var/lib/docker/volumes/aplikacia_data/_data \
--tag server01
Ak /home/user/aplikacia/.env obsahuje heslá, nie je problém ho ukladať do Restic repository, pretože Restic dáta šifruje.
Samotné Restic heslo však musí byť uložené samostatne mimo repository.
Praktická štruktúra backupu
Výsledok môže vyzerať napríklad:
Synology NAS
│
└── NetBackup
│
└── BACKUP
│
├── server01
│ └── restic
│
├── server02
│ └── restic
│
└── server03
└── restic
Každý server má:
vlastné Restic repository
vlastné Restic heslo
vlastný tag
vlastný systemd timer
vlastný backup skript
Bezpečnostné odporúčania
Restic repository je šifrované, ale stále odporúčam:
NFS povoliť iba vybraným serverom
Restic heslo uložiť mimo servera
.env súbory chmod 600
backup skripty spúšťať ako root iba ak je to potrebné
DB heslá nevkladať priamo do verejných skriptov
pravidelne kontrolovať backup logy
testovať obnovu dát
Najdôležitejšie pravidlo je:
Backup, ktorý sme nikdy neskúsili obnoviť, ešte nemáme reálne overený.
Záver
Výsledkom je plne automatizovaný backup systém:
Linux server
↓
databázové dumpy
↓
Restic
↓
šifrovanie + deduplikácia
↓
NFS
↓
Synology NAS
↓
retention + prune
↓
e-mail OK / FAILED
Takto je možné relatívne jednoducho zálohovať viac Linux serverov a Docker aplikácií do jedného NAS zariadenia, pričom každý server zostáva oddelený vlastným repository a vlastným šifrovacím heslom.
Reálny príklad – FreeIPA + BookStack + Jellyfin
Nasledujúci príklad vychádza z reálneho nasadenia, kde jeden Linux server prevádzkuje viac služieb naraz.
Pred vytvorením Restic snapshotu skript:
FreeIPA
→ vytvorí natívny ipa-backup
→ skontroluje stav FreeIPA služieb
BookStack
→ vytvorí konzistentný MariaDB dump
→ skontroluje integritu gzip
→ porovná počet tabuliek
→ nájde aktuálny /config Docker volume
Jellyfin
→ zálohuje aplikačné dáta
→ vynechá cache
Restic
→ vytvorí šifrovaný snapshot
→ aplikuje retention
→ vykoná prune
E-mail
→ pošle BACKUP OK alebo BACKUP FAILED
Kompletný backup skript
Vytvoríme:
sudo nano /usr/local/sbin/backup-server01.sh
Obsah:
#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
# ============================================================
# E-mail notification
# ============================================================
MAIL_TO="admin@example.com"
MAIL_FROM="backup@example.com"
SERVER_NAME="SERVER01"
NOTIFY_REPO="/mnt/nas-backup/BACKUP/server01/restic"
NOTIFY_RESTIC_PASS="/root/.config/restic/server01.pass"
NOTIFY_TAG="server01"
send_backup_mail() {
local SUBJECT="$1"
local BODY="$2"
{
printf 'From: %s\n' "$MAIL_FROM"
printf 'To: %s\n' "$MAIL_TO"
printf 'Subject: %s\n' "$SUBJECT"
printf 'Date: %s\n' "$(date -R)"
printf 'MIME-Version: 1.0\n'
printf 'Content-Type: text/plain; charset=UTF-8\n'
printf '\n%s\n' "$BODY"
} | msmtp "$MAIL_TO"
}
backup_exit_notification() {
local RC=$?
trap - EXIT
set +e
local HOST
local NOW
local LATEST
HOST="$(hostname -f 2>/dev/null || hostname)"
NOW="$(date '+%Y-%m-%d %H:%M:%S %Z')"
if [[ "$RC" -eq 0 ]]; then
LATEST="$(
RESTIC_PASSWORD_FILE="$NOTIFY_RESTIC_PASS" \
restic -r "$NOTIFY_REPO" snapshots \
--latest 1 \
--tag "$NOTIFY_TAG" \
--compact 2>/dev/null
)"
send_backup_mail \
"[BACKUP OK] ${SERVER_NAME}" \
"Backup bol uspesne dokonceny.
Server: ${SERVER_NAME}
Hostname: ${HOST}
Cas: ${NOW}
Status: SUCCESS
Posledny Restic snapshot:
${LATEST}
Repository:
${NOTIFY_REPO}"
else
send_backup_mail \
"[BACKUP FAILED] ${SERVER_NAME}" \
"Backup servera ZLYHAL.
Server: ${SERVER_NAME}
Hostname: ${HOST}
Cas: ${NOW}
Exit code: ${RC}
Skontroluj:
systemctl status backup-server01.service
journalctl -u backup-server01.service -n 100 --no-pager"
fi
exit "$RC"
}
trap backup_exit_notification EXIT
# ============================================================
# Základná konfigurácia
# ============================================================
LOCK_FILE="/run/lock/backup-server01.lock"
NAS="/mnt/nas-backup"
REPO="${NAS}/BACKUP/server01/restic"
PASSWORD_FILE="/root/.config/restic/server01.pass"
TAG="server01"
FREEIPA_STAGE="/var/backups/server01/freeipa"
BOOKSTACK_STAGE="/var/backups/server01/bookstack"
FREEIPA_CONTAINER="freeipa-server"
BOOKSTACK_CONTAINER="bookstack"
BOOKSTACK_DB_CONTAINER="bookstack-db"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
}
# ============================================================
# Zabránenie súbežnému spusteniu
# ============================================================
exec 9>"$LOCK_FILE"
if ! flock -n 9; then
log "ERROR: Backup už beží."
exit 1
fi
# ============================================================
# Kontrola Restic hesla
# ============================================================
if [[ ! -r "$PASSWORD_FILE" ]]; then
log "ERROR: Restic password file neexistuje alebo nie je čitateľný."
exit 1
fi
# ============================================================
# Aktivácia systemd NFS automountu
# ============================================================
ls "$NAS" >/dev/null 2>&1 || true
# ============================================================
# Kontrola NAS
# ============================================================
if ! mountpoint -q "$NAS"; then
log "ERROR: NAS nie je pripojený na $NAS."
exit 1
fi
# ============================================================
# Kontrola repository
# ============================================================
if [[ ! -d "$REPO" ]]; then
log "ERROR: Restic repository neexistuje: $REPO"
exit 1
fi
# ============================================================
# Príprava staging adresárov
# ============================================================
mkdir -p "$FREEIPA_STAGE"
mkdir -p "$BOOKSTACK_STAGE"
chmod 700 "$FREEIPA_STAGE"
chmod 700 "$BOOKSTACK_STAGE"
export RESTIC_PASSWORD_FILE="$PASSWORD_FILE"
# ============================================================
# 1. FreeIPA native backup
# ============================================================
log "=== FreeIPA native backup ==="
docker exec "$FREEIPA_CONTAINER" ipa-backup
log "Kontrola FreeIPA služieb..."
docker exec "$FREEIPA_CONTAINER" ipactl status
LATEST_IPA_BACKUP="$(
docker exec "$FREEIPA_CONTAINER" bash -lc \
'ls -1dt /var/lib/ipa/backup/ipa-full-* 2>/dev/null | head -n1'
)"
if [[ -z "$LATEST_IPA_BACKUP" ]]; then
log "ERROR: Nenašiel sa FreeIPA backup."
exit 1
fi
IPA_BACKUP_NAME="$(basename "$LATEST_IPA_BACKUP")"
log "Kopírujem $IPA_BACKUP_NAME na hosta..."
rm -rf "${FREEIPA_STAGE:?}/${IPA_BACKUP_NAME}"
docker cp \
"${FREEIPA_CONTAINER}:${LATEST_IPA_BACKUP}" \
"${FREEIPA_STAGE}/"
if [[ ! -f "${FREEIPA_STAGE}/${IPA_BACKUP_NAME}/ipa-full.tar" ]]; then
log "ERROR: ipa-full.tar nebol skopírovaný."
exit 1
fi
log "FreeIPA backup pripravený: ${FREEIPA_STAGE}/${IPA_BACKUP_NAME}"
# ============================================================
# 2. BookStack MariaDB backup
# ============================================================
log "=== BookStack MariaDB backup ==="
BOOKSTACK_TMP="${BOOKSTACK_STAGE}/bookstack.sql.gz.tmp"
BOOKSTACK_FINAL="${BOOKSTACK_STAGE}/bookstack.sql.gz"
rm -f "$BOOKSTACK_TMP"
docker exec "$BOOKSTACK_DB_CONTAINER" sh -lc '
if command -v mariadb-dump >/dev/null 2>&1; then
DUMP=mariadb-dump
else
DUMP=mysqldump
fi
"$DUMP" \
-u"$MYSQL_USER" \
-p"$MYSQL_PASSWORD" \
--single-transaction \
--quick \
--skip-lock-tables \
"$MYSQL_DATABASE"
' | gzip -1 > "$BOOKSTACK_TMP"
# ============================================================
# Kontrola gzip integrity
# ============================================================
gzip -t "$BOOKSTACK_TMP"
# ============================================================
# Počet tabuliek v živej DB
# ============================================================
DB_TABLES="$(
docker exec "$BOOKSTACK_DB_CONTAINER" sh -lc '
mariadb \
-u"$MYSQL_USER" \
-p"$MYSQL_PASSWORD" \
"$MYSQL_DATABASE" \
-Nse "SHOW TABLES;" | wc -l
'
)"
# ============================================================
# Počet tabuliek v SQL dumpe
# ============================================================
DUMP_TABLES="$(
gzip -dc "$BOOKSTACK_TMP" |
grep -c '^CREATE TABLE' || true
)"
log "BookStack DB tabuliek: $DB_TABLES"
log "BookStack dump tabuliek: $DUMP_TABLES"
if [[ "$DB_TABLES" -lt 1 ]]; then
log "ERROR: BookStack databáza nemá žiadne tabuľky."
exit 1
fi
if [[ "$DUMP_TABLES" -ne "$DB_TABLES" ]]; then
log "ERROR: Počet tabuliek v dumpe nesedí s databázou."
exit 1
fi
mv "$BOOKSTACK_TMP" "$BOOKSTACK_FINAL"
log "BookStack SQL backup OK."
# ============================================================
# 3. Zistenie aktuálneho BookStack /config volume
# ============================================================
BOOKSTACK_CONFIG="$(
docker inspect "$BOOKSTACK_CONTAINER" \
--format '{{range .Mounts}}{{if eq .Destination "/config"}}{{.Source}}{{end}}{{end}}'
)"
if [[ -z "$BOOKSTACK_CONFIG" || ! -d "$BOOKSTACK_CONFIG" ]]; then
log "ERROR: BookStack /config volume sa nepodarilo nájsť."
exit 1
fi
log "BookStack config: $BOOKSTACK_CONFIG"
# ============================================================
# 4. Restic backup
# ============================================================
log "=== Restic backup ==="
restic -r "$REPO" backup \
/var/backups/server01 \
/home/user/freeipa-docker \
/home/user/bookstack \
"$BOOKSTACK_CONFIG" \
/home/user/jellyfin \
/etc/fstab \
--exclude='/home/user/jellyfin/cache/**' \
--tag "$TAG"
# ============================================================
# 5. Retention
# ============================================================
log "=== Restic retention ==="
restic -r "$REPO" forget \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
--group-by host,tags \
--tag "$TAG" \
--prune
# ============================================================
# 6. Cleanup lokálnych FreeIPA backupov
# ponecháme posledné 2
# ============================================================
log "=== Cleanup starých FreeIPA staging backupov ==="
mapfile -t OLD_LOCAL < <(
find "$FREEIPA_STAGE" \
-mindepth 1 \
-maxdepth 1 \
-type d \
-name 'ipa-full-*' \
-printf '%T@ %p\n' |
sort -nr |
tail -n +3 |
cut -d' ' -f2-
)
for DIR in "${OLD_LOCAL[@]}"; do
log "Odstraňujem lokálny staging: $DIR"
rm -rf -- "$DIR"
done
# ============================================================
# Cleanup backupov priamo vo FreeIPA kontajneri
# ponecháme posledné 2
# ============================================================
docker exec "$FREEIPA_CONTAINER" bash -lc '
ls -1dt /var/lib/ipa/backup/ipa-full-* 2>/dev/null |
tail -n +3 |
xargs -r rm -rf --
'
log "============================================"
log "Backup SERVER01 úspešne dokončený."
log "============================================"
Nastavíme práva:
sudo chmod 750 /usr/local/sbin/backup-server01.sh
Pred prvým spustením skontrolujeme syntax:
sudo bash -n /usr/local/sbin/backup-server01.sh \
&& echo "SCRIPT OK"
Správny výsledok:
SCRIPT OK
Čo tento skript reálne zálohuje
Výsledný Restic snapshot obsahuje napríklad:
/var/backups/server01
│
├── freeipa
│ └── ipa-full-YYYY-MM-DD-HH-MM-SS
│ └── ipa-full.tar
│
└── bookstack
└── bookstack.sql.gz
/home/user/freeipa-docker
/home/user/bookstack
├── docker-compose.yml
└── .env
BookStack /config Docker volume
/home/user/jellyfin
/etc/fstab
Súbor:
/home/user/bookstack/.env
môže obsahovať napríklad:
APP_KEY
databázové heslá
Jeho zálohovanie do Restic repository je v poriadku, pretože obsah repository je šifrovaný.
Restic heslo samotné však nesmie byť uložené iba v tomto repository.
Prečo používame SQL dump databázy
Pri MariaDB nekopírujeme iba živý databázový adresár.
Pred Restic snapshotom používame:
mariadb-dump \
--single-transaction \
--quick \
--skip-lock-tables
Výsledkom je konzistentný SQL dump:
bookstack.sql.gz
Skript následne skontroluje:
gzip integritu
počet tabuliek v databáze
počet tabuliek v dumpe
Ak napríklad databáza obsahuje:
41 tabuliek
a dump takisto:
41 tabuliek
skript pokračuje.
Ak čísla nesedia, celý backup skončí chybou a nevytvorí sa falošne úspešný snapshot.
Automatické vyhľadanie Docker volume
Namiesto zapisovania dlhého Docker volume ID priamo do skriptu:
/var/lib/docker/volumes/xxxxxxxxxxxx/_data
sa aktuálna cesta zisťuje automaticky:
docker inspect bookstack \
--format '{{range .Mounts}}{{if eq .Destination "/config"}}{{.Source}}{{end}}{{end}}'
Takto skript nájde aktuálny /config aj v prípade, že sa názov alebo interné ID volume zmení.
Retention
Po úspešnom vytvorení snapshotu:
restic forget \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
--prune
zostáva:
7 denných snapshotov
4 týždenné snapshoty
6 mesačných snapshotov
Restic následne pomocou:
--prune
odstráni dátové bloky, ktoré už nepotrebuje žiadny existujúci snapshot.
Cleanup FreeIPA backupov
ipa-backup vytvára lokálne zálohy aj priamo vo FreeIPA kontajneri.
Aby časom nezaplnili disk, skript ponecháva iba:
2 posledné FreeIPA native backupy
Staršie sú odstránené až po úspešnom Restic backupe.
To znamená, že dlhodobú históriu už zabezpečuje Restic repository na NAS.
Výsledok
Celý proces vyzerá:
FreeIPA
↓
ipa-backup
↓
FreeIPA native archive
│
│
BookStack
↓
MariaDB dump
↓
kontrola integrity
│
│
Docker /config
│
│
Jellyfin
│
↓
RESTIC
↓
šifrovanie
↓
deduplikácia
↓
Synology NAS
↓
retention
↓
prune
↓
BACKUP OK / FAILED e-mail
