Kategorien

TrueNAS Backup mit zrep

TrueNAS bietet zwar von sich aus eine Backup-Lösung an, allerdings geht die Initiierung des Backups immer vom Server mit den Daten aus, der dann zum Backup-Server repliziert. Aus Sicherheitsaspekten ist dies nicht optimal, denn wenn der Datenserver kompromittiert ist, besteht auch die Gefahr, dass der Backup-Server oder die Backups verändert werden. Aus diesem Grund habe ich mich dazu entschlossen, selbst eine Backup-Lösung mit zrep zu implementieren. Diese sieht folgendermaßen aus:

  1. Der Backup-Server greift über ssh auf den Datenserver zu. Dabei wird ein Benutzer verwendet, der nur eingeschränkte Rechte auf dem Daten- und Backupserver hat
  2. Der Backup-Server legt mit zrep einen Snapshot auf den zu sichernden ZFS Pools des Datenservers an und kopiert diese dann auf den ZFS Pool auf dem Backup-Server
  3. Der Backup-Server löscht in regelmäßigen Abständen nicht mehr benötigte Snapshots auf dem Backup-Server
  4. Der Daten-Server löscht in regelmäßigen Abständen nicht mehr benötigte Snapshots auf dem Daten-Server

In TrueNAS wird im GUI unter Storage/Pools zunächst ein Dataset für den Benutzer zsbackup (s für send) angelegt (hier: /mnt/data0/zsbackup) und dann der Benutzer:

Über die Shell geben wir dem Benutzer nun die erforderlichen Rechte, laden das zrep Skript herunter und machen es ausführbar

zfs allow -u zsbackup send,hold,snapshot,userprop data0
cd /mnt/data0/zsbackup
wget https://github.com/bolthole/zrep/raw/master/zrep
chmod +x zrep

Auf dem Backup-Server machen wir das analog:

und führen auch hier die folgenden Befehle aus:

zfs allow -u zrbackup create,mount,receive,userprop remote_backup
cd /mnt/remote_backup/zrbackup
wget https://github.com/bolthole/zrep/raw/master/zrep
chmod +x zrep

SSH-Keys erzeugen

Im nächsten Schritt müssen wir dafür sorgen, dass zrbackup sich auf dem Datenserver als zsbackup mittels ssh einloggen kann. Dazu erzeugen wir auf dem Backup-Server den ssh-key:

su zrbackup
ssh-keygen -t rsa -b 4096

Wichtig hier ist, dass alles mit Enter bestätigt wird und kein Passwort vergeben wird. Dann legen wir auf dem Datenserver das .ssh-Verzeichnis an und ergänzen den öffentlichen Key in der Datei authorized_keys hinterlegen

su zsbackup
mkdir /mnt/data0/zsbackup/.ssh
vi /mnt/data0/zsbackup/.ssh/authorized_keys

Statt mit dem Editor zu arbeiten kann man vom Backup-Server mittels root-login auch den Schlüssel wie folgt hinterlegen:

<.ssh/id_rsa.pub ssh root@dataserver 'cat >> /mnt/data0/zsbackup/.ssh/authorized_keys'

Dann sollte man vom Backup-Server den Login testen mittels

ssh zsbackup@dataserver

Erstes Backup manuell erzeugen

Wenn man noch keinen Backup-Pool hat, sondern komplett neu anfängt, kann man sich an die zrep-Anleitung halten und von Grund auf einen Backup-Pool erzeugen. Da ich jedoch bereits einen Pool mit Backup-Snapshots habe, bin ich wie folgt vorgegangen, um diesen Pool auch mit zrep zu nutzen.

Im ersten Schritt wird ein Snapshot in der zrep-Nomenklatur erzeugt und dann die entsprechende zrep-Konfiguration hinterlegt.

zsbackup@dataserver$ zfs snap data0/pool1@zrep_000001
zsbackup@dataserver$ ./zrep changeconfig -f data0/pool1 backupserver remote_backup/pool1

Anschließend kann man mit folgenden Befehlen manuell über zfs send/receive diesen Snapshot auf den backupserver übertragen und zwar vom Backupserver aus (last_synced_snapshot durch den Snapshot ersetzen, der auf beiden Systemen vorhanden ist).

zrbackup@backupserver$ ssh -p 22 -l zsbackup dataserver zfs send -I data0/pool1@last_synced_snapshot data0/pool1@zrep_000001 | zfs recv -F remote_backup/pool1

Nun kann man auch auf dem Backup-Server auch die zrep-Konfiguration ergänzen

