Skip to main content

Warum BorgBackup

Weil BorgBackup ein vom Betriebssystem unabhängiges, Open-Source (BSD) Backup-System ist, welches sehr effizient, verschlüsselt und performant, deduplizierende Backups erstellen kann. Nebenher gibt es noch unzählige Einstellungsoptionen, Borg wird kräftig weiterentwickelt und die Dokumentation ist aller erste Sahne.

Warum Borgmatic

Weil man hiermit BorgBackup um einiges leichter, schicker und schneller steuern kann. Es ist auch möglich geschwind verschiedene Backup-Profile anzulegen, die dann nur bestimmte Applikationen wie z. B. den Webserver oder die Datenbank absichern.

Ausgangsszenario

Für dieses derbe Unterfangen nehme ich einen bei Netcup schuftenden Ubuntu Webserver (RS 4000 G9) und peitsche das Backup über eine freshe SSH-Verbindung direkt auf meinen Hetzner Backup-Server (AX51).

Vorgaben

# Achtung Ficktive Daten :)
# Backup-Programme: BorgBackup und Borgmatic
# Backup-Patient: Ubuntu-20.04 Webserver (IP: 91.200.90.200 | hostname: betzi.true-og.de)
# Backup-Server: Ubuntu-20.04 Fileserver (IP: 95.100.70.100 | hostname: fillissima.true-og.de)

# Backup-Patient Ordnerstruktur:
- /root/server-scripts/borg/ # Mysql Backupskript
- /data/backups/db/ # Mysql Backupverzeichnis
- /var/log/borg/ # BorgBackup/Mysql Logfileverzeichnis
- /data/backups/borg/restore/$(hostname -f) # Ordner für den Backup-Restore
- /mnt/backups/borg/$(hostname -f) # Ordner für den Mount eines Backups

# Backup-Server Ordnerstruktur:
- /data/backups/borg/$(hostname -f) # BorgBackup Silo

Installation und Konfiguration

Installation BorgBackup

# Auf Webserver und Backupserver ausführen
apt install software-properties-common zstd
add-apt-repository ppa:costamagnagianfranco/borgbackup
aptitude update && aptitude install borgbackup liblz4-tool

Installation Borgmatic

# Borgmatic über Python Pip (da aktueller). Nur auf dem Webserver installieren!
apt install python3-pip python3-setuptools
pip3 install --upgrade pip
pip3 install --upgrade borgmatic

Ordnerstruktur auf dem Webserver anlegen

# Ordner für die Borgbackup-Skripte erstellen
mkdir -p /root/server-scripts/borg

# Ordner für die Datenbank Backups erstellen
mkdir -p /data/backups/db

# BorgBackup Logfile-Ordner erstellen
mkdir -p /var/log/borg

# BorgBackup Restore-Ordner erstellen
mkdir -p /data/backups/borg/restore

# Berechtigung setzen
find /root -type d | xargs -I {} chmod -v 700 {} && find /root/ -type f | xargs -I {} chmod -v 600 {}
find /data/backups -maxdepth 1 -type d | xargs -I {} chmod -v 700 {}

Ordnerstruktur auf dem Backupserver anlegen

# Ordner für die Borgbackups erstellen
mkdir -p /data/backups/borg/betzi.true-og.de

# Berechtigung setzen
find /data/backups -type d | xargs -I {} chmod -v 700 {}

SSH-Key auf dem Webserver erstellen

# Superstabilen SSH-Key mit elliptischen Kurven für die Übertragung auf dem Backupserver erstellen
ssh-keygen -t ed25519 -o -a 100 -C "$(whoami)@$(hostname)-borg-$(date -I)" -f ~/.ssh/borg_id_ed25519

# Den superstabilen SSH-Key auf den Backupserver (fillissima.true-og.de) übertragen
ssh-copy-id -i ~/.ssh/borg_id_ed25519.pub root@fillissima.true-og.de:33220

SSH-Berechtigung auf dem Backupserver anpassen

