add: backup Paperless NGX to MacOS
This commit is contained in:
1 parent
b9a32c92d3
commit
f36e243da7
4 files changed
+455
No files matched your search
@@ -0,0 +1,96 @@
|
|||||||
|
# Paperless-ngx-Backup von TrueNAS auf macOS
|
||||||
|
|
||||||
|
Das Script ist fuer die auf `bfds` erkannte Installation vorbereitet:
|
||||||
|
|
||||||
|
- TrueNAS 25.04.2.6
|
||||||
|
- TrueNAS-App `paperless-ngx` 1.6.37
|
||||||
|
- Paperless-ngx 3.0.2
|
||||||
|
- Container `ix-paperless-ngx-paperless-1`
|
||||||
|
|
||||||
|
Es pflegt einen dauerhaften Paperless-Export und synchronisiert ihn ungezippt
|
||||||
|
auf den Mac. Nach dem ersten vollstaendigen Lauf werden nur neue, geaenderte
|
||||||
|
oder geloeschte Dateien abgeglichen. Es entstehen keine Archive und keine
|
||||||
|
taeglichen Vollkopien.
|
||||||
|
|
||||||
|
Der lokale Stand befindet sich hier:
|
||||||
|
|
||||||
|
```text
|
||||||
|
~/Backups/paperless-ngx/current/
|
||||||
|
├── backup-info.txt
|
||||||
|
├── paperless-export/
|
||||||
|
│ ├── manifest.json
|
||||||
|
│ ├── metadata.json
|
||||||
|
│ ├── archive/
|
||||||
|
│ ├── originals/
|
||||||
|
│ └── thumbnails/
|
||||||
|
└── truenas-app-config/
|
||||||
|
```
|
||||||
|
|
||||||
|
`paperless-export` enthaelt Dokumente, Thumbnails, Metadaten, Benutzer und die
|
||||||
|
exportierten Datenbankinhalte. `truenas-app-config` enthaelt zusaetzlich die
|
||||||
|
TrueNAS-App-Einstellungen und die Konfiguration frueherer App-Versionen.
|
||||||
|
|
||||||
|
## Testen und ausfuehren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./backup-paperless-ngx.sh --check
|
||||||
|
./backup-paperless-ngx.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
`--check` prueft SSH, Container und Mounts. Ausserdem wird ein kleiner
|
||||||
|
temporaerer `document_exporter --data-only`-Lauf ausgefuehrt und dessen
|
||||||
|
Manifest kontrolliert. Der Testexport wird sofort wieder entfernt.
|
||||||
|
|
||||||
|
Alle Werte lassen sich ueber `~/.config/paperless-backup/config` aendern;
|
||||||
|
siehe `config.example`. Voraussetzung ist, dass
|
||||||
|
`ssh -o BatchMode=yes bfds true` ohne Passwortdialog funktioniert.
|
||||||
|
|
||||||
|
## Taeglich um 03:00 Uhr ausfuehren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./install-launchagent.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Der Installer kopiert das Script nach
|
||||||
|
`~/Library/Application Support/PaperlessBackup`, legt bei Bedarf die
|
||||||
|
Konfiguration an und registriert einen LaunchAgent. Ein manueller Lauf des
|
||||||
|
installierten Jobs ist mit folgendem Befehl moeglich:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
launchctl kickstart -k gui/$(id -u)/de.rob.paperless-ngx-backup
|
||||||
|
```
|
||||||
|
|
||||||
|
Logs stehen in `~/Library/Logs/paperless-ngx-backup.log` sowie in den beiden
|
||||||
|
`paperless-ngx-launchd.*.log`-Dateien.
|
||||||
|
|
||||||
|
## Wiederherstellung
|
||||||
|
|
||||||
|
1. Eine frische Paperless-Instanz mit derselben Paperless-Version wie in
|
||||||
|
`backup-info.txt` bereitstellen.
|
||||||
|
2. Den Inhalt von `current/paperless-export` in das Export-Volume der neuen
|
||||||
|
Instanz kopieren und dort `document_importer` ausfuehren.
|
||||||
|
3. `current/truenas-app-config` dient als Referenz fuer Ports, Storage,
|
||||||
|
Umgebungswerte und Secrets. Diese Dateien nicht blind in eine laufende
|
||||||
|
TrueNAS-App zurueckkopieren.
|
||||||
|
|
||||||
|
Der Paperless-Exporter sichert keine API-Tokens; sie muessen nach einem Import
|
||||||
|
neu erzeugt werden.
|
||||||
|
|
||||||
|
## Verhalten und Sicherheit
|
||||||
|
|
||||||
|
Das ist ein Spiegel des aktuellen Paperless-Stands. Wird ein Dokument in
|
||||||
|
Paperless geloescht, wird es beim naechsten erfolgreichen Lauf auch aus diesem
|
||||||
|
Export entfernt. Fuer historische Staende sollte der Ordner zusaetzlich durch
|
||||||
|
Time Machine oder ein anderes versionierendes Backup gesichert werden.
|
||||||
|
|
||||||
|
Der Export enthaelt alle Dokumente und moegliche Klartext-Secrets aus der
|
||||||
|
TrueNAS-App-Konfiguration. Das uebergeordnete Zielverzeichnis ist nur fuer den
|
||||||
|
aktuellen macOS-Benutzer zugaenglich. FileVault sollte aktiviert sein.
|
||||||
|
|
||||||
|
Auf dem TrueNAS-Apps-Pool bleibt ebenfalls ein ungezipptes Exportverzeichnis
|
||||||
|
`macos-backup-current` bestehen. Es wird von Paperless bei jedem Lauf
|
||||||
|
inkrementell aktualisiert.
|
||||||
|
|
||||||
|
Bereits mit einer aelteren Scriptversion erzeugte `.tar.gz`-Archive werden
|
||||||
|
nicht automatisch geloescht. Sie koennen nach erfolgreicher Kontrolle des
|
||||||
|
neuen `current`-Ordners manuell entfernt werden.
|
||||||
+290
@@ -0,0 +1,290 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Unkomprimierter, inkrementell aktualisierter Paperless-Export auf diesen Mac.
|
||||||
|
# Kompatibel mit dem mit macOS ausgelieferten Bash 3.2.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/homebrew/bin"
|
||||||
|
export PATH
|
||||||
|
|
||||||
|
SERVER="${SERVER:-bfds}"
|
||||||
|
APP_NAME="${APP_NAME:-paperless-ngx}"
|
||||||
|
PAPERLESS_CONTAINER="${PAPERLESS_CONTAINER:-ix-paperless-ngx-paperless-1}"
|
||||||
|
BACKUP_DIR="${BACKUP_DIR:-$HOME/Backups/paperless-ngx}"
|
||||||
|
SSH_CONNECT_TIMEOUT="${SSH_CONNECT_TIMEOUT:-10}"
|
||||||
|
NOTIFY="${NOTIFY:-1}"
|
||||||
|
|
||||||
|
CONFIG_FILE="${PAPERLESS_BACKUP_CONFIG:-$HOME/.config/paperless-backup/config}"
|
||||||
|
LOG_FILE="${PAPERLESS_BACKUP_LOG:-$HOME/Library/Logs/paperless-ngx-backup.log}"
|
||||||
|
|
||||||
|
if [ -f "$CONFIG_FILE" ]; then
|
||||||
|
# Die Datei ist eine benutzereigene Shell-Konfiguration (KEY=WERT).
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. "$CONFIG_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
SSH=(/usr/bin/ssh -o BatchMode=yes -o ConnectTimeout="$SSH_CONNECT_TIMEOUT")
|
||||||
|
RSYNC_RSH="/usr/bin/ssh -o BatchMode=yes -o ConnectTimeout=$SSH_CONNECT_TIMEOUT"
|
||||||
|
APP_CONFIG_DIR="/mnt/.ix-apps/app_configs/$APP_NAME"
|
||||||
|
REMOTE_CURRENT_DIR="/usr/src/paperless/export/macos-backup-current"
|
||||||
|
LOCAL_CURRENT_DIR="$BACKUP_DIR/current"
|
||||||
|
|
||||||
|
LOCK_DIR="${TMPDIR:-/tmp}/paperless-ngx-backup-${UID}.lock"
|
||||||
|
LOCAL_CHECK_DIR=""
|
||||||
|
REMOTE_EXPORT_DIR=""
|
||||||
|
REMOTE_EXPORT_HOST_DIR=""
|
||||||
|
BACKUP_SUCCEEDED=0
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Aufruf: backup-paperless-ngx.sh [--check | --help]
|
||||||
|
|
||||||
|
ohne Option Lokalen Paperless-Export inkrementell aktualisieren
|
||||||
|
--check Zusaetzlich einen temporaeren Datenbankexport testen
|
||||||
|
--help Diese Hilfe anzeigen
|
||||||
|
|
||||||
|
Optionale Konfiguration: ~/.config/paperless-backup/config
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
log() {
|
||||||
|
local message
|
||||||
|
message="[$(date '+%Y-%m-%d %H:%M:%S')] $*"
|
||||||
|
printf '%s\n' "$message" | /usr/bin/tee -a "$LOG_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
warn() {
|
||||||
|
log "WARNUNG: $*"
|
||||||
|
}
|
||||||
|
|
||||||
|
notify() {
|
||||||
|
[ "$NOTIFY" = "1" ] || return 0
|
||||||
|
/usr/bin/osascript - "$1" "$2" >/dev/null 2>&1 <<'APPLESCRIPT' || true
|
||||||
|
on run argv
|
||||||
|
display notification (item 2 of argv) with title "Paperless-ngx Backup" subtitle (item 1 of argv)
|
||||||
|
end run
|
||||||
|
APPLESCRIPT
|
||||||
|
}
|
||||||
|
|
||||||
|
die() {
|
||||||
|
log "FEHLER: $*"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
local exit_code=$?
|
||||||
|
trap - EXIT INT TERM
|
||||||
|
set +e
|
||||||
|
|
||||||
|
if [ -n "$REMOTE_EXPORT_DIR" ]; then
|
||||||
|
case "$REMOTE_EXPORT_DIR" in
|
||||||
|
/usr/src/paperless/export/macos-backup-check-*)
|
||||||
|
"${SSH[@]}" "$SERVER" \
|
||||||
|
"docker exec '$PAPERLESS_CONTAINER' rm -rf -- '$REMOTE_EXPORT_DIR'" \
|
||||||
|
>/dev/null 2>&1 || true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$LOCAL_CHECK_DIR" ] && [ -d "$LOCAL_CHECK_DIR" ]; then
|
||||||
|
case "$LOCAL_CHECK_DIR" in
|
||||||
|
"$BACKUP_DIR"/.check.*) /bin/rm -rf -- "$LOCAL_CHECK_DIR" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
/bin/rmdir "$LOCK_DIR" >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
if [ "$exit_code" -ne 0 ] && [ "$BACKUP_SUCCEEDED" -ne 1 ]; then
|
||||||
|
notify "Fehlgeschlagen" "Details: $LOG_FILE"
|
||||||
|
fi
|
||||||
|
exit "$exit_code"
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_configuration() {
|
||||||
|
case "$SERVER" in
|
||||||
|
*[!A-Za-z0-9_.:@-]*|'') die "Ungueltiger SERVER-Wert: $SERVER" ;;
|
||||||
|
esac
|
||||||
|
case "$APP_NAME" in
|
||||||
|
*[!A-Za-z0-9_.-]*|'') die "Ungueltiger APP_NAME-Wert: $APP_NAME" ;;
|
||||||
|
esac
|
||||||
|
case "$PAPERLESS_CONTAINER" in
|
||||||
|
*[!A-Za-z0-9_.-]*|'') die "Ungueltiger Containername: $PAPERLESS_CONTAINER" ;;
|
||||||
|
esac
|
||||||
|
case "$SSH_CONNECT_TIMEOUT" in
|
||||||
|
*[!0-9]*|'') die "SSH_CONNECT_TIMEOUT muss eine ganze Zahl sein" ;;
|
||||||
|
esac
|
||||||
|
case "$BACKUP_DIR" in
|
||||||
|
/*) ;;
|
||||||
|
*) die "BACKUP_DIR muss ein absoluter Pfad sein" ;;
|
||||||
|
esac
|
||||||
|
[ "$BACKUP_DIR" != "/" ] || die "Das Wurzelverzeichnis darf nicht BACKUP_DIR sein"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_remote() {
|
||||||
|
local running
|
||||||
|
|
||||||
|
log "Pruefe SSH-Verbindung zu $SERVER ..."
|
||||||
|
"${SSH[@]}" "$SERVER" true >/dev/null 2>&1 || \
|
||||||
|
die "SSH-Verbindung fehlgeschlagen (fuer launchd ist ein SSH-Key ohne Rueckfrage erforderlich)"
|
||||||
|
|
||||||
|
running=$("${SSH[@]}" "$SERVER" \
|
||||||
|
"docker inspect --format='{{.State.Running}}' '$PAPERLESS_CONTAINER' 2>/dev/null") || \
|
||||||
|
die "Paperless-Container $PAPERLESS_CONTAINER wurde nicht gefunden"
|
||||||
|
[ "$running" = "true" ] || die "Paperless-Container laeuft nicht"
|
||||||
|
|
||||||
|
"${SSH[@]}" "$SERVER" "test -d '$APP_CONFIG_DIR' && test -r '$APP_CONFIG_DIR'" || \
|
||||||
|
die "TrueNAS-App-Konfiguration ist nicht lesbar: $APP_CONFIG_DIR"
|
||||||
|
|
||||||
|
REMOTE_EXPORT_HOST_DIR=$("${SSH[@]}" "$SERVER" \
|
||||||
|
"docker inspect --format='{{range .Mounts}}{{if eq .Destination \"/usr/src/paperless/export\"}}{{.Source}}{{end}}{{end}}' '$PAPERLESS_CONTAINER'")
|
||||||
|
case "$REMOTE_EXPORT_HOST_DIR" in
|
||||||
|
/mnt/.ix-apps/docker/volumes/*/_data) ;;
|
||||||
|
*) die "Export-Mount des Paperless-Containers konnte nicht sicher ermittelt werden" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# document_exporter wird vom Container-Wrapper von root auf den Benutzer
|
||||||
|
# paperless heruntergestuft. Daher muessen Check und Ordnererstellung mit
|
||||||
|
# genau diesem Benutzer erfolgen.
|
||||||
|
"${SSH[@]}" "$SERVER" \
|
||||||
|
"docker exec --user paperless:paperless '$PAPERLESS_CONTAINER' test -w /usr/src/paperless/export" || \
|
||||||
|
die "Paperless-Exportverzeichnis ist nicht beschreibbar"
|
||||||
|
|
||||||
|
log "Paperless-Container und TrueNAS-Speicherorte sind bereit"
|
||||||
|
}
|
||||||
|
|
||||||
|
write_backup_info() {
|
||||||
|
local info_file="$1"
|
||||||
|
|
||||||
|
{
|
||||||
|
printf 'Backup created on Mac: %s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
|
||||||
|
printf 'SSH server: %s\n' "$SERVER"
|
||||||
|
printf 'TrueNAS app name: %s\n' "$APP_NAME"
|
||||||
|
printf 'Paperless container: %s\n' "$PAPERLESS_CONTAINER"
|
||||||
|
"${SSH[@]}" "$SERVER" "printf 'TrueNAS version: '; cat /etc/version; printf '\nContainer image (Paperless version): '; docker inspect --format='{{.Config.Image}}' '$PAPERLESS_CONTAINER'"
|
||||||
|
} > "$info_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_capacity() {
|
||||||
|
local source_kb remote_current_kb local_current_kb
|
||||||
|
local remote_needed_kb local_needed_kb remote_free_kb local_free_kb
|
||||||
|
|
||||||
|
source_kb=$("${SSH[@]}" "$SERVER" \
|
||||||
|
"du -sk /mnt/.ix-apps/app_mounts/'$APP_NAME'/media /mnt/.ix-apps/app_mounts/'$APP_NAME'/data 2>/dev/null | awk '{s+=\$1} END {print s+0}'") || source_kb=0
|
||||||
|
remote_free_kb=$("${SSH[@]}" "$SERVER" \
|
||||||
|
"df -Pk '$REMOTE_EXPORT_HOST_DIR' | awk 'NR==2 {print \$4}'") || remote_free_kb=0
|
||||||
|
local_free_kb=$(/bin/df -Pk "$BACKUP_DIR" | /usr/bin/awk 'NR==2 {print $4}')
|
||||||
|
remote_current_kb=$("${SSH[@]}" "$SERVER" \
|
||||||
|
"du -sk '$REMOTE_EXPORT_HOST_DIR/macos-backup-current' 2>/dev/null | awk '{print \$1+0}'") || remote_current_kb=0
|
||||||
|
local_current_kb=$(/usr/bin/du -sk "$LOCAL_CURRENT_DIR/paperless-export" 2>/dev/null | /usr/bin/awk '{print $1+0}') || local_current_kb=0
|
||||||
|
|
||||||
|
if [ "$source_kb" -gt 0 ]; then
|
||||||
|
log "Geschaetzte Paperless-Datenmenge: $((source_kb / 1024)) MB"
|
||||||
|
remote_needed_kb=$((source_kb - remote_current_kb))
|
||||||
|
local_needed_kb=$((source_kb - local_current_kb))
|
||||||
|
[ "$remote_needed_kb" -gt 0 ] || remote_needed_kb=0
|
||||||
|
[ "$local_needed_kb" -gt 0 ] || local_needed_kb=0
|
||||||
|
[ "$remote_free_kb" -gt "$remote_needed_kb" ] || \
|
||||||
|
warn "Auf dem TrueNAS-Apps-Pool koennte der Platz fuer den Export knapp sein"
|
||||||
|
[ "$local_free_kb" -gt "$local_needed_kb" ] || \
|
||||||
|
warn "Auf dem Mac koennte der Platz fuer den lokalen Export knapp sein"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_document_exporter() {
|
||||||
|
local check_id check_host_dir
|
||||||
|
|
||||||
|
check_id="$(date '+%Y-%m-%d_%H-%M-%S')-$$"
|
||||||
|
REMOTE_EXPORT_DIR="/usr/src/paperless/export/macos-backup-check-$check_id"
|
||||||
|
check_host_dir="$REMOTE_EXPORT_HOST_DIR/macos-backup-check-$check_id"
|
||||||
|
LOCAL_CHECK_DIR=$(/usr/bin/mktemp -d "$BACKUP_DIR/.check.XXXXXX")
|
||||||
|
|
||||||
|
log "Teste document_exporter und inkrementelle Aktualisierung ..."
|
||||||
|
if ! "${SSH[@]}" "$SERVER" \
|
||||||
|
"docker exec --user paperless:paperless '$PAPERLESS_CONTAINER' mkdir -p '$REMOTE_EXPORT_DIR' && docker exec '$PAPERLESS_CONTAINER' document_exporter --no-progress-bar --data-only --compare-json --delete --use-folder-prefix '$REMOTE_EXPORT_DIR' && docker exec '$PAPERLESS_CONTAINER' document_exporter --no-progress-bar --data-only --compare-json --delete --use-folder-prefix '$REMOTE_EXPORT_DIR' && docker exec '$PAPERLESS_CONTAINER' test -s '$REMOTE_EXPORT_DIR/manifest.json'" \
|
||||||
|
2>&1 | /usr/bin/tee -a "$LOG_FILE"; then
|
||||||
|
die "Test des document_exporter ist fehlgeschlagen"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Teste inkrementelle rsync-Uebertragung auf den Mac ..."
|
||||||
|
/usr/bin/rsync -a --delete --no-owner --no-group -e "$RSYNC_RSH" \
|
||||||
|
"$SERVER:$check_host_dir/" "$LOCAL_CHECK_DIR/" \
|
||||||
|
>> "$LOG_FILE" 2>&1 || die "Test der rsync-Uebertragung ist fehlgeschlagen"
|
||||||
|
[ -s "$LOCAL_CHECK_DIR/manifest.json" ] || \
|
||||||
|
die "Der rsync-Test hat kein gueltiges Manifest uebertragen"
|
||||||
|
|
||||||
|
"${SSH[@]}" "$SERVER" \
|
||||||
|
"docker exec '$PAPERLESS_CONTAINER' rm -rf -- '$REMOTE_EXPORT_DIR'" \
|
||||||
|
>/dev/null 2>&1 || die "Temporaerer Testexport konnte nicht entfernt werden"
|
||||||
|
REMOTE_EXPORT_DIR=""
|
||||||
|
/bin/rm -rf -- "$LOCAL_CHECK_DIR"
|
||||||
|
LOCAL_CHECK_DIR=""
|
||||||
|
log "document_exporter, Aktualisierung, Manifest und rsync erfolgreich getestet"
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
local mode="backup" export_size remote_current_host
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
'') ;;
|
||||||
|
--check) mode="check" ;;
|
||||||
|
--help|-h) usage; exit 0 ;;
|
||||||
|
*) usage >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
case "$BACKUP_DIR" in
|
||||||
|
/*) ;;
|
||||||
|
*) printf 'FEHLER: BACKUP_DIR muss ein absoluter Pfad sein\n' >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
[ "$BACKUP_DIR" != "/" ] || { printf 'FEHLER: Ungueltiger BACKUP_DIR\n' >&2; exit 1; }
|
||||||
|
|
||||||
|
/bin/mkdir -p "$(dirname "$LOG_FILE")" "$BACKUP_DIR"
|
||||||
|
/bin/chmod 700 "$BACKUP_DIR" 2>/dev/null || true
|
||||||
|
validate_configuration
|
||||||
|
|
||||||
|
if ! /bin/mkdir "$LOCK_DIR" 2>/dev/null; then
|
||||||
|
die "Ein Paperless-Backup laeuft bereits (Lock: $LOCK_DIR)"
|
||||||
|
fi
|
||||||
|
trap cleanup EXIT
|
||||||
|
trap 'exit 130' INT
|
||||||
|
trap 'exit 143' TERM
|
||||||
|
|
||||||
|
check_remote
|
||||||
|
if [ "$mode" = "check" ]; then
|
||||||
|
check_document_exporter
|
||||||
|
write_backup_info /dev/stdout
|
||||||
|
log "Pruefung erfolgreich; temporaerer Testexport entfernt und kein Backup auf dem Mac gespeichert"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
check_capacity
|
||||||
|
/bin/mkdir -p "$LOCAL_CURRENT_DIR/paperless-export" "$LOCAL_CURRENT_DIR/truenas-app-config"
|
||||||
|
remote_current_host="$REMOTE_EXPORT_HOST_DIR/macos-backup-current"
|
||||||
|
|
||||||
|
log "Aktualisiere den dauerhaften Paperless-Export ..."
|
||||||
|
if ! "${SSH[@]}" "$SERVER" \
|
||||||
|
"docker exec --user paperless:paperless '$PAPERLESS_CONTAINER' mkdir -p '$REMOTE_CURRENT_DIR' && docker exec '$PAPERLESS_CONTAINER' document_exporter --no-progress-bar --compare-json --delete --use-folder-prefix '$REMOTE_CURRENT_DIR'" \
|
||||||
|
2>&1 | /usr/bin/tee -a "$LOG_FILE"; then
|
||||||
|
die "document_exporter ist fehlgeschlagen"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Synchronisiere neue und geaenderte Dokumente auf den Mac ..."
|
||||||
|
/usr/bin/rsync -a --delete --no-owner --no-group -e "$RSYNC_RSH" \
|
||||||
|
"$SERVER:$remote_current_host/" "$LOCAL_CURRENT_DIR/paperless-export/" \
|
||||||
|
>> "$LOG_FILE" 2>&1 || die "Uebertragung des Paperless-Exports ist fehlgeschlagen"
|
||||||
|
[ -s "$LOCAL_CURRENT_DIR/paperless-export/manifest.json" ] || \
|
||||||
|
die "Der lokale Export enthaelt kein gueltiges manifest.json"
|
||||||
|
|
||||||
|
log "Sichere die TrueNAS-App-Konfiguration ..."
|
||||||
|
/usr/bin/rsync -a --delete --no-owner --no-group -e "$RSYNC_RSH" \
|
||||||
|
"$SERVER:$APP_CONFIG_DIR/" "$LOCAL_CURRENT_DIR/truenas-app-config/" \
|
||||||
|
>> "$LOG_FILE" 2>&1 || die "Uebertragung der App-Konfiguration ist fehlgeschlagen"
|
||||||
|
|
||||||
|
write_backup_info "$LOCAL_CURRENT_DIR/backup-info.txt"
|
||||||
|
export_size=$(/usr/bin/du -sh "$LOCAL_CURRENT_DIR" | /usr/bin/awk '{print $1}')
|
||||||
|
BACKUP_SUCCEEDED=1
|
||||||
|
log "Backup erfolgreich aktualisiert: $LOCAL_CURRENT_DIR ($export_size)"
|
||||||
|
notify "Erfolgreich aktualisiert" "$LOCAL_CURRENT_DIR – $export_size"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Diese Datei nach ~/.config/paperless-backup/config kopieren und anpassen.
|
||||||
|
# Die Standardwerte passen bereits zur untersuchten Installation auf "bfds".
|
||||||
|
|
||||||
|
SERVER="bfds"
|
||||||
|
APP_NAME="paperless-ngx"
|
||||||
|
PAPERLESS_CONTAINER="ix-paperless-ngx-paperless-1"
|
||||||
|
BACKUP_DIR="$HOME/Backups/paperless-ngx"
|
||||||
|
|
||||||
|
# 1 = macOS-Mitteilung bei Erfolg/Fehler, 0 = keine Mitteilung.
|
||||||
|
NOTIFY=1
|
||||||
|
|
||||||
|
SSH_CONNECT_TIMEOUT=10
|
||||||
+57
@@ -0,0 +1,57 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SOURCE_DIR=$(cd "$(dirname "$0")" && pwd)
|
||||||
|
INSTALL_DIR="$HOME/Library/Application Support/PaperlessBackup"
|
||||||
|
CONFIG_DIR="$HOME/.config/paperless-backup"
|
||||||
|
PLIST="$HOME/Library/LaunchAgents/de.rob.paperless-ngx-backup.plist"
|
||||||
|
LOG_DIR="$HOME/Library/Logs"
|
||||||
|
UID_VALUE=$(id -u)
|
||||||
|
|
||||||
|
mkdir -p "$INSTALL_DIR" "$CONFIG_DIR" "$(dirname "$PLIST")" "$LOG_DIR"
|
||||||
|
install -m 700 "$SOURCE_DIR/backup-paperless-ngx.sh" "$INSTALL_DIR/backup-paperless-ngx.sh"
|
||||||
|
|
||||||
|
if [ ! -f "$CONFIG_DIR/config" ]; then
|
||||||
|
install -m 600 "$SOURCE_DIR/config.example" "$CONFIG_DIR/config"
|
||||||
|
echo "Konfiguration angelegt: $CONFIG_DIR/config"
|
||||||
|
else
|
||||||
|
echo "Vorhandene Konfiguration bleibt unveraendert: $CONFIG_DIR/config"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat > "$PLIST" <<EOF
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>Label</key>
|
||||||
|
<string>de.rob.paperless-ngx-backup</string>
|
||||||
|
<key>ProgramArguments</key>
|
||||||
|
<array>
|
||||||
|
<string>$INSTALL_DIR/backup-paperless-ngx.sh</string>
|
||||||
|
</array>
|
||||||
|
<key>StartCalendarInterval</key>
|
||||||
|
<dict>
|
||||||
|
<key>Hour</key>
|
||||||
|
<integer>3</integer>
|
||||||
|
<key>Minute</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<key>ProcessType</key>
|
||||||
|
<string>Background</string>
|
||||||
|
<key>StandardOutPath</key>
|
||||||
|
<string>$LOG_DIR/paperless-ngx-launchd.out.log</string>
|
||||||
|
<key>StandardErrorPath</key>
|
||||||
|
<string>$LOG_DIR/paperless-ngx-launchd.err.log</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod 600 "$PLIST"
|
||||||
|
plutil -lint "$PLIST"
|
||||||
|
launchctl bootout "gui/$UID_VALUE" "$PLIST" >/dev/null 2>&1 || true
|
||||||
|
launchctl bootstrap "gui/$UID_VALUE" "$PLIST"
|
||||||
|
|
||||||
|
echo "LaunchAgent installiert: taeglich um 03:00 Uhr"
|
||||||
|
echo "Vor dem ersten echten Lauf bitte pruefen:"
|
||||||
|
echo " $INSTALL_DIR/backup-paperless-ngx.sh --check"
|
||||||
Reference in new issue
Block a user