zrbackup@backupserver$ ./zrep changeconfig -f -d remote_backup/pool1 dataserver data0/pool1

Jetzt noch auf dem Datenserver das „master“ flag setzen und zrep mitteilen, dass der letzte Sync schon erfolgt ist mittels

zsbackup@dataserver$ ./zrep sentsync -L data0/pool1@zrep_000001

Überprüfen lassen sich die im zfs pool als properties hinterlegten Konfigurationen mittels

zsbackup@dataserver$ ./zrep list -v data0/pool1
zrbackup@backupserver$ ./zrep list -v remote_backup/pool1

Backup mit zrep testen

Folgender Befehl auf dem Backup-Server sollte nun erfolgreich ausgeführt werden können

zrbackup@backupserver$ env SSH="ssh -p 22 -l zsbackup" ZREP_SKIP_EXPIRE=1 ZREP_PATH="/mnt/data0/zsbackup/zrep" /mnt/remote_backup/zsbackup/zrep refresh remote_backup/pool1

Übrigens habe ich in allen Befehlen explizit den Port 22 angegeben. Das wäre nicht notwendig, aber wenn man SSH nicht auf dem Standardport laufen lässt, kann man 22 einfach ändern in den passenden Port.

Cronjobs anlegen

Nun können wir einen Cronjob anlegen – entweder direkt mit dem Befehl zum Testen oder aber über ein eigenes Skript, das den obigen Befehl enthält und z.B. so aussehen kann

#!/bin/bash
# Skript to pull backups of different datasets from dataserver
env SSH="ssh -p 22 -l zsbackup" ZREP_PATH="/mnt/data0/zsbackup/zrep" ZREP_SKIP_EXPIRE=1 /mnt/remote_backup/zrbackup/zrep refresh remote_backup/pool1
env SSH="ssh -p 22 -l zsbackup" ZREP_PATH="/mnt/data0/zsbackup/zrep" ZREP_SKIP_EXPIRE=1 /mnt/remote_backup/zrbackup/zrep refresh remote_backup/pool2
env SSH="ssh -p 22 -l zsbackup" ZREP_PATH="/mnt/data0/zsbackup/zrep" ZREP_SKIP_EXPIRE=1 /mnt/remote_backup/zrbackup/zrep refresh remote_backup/pool3

Im TrueNAS GUI auf dem Backup-Server legen wir dann den Cronjob an:

Cronjobs, um alte Snapshots zu löschen

Die Berechtigung zum Löschen von Snapshots haben sowohl der zrbackup als auch der zsbackup user nicht auf den Servern, denn leider könnten diese mit der entsprechenden Berechtigung destroy sogar das komplette dataset löschen. Aus diesem Grund werden alte zrep Snapshots über einen separaten Cronjob gelöscht, der root-Rechte besitzt und dessen Befehl auf dem Backup-Server wie folgt aussieht:

/mnt/remote_backup/zrbackup/zrep expire -L remote_backup/pool1

Auch auf dem Datenserver legen wir auch einen entsprechenden Cronjob an

/mnt/remote_backup/zsbackup/zrep expire -L data0/pool1

Ein interessantes und noch flexibleres Tool für diese Aufgabe ist zrep-expire. Inspiriert zu diesem Vorgehen hat mich auch der Blog-Post Improving Replication Security With OpenZFS Delegation

Faxempfang einrichten auf der Fritz!Box mit Telnyx als Provider

Hintergrund

Telnyx ist ein etablierter Provider in den USA (vergleichbar mit Twilio) und ermöglicht es, sehr kostengünstig verschiedene Services zu nutzen. In meinem Fall nutze ich den SIP Trunking-Service. Wichtig war mir, dass ich damit auch eingehende Faxe empfangen kann. Nach einigem Rumprobieren, habe ich nun folgende Konfiguration gefunden, die perfekt mit T.38 als Protokoll und der Fritz!Box 7490 funktioniert.

Einrichtung bei Telnyx