Damit man mit dem erstellten SSH-Key des Webservers keinen Schabernack auf dem Backupserver treiben kann, wird auf dem Backupserver die authorized_keys so angepasst, dass nur das Borgbackup-Kommando zum Managen der Backups erlaubt ist und das dafür vorgesehene Backupverzeichnis.

# /root/.ssh/authorized_keys
command="borg serve --restrict-to-path /data/backups/borg/betzi.true-og.de" ssh-ed25519 AAAAC3Nz@C3lZDI1NTVE5ABLAIT.LWNcF3A77CrjdJY/oPpEd2IpZKmP7s5mQ7zrlTgmxT5 root@betzi.true-og.de-borg-2020-12-30

Borgmatic konfigurieren

In der Borgmatic-Konfiguration config.yaml, sollte man zumindest bei „repositories“ die IP-Adresse des Backupservers, die zu sichernden „source_directories„-Ordner, die zu exkludierenden Verzeichnisse (exclude_patterns), die Hooks und unter „storage“ den „encryption_passphrase“ anpassen.

Borgmatic-Konfiguration generieren:

generate-borgmatic-config

Inhalt Borgmatic-Konfiguration:

# Borgmatic config.yaml
location:

    # Repository Pfad
    repositories:
        - root@95.100.70.100:/data/backups/borg/{fqdn}
        - root@99.100.70.100:/data/backups/borg/{fqdn} # Zusätzlicher Backup-Server wenn vorhanden

    # Backup Sources
    source_directories:
        - /etc
        - /usr
        - /opt
        - /srv
        - /var
        - /root
        - /home

    # Exclude Sources
    exclude_patterns:
        - /run
        - /sys
        - /dev
        - /tmp
        - /mnt
        - /proc
        - /var/run
        - /lost+found
        - /var/lib/lxcfs
        - /var/spool/dma
        - /data/backups/borg
    exclude_caches: true

# Repository-Optionen
storage:
    compression: auto,zstd # lz4 wenn zstd nicht vorhanden
    ssh_command: ssh -i /root/.ssh/borg_id_ed25519 -p 33220
    relocated_repo_access_is_ok: true
    archive_name_format: '{fqdn}-{now:%Y-%m-%d_%H-%M}'
    encryption_passphrase: "zum-g0ld3nen.Spu<kn@pF!_"

# Aufbewahrungszeitraum
retention:
    keep_daily: 7
    keep_weekly: 4
    keep_monthly: 6
    prefix: '{fqdn}-'

# Backup-Validierung
consistency:
    checks:
        - repository
        - archives
    check_last: 1
    prefix: '{fqdn}-'

# Farblicher Terminal output
output:
    color: true

# Aktionen
hooks:
    before_backup:
        - echo "Das geile Borgmatic-Backup ist soeben gestartet:"
        - ping -q -c 1 95.100.70.100 > /dev/null || exit 75
        - /root/server-scripts/borg/borgbackup_db.sh

    before_prune:
        - echo "Starting pruning: Mama wäre stolz auf dich."

    before_check:
        - echo "Starting Backup checks:"

    after_backup:
        - echo "Das sagenumwobene Borgmatic-Backup haben fertig. Fetter Respect dude!."

    after_prune:
        - echo "Finished pruning. Sauwa."

    after_check:
        - echo "Finished checks du krasser Checker."

    on_error:
        - echo "Irgendetwas ist derbe abgekackt ;("
    
    # Berechtigung
    umask: 0077

Borgmatic Konfiguration validieren und Backupverzeichnis initialisieren

Die Validierung checkt die Borgmatic-Konfiguration auf Syntaxfehler durch und bei dem „borgmatic ini“-Befehl müsst ihr dann für das Backup-Repository (hier betzi.true-og.de) das hoffentlich ultrafiese Passwort aus der Borgmatic- Konfiguration (hier encryption_passphrase: zum-g0ld3nen.Spu<kn@pF!_) eingeben.