Nach dem Einloggen auf dem Telnyx-Kundenportal folgende Einstellungen vornehmen:

  1. Neue Rufnummer für das Fax buchen (Numbers > Search & Buy Numbers) oder bestehende verwenden. Dann die Rufnummer konfigurieren und bei Advanced > Expert Settings > Enable T.38 FAX Gateway das Häkchen setzen
  2. Neue SIP-Verbindung anlegen mit SIP-Connection Type: Credentials, dann noch das Outbound Voice Profile festlegen (auch wenn wir eigentlich faxen wollen)
  3. Caller ID Override: Hier die Rufnummer festlegen, die der Anrufer sehen soll. Es hat leider nicht funktioniert, dies die Fritz!Box setzen zu lassen, daher manuell setzen
  4. T.38 Re-invite Initiated By: auf Customer setzen
  5. Enable on-net T.38 passthrough aktivieren
  6. Nochmal zu Numbers > My Numbers gehen und dort Connection / App auf die gerade erstellte SIP-Verbindung setzen

Einrichtung der Fritz!Box 7490

  1. T.38 aktivieren, unter Telefonie > Eigene Rufnummern > Anschlusseinstellungen > Telefonieverbindung > Faxübertragung auch mit T.38, also dort das Häkchen setzen
  2. Eigene Rufnummer anlegen mit Telnyx als Provider
    1. Telefonie > Eigene Rufnummern > Neue Rufnummer
    2. Als Telefonieanbieter habe ich SIP-Trunking mit unterschiedlichen Rufnummern ausgewählt
    3. Unter Rufnummer für die Anmeldung, Interne Rufnummer in der Fritz!Box und Anzeigename habe ich die Rufnummer ohne Landesvorwahl eingetragen (also alles identisch ausgefüllt)
    4. Zugangsdaten einrichten:
      Benutzername: Benutzername aus dem Telnyx-Portal
      Kennwort: Passwort aus dem Telnyx-Portal
      Registrar: sip.telnyx.com
      Alle anderen Feld bleiben leer (Authentifizierungsname, Proxy-Server, Stun-Server)
    5. Bei Weitere Einstellungen zur Verbindung habe ich Transportprotokoll auf TLS gesetzt
  3. Fax auf der Fritz!Box einrichten (sollte selbsterklärend sein)

Fax-Empfang testen

Testfaxanbieter suchen und darüber ein Testfax an die eigene Rufnummer schicken

ZFS Snapshots synchronisieren mit zettarepl auf dem Rasperry Pi

Für das NAS zuhause nutze ich FreeNAS und das funktioniert wunderbar. Das dort genutzt ZFS-Dateisystem bietet die wunderbare Möglichkeit, Snapshots anzulegen und durch deren zeitsparende Synchronisierung auf einen anderen Server ein verlässliches Backup einzurichten. Unter FreeNAS kann das komfortabel über das GUI unter Tasks > Replication eingerichtet werden. Da ich allerdings auf einen Rasperry Pi mit FreeBSD als Betriebssystem sichern möchte, ist nur der Push von Backups möglich. Wie sich zeigte, kann ein speziell für das Backup errichtete Nutzerkonto nicht mit ausreichend Privilegien ausgestattet werden, um ein funktionierendes Backup einzurichten. Als root hätte ich es zwar einrichten können, dann wäre allerdings für den Fall, dass jemand Zugriff auf den NAS-Server erhält auch das komplette Backup-System kompromitiert. Somit schaute ich mich nach anderen Lösungen um. Zrep war die erste Wahl und funktioniert auch sehr gut, allerdings habe ich es nicht geschafft, rekursiv zu synchronisieren (siehe Bug). Mit zettarepl, dem Tool das auch in FreeNAS Anwendung findet, startete ich einen neuen, erfolgreichen Versuch. Dazu bin ich wie folgt vorgegangen, um zettarepl in FreeBSD einzurichten:

pkg install python py37-setuptools py37-pytz py37-yaml py37-paramiko py37-croniter py37-coloredlogs py37-jsonschema py37-isodate py37-dateutil
mkdir zettarepl
cd zettarepl
fetch https://github.com/freenas/zettarepl/archive/master.tar.gz
tar xzf master.tar.gz
cd zettarepl-master/
python setup.py install --prefix /usr/local

Dann kopieren der Konfigurationsdatei und entsprechendes Anpassen:

cp examples/pull/ssh-replication.yaml ~/zettarepl_pull_backup.yaml

Dann geht es an das Testen der Pull-Replikation von Snapshots. Dazu in der Konfigurationsdatei die Sektion schedule wie folgt anpassen:

schedule:
  minute: "*"
  hour: "*"
  day-of-month: "*"
  month: "*"
  day-of-week: "*"

Nun kann mit einem

zettarepl -l "debug" run --once ~/zettarepl_pull_backup.yaml

getestet werden, ob alles richtig funktioniert.

Leider funktionierte es irgendwie nicht und ich habe nicht herausgefunden, warum. Nun greife ich auf einen FreeNAS Replication Task zurück. Damit sichert zwar das zu sichernde System selbst auf den Backup-Server (eigentlich sollte es so sein, dass der Backup-Server sich die Daten selbst holt), aber wenigstens funktioniert es so. Dazu habe ich einen speziellen Backup-User eingerichtet (mit entsprechenden ZFS-Privilegien).

Hilfreich und eine Alternative dazu ist auch diese Vorgehensweise mit zrep. Diese setze ich in Verbindung miz zrep-expire ein für ein spezielles zvol.

FreeBSD auf Rasperry Pi aktualisieren

Leider lässt sich FreeBSD auf dem Rasperry Pi nicht mit freebsd-update aktualisieren, da dort leider die Unterstützung für arm-Architekturen fehlt. In Anlehnung an einen Post im FreeBSD-Forum habe ich nun FreeBSD auf dem Rasperry Pi 3 wie folgt aktualisiert, um den langwierigen build-Prozess zu umgehen.

  1. Clone-Version installieren
    mkdir -p /usr/local/etc/pkg/repos/
    vi /usr/local/etc/pkg/repos/FreeBSD.conf

    Dann dort folgenden Inhalt eintragen:

    FreeBSD: {
      url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest",
    }

    und mit

    pkg install clone

    die richtige Version von clone installieren.

  2. Backup des aktuellen OS (SD-Karte auf externe USB-Festplatte)
    In meinem Fall das Backup-Drive mounten:

    zfs mount remote_backup

    Wechseln ins Backup-Verzeichnis:

    cd /remote_backup/backup_haning

    Über

    geom disk list

    herausfinden, welches das Systemvolume ist (hier SD-Karte mmcsd0) und dann den Parameter if im folgenden Befehl anpassen, um die Backup-Datei zu erzeugen:

    dd if=/dev/mmcsd0 of=haning_2020-07-12.img bs=1M status=progress

    Backup dann wie folgt testen:

    mdconfig -a -u 0 -t vnode -f /remote_backup/backup_haning/haning_2020-07-12.img
    mount -o noatime /dev/md0s1 /media
    ls /media
    umount /media
    mdconfig -d -u 0
  3. FreeBSD aktualisieren auf den neusten Stand
    Unter FreeBSD Releases, die aktuellste Version herausfinden und dann unter https://download.freebsd.org/ftp/releases/arm64/aarch64/ISO-IMAGES/ die entsprechende Version suchen

    cd /remote_backup/backup_haning/images
    fetch https://download.freebsd.org/ftp/releases/arm64/aarch64/ISO-IMAGES/12.1/FreeBSD-12.1-RELEASE-arm64-aarch64-RPI3.img.xz
    xz -d FreeBSD-12.1-RELEASE-arm64-aarch64-RPI3.img.xz
    mdconfig -a -u 0 -t vnode -f /remote_backup/backup_haning/images/FreeBSD-12.1-RELEASE-arm64-aarch64-RPI3.img
    mount -o noatime,ro /dev/md0s2a /media
    clone -c rwoff -s -x /usr/home:/usr/local:/usr/ports:/usr/obj:/usr/src /media/usr /usr &
    clone -c rwoff -s /media/sbin /sbin &
    clone -c rwoff -s /media/rescue /rescue &
    clone -c rwoff -s -x crontab:exports:fstab:group:hosts:shells:localtime:master.passwd:motd:ntp.conf:passwd:pwd.db:rc.conf:rc.local:resolv.conf:spwd.db:ssh:ssl:unbound:aliases:dma:mailer/mailer.conf /media/etc /etc &
    clone -c rwoff -s -x /boot/loader.conf:/boot:modules:/boot/msdos /media/boot /boot &
    clone -c rwoff -s /media/bin /bin &
    clone -c rwoff -s /media/libexec /libexec &
    clone -c rwoff -s /media/lib /lib &
    

    Dann mit dem Befehl

    jobs

    prüfen, bis alle Befehle im Hintergrund fertiggestellt wurden.

    umount /media
    mdconfig -d -u 0
    zfs umount remote_backup

    Dann neu starten mit

    shutdown -r now
  4. Bitte überspringen – nur als Erinnerung für mich: verschlüsselte USB-Festplatte einbinden mit
    geli attach -k /root/remote_backup_wd_elements_10tb.key /dev/da0p2
    zpool import -N remote_backup
    zfs mount remote_backup
  5. Boot-Partition aktualisieren und Pakete installieren wie z.B. dma
    mdconfig -a -u 0 -t vnode -f /remote_backup/backup_haning/images/FreeBSD-12.1-RELEASE-arm64-aarch64-RPI3.img
    mount_msdosfs -o noatime /dev/md0s1 /media
    clone -c rwoff -s /media /boot/msdos
    umount /media
    mdconfig -d -u 0
    pkg install dma
    shutdown -r now
  6. Pakete installieren
    Paketquelle wieder richtig setzen mit

    rm /usr/local/etc/pkg/repos/FreeBSD.conf

    Jetzt fehlen eventuell die aus der Vergangenheit vorhandenen Pakete. Diese lassen sich installieren mit

    pkg update
    pkg upgrade