validate-borgmatic-config
borgmatic init --encryption repokey-blake2

Mysql Datenbank Backupskript

Mit diesem duften Mysql Backupskript werden die Datenbanken einmal in separaten SQL-Files gespeichert und danach noch mal alle Datenbanken in ein einzelnes SQL-File geballert, damit man bei einem Datenmalheur je nach Situation trotzdem schön geschmeidig bleiben kann. PS: Das Mysql-Backupskript kann man auch sehr schön von BorgBackup enkoppelt als Standalone-Backupskript benutzen.

#==========================================================
#!/usr/bin/env bash
# Autor: Hackspoiler
# Version: 0.9
# Shellcheck: True
# Datum: 29.01.2020
# Modifizierung: 17.02.2024
# URL: https://hackspoiler.de
# Skriptname: borgbackup_db.sh
# Skriptpfad: /root/server-scripts/borg
# Beschreibung: DBs werden in separate SQL-Files eingetütet plus alles zusammen in ein SQL-File. DB-Passwort wird aus .mylogin.cnf gezogen
#==========================================================

# Check for root permissions
if [[ "$(id -u)" -ne 0 ]]; then
  echo "Requires root permissions" > /dev/stderr
  exit 1
fi

# Set Bash-Defaults
set -o nounset  # Beenden, falls ein ungesetzter Variablenname verwendet wird
set -o pipefail # Beenden, falls eine Pipeline fehlschlägt
 
# Set Variables
USER="root"
RM="$(which rm)"
TEE="$(which tee)"
GREP="$(which grep)"
FIND="$(which find)"
XARGS="$(which xargs)"
MKDIR="$(which mkdir)"
MYSQL="$(which mysql)"
MYSQLDUMP="$(which mysqldump)"
COMPRESSION="gzip" #(bzip2|lz4|pigz|zstd)
COMPRESSION_TYPE="gz" #(bz2|lz4|zst)
LOG_DIRECTORY="/var/log/borg"
LOG_FILE="${LOGDIRECTORY}/mysql_db_dump.log"
TIMESTAMP=$(date +'%F-%H-%M-%S')
BACKUP_DIR="/var/backups/db"

## Logging starten
exec > >(tee --ignore-interrupts "${LOG_FILE}") 2>&1
 
# BACKUP_DIR + LOG_DIRECTORY erstellen
"${MKDIR}" --parents "${LOG_DIRECTORY}" "${BACKUP_DIR}/${TIMESTAMP}"
 
# Datenbanken älter als eine Stunde rasieren
"${FIND}" "${BACKUP_DIR}"/ -mindepth 1 -type d -mmin +60 -print0 | "${XARGS}" -0 -I {} "${RM}" -rf {}
  
# Datenbank-Backup starten
DATABASES=$("$MYSQL" --user="$USER" --batch --skip-column-names -e "SHOW DATABASES;" | "$GREP" -E -v '^mysql$|^sys$|*_schema$')
for DATABASE in ${DATABASES[@]}; do
    "${MYSQLDUMP}"                  \
    --user="${USER}"                \
    --force                         \
    --quote-names --dump-date       \
    --opt --single-transaction      \
    --events --routines --triggers  \
    --databases "${DATABASE}"       \
    --result-file="${BACKUP_DIR}/${TIMESTAMP}/${DATABASE}.sql"
    echo "Backup ${DATABASE} am ${TIMESTAMP} erstellt"
done

# Logging
[[ ${STATUS} == 0 ]] && printf "Task am %s erfolgreich in %s erstellt\n" "$(date +'%F-%H-%M-%S')" "${BACKUP_DIR}" || printf "Task am %s gefailed\n" "$(date +'%F-%H-%M-%S')"

# Backup der Datenbanken in ein ganzes, komprimiertes SQL-File
echo "Drop Full DB Backup"
"${MYSQLDUMP}" --user="${USER}" --all-databases --events --quick --routines --single-transaction --triggers | "${COMPRESSION}" > "${BACKUP_DIR}/${TIMESTAMP}/full_db.sql.${COMPRESSION_TYPE}"

Erstes Initiales Backup erstellen

borgmatic --verbosity 2 --log-file /var/log/borg/borgmatic.log

Backup verifizieren

borgmatic list
borgmatic info

Cronjob einrichten

# vim /etc/cron.d/borgmatic
# Jeden Tag um 01:00 Hur Nachts
0 1 * * * root /usr/local/bin/borgmatic --log-file /var/log/borg/borgmatic.log --syslog-verbosity 2

Logrotate einrichten

# Borgmatic Logrotate-Files (/etc/logrotate.d/borgmatic)
/var/log/borg/*.log
{
	rotate 4
	weekly
	missingok
	notifempty
	compress
	delaycompress
	sharedscripts
	postrotate
	invoke-rc.d rsyslog rotate >/dev/null 2>&1 || true
	endscript
}

Hier endet nun die komplette Installation und Konfiguration von BorgBackup und Borgmatic. Doch seid nicht traurig, im nächsten Abschnitt gibt es noch etwas zu den Themen „Backups wiederherstellen“ und „Backups manuell entfernen“.

Borgmatic Befehle

Backups wiederherstellen – Mount Version

# Alle vorhandenen Archive anzeigen
borgmatic list

# Zuletzt erstelles Backup-Archiv unter /mnt/backups/borg/$(hostname -f) mounten
borgmatic mount --archive latest --mount-point /mnt/backups/borg/$(hostname -f)

# Mount des angegebenen, kompletten Backups unter /mnt/backups/borg/$(hostname -f)
borgmatic mount --archive $ARCHIVE_NAME --mount-point /mnt/backups/borg/$(hostname -f)

# Nur einen speziellen Pfad des zuletzt erstellten Backups mounten
borgmatic mount --archive latest --mount-point /mnt/backups/borg/$(hostname -f) --path etc/apache2/

# Backup-Mounts wieder entmounten
borgmatic umount --mount-point /mnt/backups/borg/$(hostname -f)

Backups wiederherstellen – Extract Version

# Erstellen des Restore-Ordners
mkdir -p /data/backups/borg/restore/$(hostname -f)

# Vorhandene Backup-Archive anzeigen
borgmatic list

# Restore des aktuellsten kompletten Backups in das angegeben Restore-Verzeichnis
borgmatic extract --archive latest --destination /data/backups/borg/restore/$(hostname -f)

# Restore des angegebenen kompletten Backups in das Restore-Verzeichnis
borgmatic extract --archive $ARCHIVE_NAME --destination /data/backups/borg/restore/$(hostname -f)

# Restore der angegebenen Pfade (/etc und /usr) in das Restore-Verzeichnis
borgmatic extract --archive $ARCHIVE_NAME --destination /data/backups/borg/restore/$(hostname -f) --restore-path /etc/ /usr/

Backups entfernen

# Repository-Pfad setzen
REPOSITORY="root@95.100.70.100:/data/backups/borg/betzi.true-og.de"

# Alle vorhandenen Backups auflisten
borgmatic list

# Beispiel-Archiv
betzi.true-og.de-2021-01-21_22-55 Sun, 2021-02-21 22:55:15

# Gewünschtes Backup löschen
borg delete ${REPOSITORY}::'betzi.true-og.de-2021-01-21_22-55'

# Will man das ganze Repository endgültig entfernen (bei der Bestätigung "YES" groß schreiben!)
borg delete ${REPOSITORY}

Repository Passwort ändern

# Repository Pfad setzen
REPOSITORY="root@95.100.70.100:/data/backups/borg/betzi.true-og.de"
 
# Repository-Passwort ändern
borg key change-passphrase -v root@95.100.70.100:/data/backups/borg/betzi.true-og.de

Falls jemand Fragen, Anregungen  oder Verbesserungsvorschläge hat, schreibt mir einfach auf Mastodon.