MP3 und andere Audiodateien unter Linux umwandeln, um sie schneller abzuspielen

Podcasts sind eine tolle Sache und ich höre sie wahnsinnig gerne beim Autofahren. Um die Zeit noch effektiver zu nutzen, möchte ich manche Audiodateien bei erhöhter Geschwindigkeit hören. Das unterstüzten mittlerweile viele Podcast-Spieler auf dem Handy von Hause aus – nur leider nicht das Entertainment-System von meinem Auto. Und genau deshalb habe ich einen Weg gesucht, um die Podcast-Dateien schnell und komfortabel unter Linux im Batchmodus umzuwandeln, so dass sie mit einer höheren Geschwindigkeit vom USB-Stick abgespielt werden.

Dazu benötigt man unter Ubuntu nur ein Paket: ffmpeg. Wenn man eine etwas bessere Qualität haben möchte, kann man alternativ eine Kombination aus verschiedenen Programmen einsetzen. Dazu benötigt man dann die Pakete: sox, libsox-fmt-mp3, python-mutagen sowie das Programm mid3cp. Letzteres bekommt man unter ubuntu, wenn man diese Datei in github in /usr/bin schiebt und ausführbar macht.

Wenn man diese Voraussetzungen geschaffen hat, kann man mit folgendem Skript sehr komfortabel alle Audio-Dateien in einem Verzeichnis komplett umwandeln.

#!/usr/bin/env bash
# 
# Simple shell script to speed up audio files to 1.5 playing speed
# with ffmpeg
#
#==========================================================
#
#contains username separated by newline
INPUTDIR="/mnt/markus/Downloads/Sorted/Mp3Z/Podcasts/export/dk"
#Directory to link training files to
OUTPUTDIR=/mnt/output/dk
USE_FFMPEG=true
# ffmpeg binary 
FFMPEG_COMMAND=/usr/bin/ffmpeg
SOX_COMMAND=/usr/bin/sox
MID3CP_COMMAND=/usr/bin/mid3cp

echo `date` Begin Audio Conversion
find "${INPUTDIR}" -type f -regextype posix-egrep -regex '.*\.(mp3|m4a|ogg)$' -print0 | sort -z | while read -d $'\0' AUDIO
do
	echo `date` Converting File $AUDIO
	filename=$(basename -- "$AUDIO")
	extension="${filename##*.}"
	filename="${filename%.*}_speed"
	if [ ! -d "$OUTPUTDIR/$dir/" ]; then
		mkdir -p "$OUTPUTDIR/$dir/"
	fi
	if [ -f "$OUTPUTDIR/$dir$filename.$extension" ]; then
		echo `date` Skipping.. "$OUTPUTDIR/$dir$filename.$extension" exists already
	else
		if [[ "${extension,,}" != "mp3" ]] || [ "$USE_FFMPEG" == "true" ] ; then
			echo `date` Generating "$OUTPUTDIR/$dir$filename.$extension" with ffmpeg
			</dev/null $FFMPEG_COMMAND -i "$AUDIO" -v quiet -loglevel panic -filter:a "atempo=1.5" -vn "$OUTPUTDIR/$dir$filename.$extension"
		else
			echo `date` Generating "$OUTPUTDIR/$dir$filename.$extension" with sox
			# variant with sox to change speed and pitch
			#$SOX_COMMAND "$AUDIO" "$OUTPUTDIR/$dir$filename.$extension" speed 1.5 pitch -700
			# variant with sox to change tempo
			$SOX_COMMAND "$AUDIO" "$OUTPUTDIR/$dir$filename.$extension" tempo 1.5
			echo Copying ID3 Tag from original file
			$MID3CP_COMMAND "$AUDIO" "$OUTPUTDIR/$dir$filename.$extension"
		fi
	fi
done