Compare commits
6
Commits
f36e243da7
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44674bdc38 | ||
|
|
46e13a4dd5 | ||
|
|
f035a3dc0c | ||
|
|
3e1c561559 | ||
|
|
6fe87107ce | ||
|
|
9f0eafee19 |
No files matched your search
@@ -1,34 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# this one makes a copy of the whole /var/www/html from boogie to BFDS
|
|
||||||
|
|
||||||
SCRIPTPATH=$(dirname `realpath $0`)
|
|
||||||
cd $SCRIPTPATH
|
|
||||||
|
|
||||||
# rsync source -> destination
|
|
||||||
SOURCE_PATH=/var/www/virtual/boogie/html
|
|
||||||
DEST_PATH_FILES=/mnt/bfds/rob/backup/server/boogiedev.net/var_www
|
|
||||||
|
|
||||||
# path of the database backups
|
|
||||||
DEST_PATH_DB=/mnt/bfds/rob/backup/server/boogiedev.net/db
|
|
||||||
|
|
||||||
# EXCLUDE="--exclude-from exclude-list"
|
|
||||||
|
|
||||||
# ### Get all databases
|
|
||||||
|
|
||||||
# kick off DB dumping
|
|
||||||
curl --insecure --silent https://backup.boogiedev.net/dump_all_databases.php
|
|
||||||
|
|
||||||
# download DB dumps
|
|
||||||
cd $DEST_PATH_DB
|
|
||||||
curl --insecure --silent https://backup.boogiedev.net/dumps.zip > dumps.zip
|
|
||||||
if [ -f dumps.zip ]
|
|
||||||
then
|
|
||||||
today=`date +%F`
|
|
||||||
mv dumps.zip all_databases_dump_$today.zip
|
|
||||||
else
|
|
||||||
echo "Datenbank Dump konnte nicht herunter geladen werden"
|
|
||||||
fi
|
|
||||||
|
|
||||||
## aufräumen
|
|
||||||
curl --insecure --silent https://backup.boogiedev.net/dump_all_databases.php?cleanup_dump=1
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
backup_all_databases_cMxNrCTVLBPrNo6qaonojeejCvCepekwssh
|
|
||||||
nextcloud/config/config.php
|
|
||||||
nextcloud/data/root/files/Extern
|
|
||||||
nextcloud/updater
|
|
||||||
nextcloud/backup
|
|
||||||
/nextcloud-data/updater-*/
|
|
||||||
files_trashbin/
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
credentials.php
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
The content of this folder hast to be on the Boogie server at:
|
|
||||||
/var/www/virtual/boogie/html/backup-boogie
|
|
||||||
|
|
||||||
Its the server side enpoint of the backup script running on BFDS.
|
|
||||||
|
|
||||||
The credentials.php has to be filled but never commited to the git
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
<?php
|
|
||||||
ini_set('display_errors', 1);
|
|
||||||
ini_set('display_startup_errors', 1);
|
|
||||||
error_reporting(E_ALL);
|
|
||||||
|
|
||||||
|
|
||||||
$zipfile = "dumps.zip";
|
|
||||||
|
|
||||||
if (isset($_GET['cleanup_dump']) && $_GET['cleanup_dump'] == 1)
|
|
||||||
{
|
|
||||||
Cleanup();
|
|
||||||
die("Cleanup done");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$dumps_path = 'dumps/';
|
|
||||||
if(file_exists($dumps_path))
|
|
||||||
{
|
|
||||||
array_map( 'unlink', array_filter((array) glob($dumps_path.'*') ) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mkdir('dumps');
|
|
||||||
}
|
|
||||||
|
|
||||||
//read php file with credentials and parse it
|
|
||||||
fopen("credentials.php", "r") or die("Unable to open file!");
|
|
||||||
include 'credentials.php';
|
|
||||||
//should priovide the following variables:
|
|
||||||
// $db_host = 'host';
|
|
||||||
// $db_user = 'user';
|
|
||||||
// $db_pass = 'pw';
|
|
||||||
|
|
||||||
if ($db_host == NULL || $db_user == NULL || $db_pass == NULL) {
|
|
||||||
die("Please provide credentials in credentials.php");
|
|
||||||
}
|
|
||||||
|
|
||||||
$db_conn = new mysqli($db_host, $db_user, $db_pass);
|
|
||||||
|
|
||||||
$result = mysqli_query($db_conn,"SHOW DATABASES");
|
|
||||||
while ($row = mysqli_fetch_array($result)) {
|
|
||||||
|
|
||||||
if($row[0] == 'information_schema' || $row[0] == 'performance_schema')
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$database = $row[0];
|
|
||||||
$dir = dirname(__FILE__) . '/'.$dumps_path.$database.'.sql';
|
|
||||||
|
|
||||||
exec("mysqldump --user={$db_user} --password={$db_pass} --host={$db_host} {$database} --result-file={$dir} 2>&1", $output);
|
|
||||||
if(!empty($output))
|
|
||||||
{
|
|
||||||
var_dump($output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
## Zip all dumps
|
|
||||||
|
|
||||||
Cleanup($zipfile);
|
|
||||||
$zip = new ZipArchive;
|
|
||||||
if($zip -> open($zipfile, ZipArchive::CREATE ) === TRUE)
|
|
||||||
{
|
|
||||||
$dir = opendir($dumps_path);
|
|
||||||
while($file = readdir($dir)) {
|
|
||||||
if(is_file($dumps_path.$file)) {
|
|
||||||
$zip -> addFile($dumps_path.$file, $file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$zip ->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
//eine funktion die auf den url parameter cleanup_dump=1 reagiert und dann alle dumps löscht
|
|
||||||
function Cleanup()
|
|
||||||
{
|
|
||||||
global $zipfile;
|
|
||||||
|
|
||||||
if(file_exists($zipfile))
|
|
||||||
{
|
|
||||||
unlink($zipfile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
bfds soll sich regelmässig eine copy des wikis und aller scripte auf boogedev.net (uberspace) holen
|
|
||||||
|
|
||||||
|
|
||||||
Um keine hindernden Passwort-Eingaben zu haben, wird ein dezediertes keyfile ohne PW verwendet.
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# Hint: to exclude any directory (for example an cache dir)
|
|
||||||
# place the CACHEDIR.TAG file in there: https://bford.info/cachedir/
|
|
||||||
# don't forget the signature in there and set the parameter: --exclude-caches
|
|
||||||
|
|
||||||
export RESTIC_REPOSITORY=bfds:/mnt/bfds/rob-restic-backups/restic-repo-t520-user
|
|
||||||
export RESTIC_PASSWORD=kopenhagenhatsuperinternetwirklich
|
|
||||||
|
|
||||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
|
||||||
|
|
||||||
# backup the whole user dir to bfds
|
|
||||||
#restic -r sftp:${RESTIC_REPOSITORY} backup /home/rob --exclude-caches --exclude-file=${SCRIPT_DIR}/backup.excludes
|
|
||||||
|
|
||||||
# find files in backup. $1 is the parameter from comand line.
|
|
||||||
# example: $ backup-list-files.sh /home/rob/Pictures > output.txt
|
|
||||||
# find all files containing Pictures path and out into output.txt
|
|
||||||
restic -r sftp:${RESTIC_REPOSITORY} find $1
|
|
||||||
|
|
||||||
|
|
||||||
#restic -r sftp:bfds:/mnt/bfds/rob-restic-backups/restic-repo-t520-user backup /home/rob --exclude-caches
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# Hint: to exclude any directory (for example an cache dir)
|
|
||||||
# place the CACHEDIR.TAG file in there: https://bford.info/cachedir/
|
|
||||||
# don't forget the signature in there and set the parameter: --exclude-caches
|
|
||||||
|
|
||||||
export RESTIC_REPOSITORY=bfds:/mnt/bfds/rob-restic-backups/restic-repo-t520-user
|
|
||||||
export RESTIC_PASSWORD=kopenhagenhatsuperinternetwirklich
|
|
||||||
|
|
||||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
|
||||||
|
|
||||||
# backup the whole user dir to bfds
|
|
||||||
# restic -r sftp:${RESTIC_REPOSITORY} backup /home/rob --exclude-caches --exclude-file=${SCRIPT_DIR}/backup.excludes
|
|
||||||
|
|
||||||
#restic stats -r sftp:${RESTIC_REPOSITORY}
|
|
||||||
restic snapshots -r sftp:${RESTIC_REPOSITORY}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#Just Caches
|
|
||||||
**/.cache/
|
|
||||||
**/cache/
|
|
||||||
**/Cache/
|
|
||||||
|
|
||||||
#Logs
|
|
||||||
**/log/
|
|
||||||
**/logs/
|
|
||||||
**/Log/
|
|
||||||
**/Logs/
|
|
||||||
*.log
|
|
||||||
|
|
||||||
# VSCode
|
|
||||||
/home/rob/.config/Code/Cache
|
|
||||||
/home/rob/.config/Code/CachedData
|
|
||||||
/home/rob/.config/Code/CachedExtensions
|
|
||||||
/home/rob/.config/Code/CachedExtensionVSIXs
|
|
||||||
|
|
||||||
# Firefox und Co.
|
|
||||||
/home/rob/.mozilla
|
|
||||||
/home/rob/Downloads
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# Hint: to exclude any directory (for example an cache dir)
|
|
||||||
# place the CACHEDIR.TAG file in there: https://bford.info/cachedir/
|
|
||||||
# don't forget the signature in there and set the parameter: --exclude-caches
|
|
||||||
|
|
||||||
export RESTIC_REPOSITORY=bfds:/mnt/bfds/rob-restic-backups/restic-repo-t520-user
|
|
||||||
export RESTIC_PASSWORD=kopenhagenhatsuperinternetwirklich
|
|
||||||
|
|
||||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
|
||||||
|
|
||||||
# backup the whole user dir to bfds
|
|
||||||
restic -r sftp:${RESTIC_REPOSITORY} backup /home/rob --exclude-caches --exclude-file=${SCRIPT_DIR}/backup.excludes
|
|
||||||
|
|
||||||
|
|
||||||
#restic -r sftp:bfds:/mnt/bfds/rob-restic-backups/restic-repo-t520-user backup /home/rob --exclude-caches
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# mount the backup into the file system
|
|
||||||
|
|
||||||
MOUNTPOINT="/mnt/restic-backup-me"
|
|
||||||
|
|
||||||
echo Erstelle Ordner $MOUNTPOINT via sudo
|
|
||||||
sudo mkdir $MOUNTPOINT
|
|
||||||
sudo chown rob:rob $MOUNTPOINT
|
|
||||||
|
|
||||||
echo Mount Backup
|
|
||||||
./restic-bfds.sh mount $MOUNTPOINT
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# Hint: to exclude any directory (for example an cache dir)
|
|
||||||
# place the CACHEDIR.TAG file in there: https://bford.info/cachedir/
|
|
||||||
# don't forget the signature in there and set the parameter: --exclude-caches
|
|
||||||
|
|
||||||
export RESTIC_REPOSITORY=bfds:/mnt/bfds/rob-restic-backups/restic-repo-t520-user
|
|
||||||
export RESTIC_PASSWORD=kopenhagenhatsuperinternetwirklich
|
|
||||||
|
|
||||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
|
|
||||||
|
|
||||||
# restic wrapper for use with command line arguments
|
|
||||||
restic -r sftp:${RESTIC_REPOSITORY} $1 $2 $3 $4 $5 $6 $7 $8 $9
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
INCLUDE_FILES="/home/rob/Pictures/2022/*"
|
|
||||||
RESTORE_PATH="/home/rob/Pictures/from_restic/"
|
|
||||||
./restic-bfds.sh restore --target "$RESTORE_PATH" --include "$INCLUDE_FILES" latest
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
backup_all_databases_cMxNrCTVLBPrNo6qaonojeejCvCepekwssh
|
|
||||||
nextcloud/config/config.php
|
|
||||||
nextcloud/data/root/files/Extern
|
|
||||||
nextcloud/updater
|
|
||||||
nextcloud/backup
|
|
||||||
/nextcloud-data/updater-*/
|
|
||||||
files_trashbin/
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
This folder hast to be on the SBZ server
|
|
||||||
|
|
||||||
The credentials.php has to be filled but never commited to the git
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
<?php
|
|
||||||
ini_set('display_errors', 1);
|
|
||||||
ini_set('display_startup_errors', 1);
|
|
||||||
error_reporting(E_ALL);
|
|
||||||
|
|
||||||
$dumps_path = 'dumps/';
|
|
||||||
if(file_exists($dumps_path))
|
|
||||||
{
|
|
||||||
array_map( 'unlink', array_filter((array) glob($dumps_path.'*') ) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mkdir('dumps');
|
|
||||||
}
|
|
||||||
|
|
||||||
$host = 'localhost';
|
|
||||||
$user = 'root';
|
|
||||||
$pass = "AdfQ3prfUDPu2MtaoLFtxvWbdBooJ6";
|
|
||||||
|
|
||||||
$db_conn = new mysqli($host, $user, $pass);
|
|
||||||
|
|
||||||
$result = mysqli_query($db_conn,"SHOW DATABASES");
|
|
||||||
while ($row = mysqli_fetch_array($result)) {
|
|
||||||
|
|
||||||
if($row[0] == 'information_schema' || $row[0] == 'performance_schema')
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$database = $row[0];
|
|
||||||
$dir = dirname(__FILE__) . '/'.$dumps_path.$database.'.sql';
|
|
||||||
|
|
||||||
exec("mysqldump --user={$user} --password={$pass} --host={$host} {$database} --result-file={$dir} 2>&1", $output);
|
|
||||||
if(!empty($output))
|
|
||||||
{
|
|
||||||
var_dump($output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
## Zip all dumps
|
|
||||||
$zipfile = "dumps.zip";
|
|
||||||
|
|
||||||
if(file_exists($zipfile))
|
|
||||||
{
|
|
||||||
unlink($zipfile);
|
|
||||||
}
|
|
||||||
$zip = new ZipArchive;
|
|
||||||
if($zip -> open($zipfile, ZipArchive::CREATE ) === TRUE)
|
|
||||||
{
|
|
||||||
$dir = opendir($dumps_path);
|
|
||||||
while($file = readdir($dir)) {
|
|
||||||
if(is_file($dumps_path.$file)) {
|
|
||||||
$zip -> addFile($dumps_path.$file, $file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$zip ->close();
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
bfds soll sich regelmässig eine copy der nextcloud instanz ziehen
|
|
||||||
|
|
||||||
Dazu wird der home-rob container im /home/rob gemountet und dann auf file basis eine Kopie vom kompletten /var/www/html
|
|
||||||
|
|
||||||
Nextcloud wird zu dem dazu in den maintenance mode versetzt.
|
|
||||||
|
|
||||||
Um keoine Passwort-Eingaben zu verhindern, wird ein dezediertes keyfile ohne PW verwendet.
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# this one makes a copy of the whole /var/www/html from sbz
|
|
||||||
#
|
|
||||||
# to recover nextcloud data see: https://docs.nextcloud.com/server/13/admin_manual/maintenance/restore.html
|
|
||||||
#
|
|
||||||
# rsync args:
|
|
||||||
# -a, --archive archive mode; equals -rlptgoD (no -H,-A,-X)
|
|
||||||
# -r, --recursive recurse into directories
|
|
||||||
# -l, --links When symlinks are encountered, recreate the symlink on the destination.
|
|
||||||
# -h, --human-readable Output numbers in a more human-readable format.
|
|
||||||
|
|
||||||
SCRIPTPATH=$(dirname `realpath $0`)
|
|
||||||
cd $SCRIPTPATH
|
|
||||||
|
|
||||||
# rsync source -> destination
|
|
||||||
SOURCE_PATH=/var/www/
|
|
||||||
DEST_PATH_FILES=/mnt/bfds/rob/backup/server/spaceboyz.net/var_www
|
|
||||||
|
|
||||||
# ssh credentials
|
|
||||||
PORT="42523"
|
|
||||||
KEY="${SCRIPTPATH}/sbz_keyless"
|
|
||||||
USER_AT_HOST="rob@spaceboyz.net"
|
|
||||||
|
|
||||||
# path of the database backups
|
|
||||||
DEST_PATH_DB=/mnt/bfds/rob/backup/server/spaceboyz.net/mariadb
|
|
||||||
|
|
||||||
## path where home-rob container is mouted into host (on SBZ)
|
|
||||||
SBZ_MOUNT_PATH=/home/rob/tmp_mnt
|
|
||||||
|
|
||||||
## path of the nextcloud instance (on SBZ)
|
|
||||||
NEXTCLOUD_PATH=/var/www/html/nextcloud
|
|
||||||
|
|
||||||
EXCLUDE="--exclude-from exclude-list"
|
|
||||||
|
|
||||||
|
|
||||||
# mount my lxc container into my home on sbz
|
|
||||||
ssh -p $PORT -i $KEY $USER_AT_HOST "sudo mount /dev/mapper/vms-home--rob $SBZ_MOUNT_PATH"
|
|
||||||
|
|
||||||
# grand read permissons if not given
|
|
||||||
ssh -p $PORT -i $KEY $USER_AT_HOST "sudo chmod -R +rx ${SBZ_MOUNT_PATH}/var/www/nextcloud-data"
|
|
||||||
|
|
||||||
# put nextcloud into maintenance, outside the home-rob container
|
|
||||||
ssh -p $PORT -i $KEY $USER_AT_HOST "sudo sed -i \"s|'maintenance' => false|'maintenance' => true|g\" $SBZ_MOUNT_PATH$NEXTCLOUD_PATH/config/config.php"
|
|
||||||
|
|
||||||
# rsync download from sbz
|
|
||||||
rsync --quiet -a -zz --progress $EXCLUDE -e "ssh -p $PORT -i $KEY" $USER_AT_HOST:${SBZ_MOUNT_PATH}${SOURCE_PATH} ${DEST_PATH_FILES}
|
|
||||||
|
|
||||||
# turn off nextcloud maintenancThis rsync lacks old-style --compress due to its external zlibe, outside the home-rob container
|
|
||||||
ssh -p $PORT -i $KEY $USER_AT_HOST "sudo sed -i \"s|'maintenance' => true|'maintenance' => false|g\" $SBZ_MOUNT_PATH$NEXTCLOUD_PATH/config/config.php"
|
|
||||||
|
|
||||||
# umount my container
|
|
||||||
ssh -p $PORT -i $KEY $USER_AT_HOST "sudo umount $SBZ_MOUNT_PATH"
|
|
||||||
|
|
||||||
|
|
||||||
### Get all databases
|
|
||||||
|
|
||||||
cd $DEST_PATH_DB
|
|
||||||
# kick off DB dumping
|
|
||||||
curl --insecure --silent https://rob.spaceboyz.net/backup_all_databases_cMxNrCTVLBPrNo6qaonojeejCvCepekwssh/dump_all_databases.php
|
|
||||||
# download DB dumps
|
|
||||||
curl --insecure --silent https://rob.spaceboyz.net/backup_all_databases_cMxNrCTVLBPrNo6qaonojeejCvCepekwssh/dumps.zip > dumps.zip
|
|
||||||
if [ -f dumps.zip ]
|
|
||||||
then
|
|
||||||
today=`date +%F`
|
|
||||||
mv dumps.zip all_databases_dump_$today.zip
|
|
||||||
else
|
|
||||||
echo "Datenbank Dump konnte nicht herunter geladen werden"
|
|
||||||
fi
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
-----BEGIN OPENSSH PRIVATE KEY-----
|
|
||||||
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
|
|
||||||
-----END OPENSSH PRIVATE KEY-----
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCrW6mg83W/cdQuaB/G0kjV3rTRUv76sXvTlyyauli6SjEsemfeDoVTDAsPUXu6ql+aKeAIE70dbq8uYdmu0hwZvUHNVcwLKIV9vTvoeMBAfNX81aTw+koXfZ6SR6MW8vaNK+b4eUYvTa4bS7FwrUXMgQV3mlnUpPLGgS+0K47id1hyxwOolzbLtGTdR1ucVzE+ZitHt3Vn6/AJ1KJV2+TFSZZXKhUp7lidHwrQt2x0n/zkQ/BW8+sL5b7/2G4kUL++OfF+nZjQGFZgnVIU28fmK1izkYtni2PYPzResy8r3eAwrqv5/8w7FqI3Lx2BkBHxKZU3sEOwV4Y5BBZACv4zk39VTJDaz55Asf7g+cCOFY0zqr/sYWek0zlPP2ccs9gi5gH/oLeLLCBPGCgefH6az8qfwvDu+gN0ugUo4aH4HfWEzZpS5klx3F12txxV514Z1RKSxvImuCg03SYvMX1cluusbO2uRj9VJ0VnA9g+UiEm/UJf9GgB450fXEcjJUyUyQ8eFyD7TPIKBzCxv0GDclKKzJeeUbfGkxQockpl3he1cIISfyoxPETyzTwIz/LOQsScMpC4W9r1yc0MJcNy8e0K6h/Bwev6tEqV0qIHzv5bnjVdDkKbEMMJ7LaBeUQstgJ4w3tgVxN6QgvTesDCRg4oWuqb5d82eAvl/9k+dQ== rob@d3v.localdomain
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
<?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>com.backup-recordings-to-bfds</string>
|
|
||||||
|
|
||||||
<key>ProgramArguments</key>
|
|
||||||
<array>
|
|
||||||
<string>/bin/bash</string>
|
|
||||||
<string>/Users/rob/code/lokale-scripte/macos/Backup-Recordings/backup-recordings-to-bfds.sh</string>
|
|
||||||
</array>
|
|
||||||
|
|
||||||
<key>StartCalendarInterval</key>
|
|
||||||
<dict>
|
|
||||||
<key>Hour</key>
|
|
||||||
<integer>12</integer>
|
|
||||||
<key>Minute</key>
|
|
||||||
<integer>0</integer>
|
|
||||||
</dict>
|
|
||||||
|
|
||||||
<key>StandardOutPath</key>
|
|
||||||
<string>/Users/rob/code/lokale-scripte/macos/Backup-Recordings/run-backup-recordings_output.log</string>
|
|
||||||
<key>StandardErrorPath</key>
|
|
||||||
<string>/Users/rob/code/lokale-scripte/macos/Backup-Recordings/run-backup-recordings_error.log</string>
|
|
||||||
|
|
||||||
<key>RunAtLoad</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Logfile definieren
|
|
||||||
LOGFILE="$HOME/Library/Logs/backup-recordings.log"
|
|
||||||
MAX_LOG_SIZE=$((3 * 1024 * 1024)) # 3MB in Bytes
|
|
||||||
|
|
||||||
# Funktion zur Überprüfung und Rotation des Logfiles
|
|
||||||
rotate_log() {
|
|
||||||
if [ -f "$LOGFILE" ]; then
|
|
||||||
local size=$(stat -f%z "$LOGFILE" 2>/dev/null || echo 0)
|
|
||||||
if [ "$size" -ge "$MAX_LOG_SIZE" ]; then
|
|
||||||
# Behalte nur die letzten 50% des Logs
|
|
||||||
local keep_lines=$(($(wc -l < "$LOGFILE") / 2))
|
|
||||||
tail -n "$keep_lines" "$LOGFILE" > "${LOGFILE}.tmp"
|
|
||||||
mv "${LOGFILE}.tmp" "$LOGFILE"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Funktion für Log-Ausgaben mit Zeitstempel
|
|
||||||
log() {
|
|
||||||
local message="[$(date '+%Y-%m-%d %H:%M:%S')] $1"
|
|
||||||
echo "$message" | tee -a "$LOGFILE"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Funktion für macOS Benachrichtigungen
|
|
||||||
notify() {
|
|
||||||
local subtitle="$1"
|
|
||||||
local message="$2"
|
|
||||||
osascript -e "display notification \"$message\" with title \"Backup Recordings\" subtitle \"$subtitle\""
|
|
||||||
}
|
|
||||||
|
|
||||||
# Funktion zum Formatieren von Bytes in menschenlesbare Größe
|
|
||||||
format_bytes() {
|
|
||||||
local bytes=$1
|
|
||||||
if [ "$bytes" -lt 1024 ]; then
|
|
||||||
echo "${bytes} B"
|
|
||||||
elif [ "$bytes" -lt 1048576 ]; then
|
|
||||||
awk "BEGIN {printf \"%.1f KB\", $bytes/1024}"
|
|
||||||
elif [ "$bytes" -lt 1073741824 ]; then
|
|
||||||
awk "BEGIN {printf \"%.1f MB\", $bytes/1048576}"
|
|
||||||
else
|
|
||||||
awk "BEGIN {printf \"%.2f GB\", $bytes/1073741824}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Log rotieren falls nötig
|
|
||||||
rotate_log
|
|
||||||
|
|
||||||
# Quelle und Ziel definieren
|
|
||||||
SOURCE="/Users/rob/Recordings/Work/00_MacOS/"
|
|
||||||
SERVER="bfds"
|
|
||||||
REMOTE_PATH="/mnt/bfds-nix/rob/recordings/Progress/Work/00_MacOS/"
|
|
||||||
TARGET="$SERVER:$REMOTE_PATH"
|
|
||||||
|
|
||||||
# Prüfen, ob SSH-Verbindung zum Server möglich ist
|
|
||||||
log "Prüfe SSH-Verbindung zu $SERVER..."
|
|
||||||
if ! ssh -o ConnectTimeout=5 -o BatchMode=yes "$SERVER" "exit" 2>/dev/null; then
|
|
||||||
log "Fehler: SSH-Verbindung zu $SERVER fehlgeschlagen"
|
|
||||||
notify "Fehler" "Server $SERVER nicht erreichbar!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
log "SSH-Verbindung erfolgreich"
|
|
||||||
|
|
||||||
# Prüfen, ob das Remote-Zielverzeichnis existiert
|
|
||||||
log "Prüfe Remote-Zielverzeichnis..."
|
|
||||||
if ! ssh "$SERVER" "test -d \"$REMOTE_PATH\""; then
|
|
||||||
log "Fehler: Remote-Verzeichnis existiert nicht: $REMOTE_PATH"
|
|
||||||
notify "Fehler" "Zielverzeichnis nicht gefunden!\n$REMOTE_PATH"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Prüfen, ob Schreibrechte vorhanden sind
|
|
||||||
if ! ssh "$SERVER" "test -w \"$REMOTE_PATH\""; then
|
|
||||||
log "Fehler: Keine Schreibrechte für Remote-Verzeichnis: $REMOTE_PATH"
|
|
||||||
notify "Fehler" "Keine Schreibrechte!\n$REMOTE_PATH"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
log "Remote-Verzeichnis ist bereit für Backup"
|
|
||||||
|
|
||||||
# Sicherung starten
|
|
||||||
log "Starte rsync..."
|
|
||||||
RSYNC_OUTPUT=$(mktemp)
|
|
||||||
log "Befehl: rsync -av --stats --no-owner --no-group \"$SOURCE\" > \"$RSYNC_OUTPUT\" \"$TARGET\""
|
|
||||||
rsync -av --stats --no-owner --no-group "$SOURCE" "$TARGET" > "$RSYNC_OUTPUT" 2>&1
|
|
||||||
|
|
||||||
# Rsync-Output komplett ins Logfile schreiben
|
|
||||||
cat "$RSYNC_OUTPUT" >> "$LOGFILE"
|
|
||||||
|
|
||||||
# -a → Archive-Modus (erhält Zeitstempel, Links, etc.)
|
|
||||||
# -v → Verbose
|
|
||||||
# --stats → Statistiken anzeigen
|
|
||||||
# --no-owner → Besitzer nicht übertragen
|
|
||||||
# --no-group → Gruppe nicht übertragen
|
|
||||||
|
|
||||||
# Statistiken auslesen - rsync gibt mehrere Formate aus, teste beide
|
|
||||||
TOTAL_FILES=$(grep -E "Number of (regular )?files transferred:" "$RSYNC_OUTPUT" | awk '{print $NF}' | tr -d ',')
|
|
||||||
if [ -z "$TOTAL_FILES" ]; then
|
|
||||||
# Alternativer Versuch
|
|
||||||
TOTAL_FILES=$(grep "files transferred:" "$RSYNC_OUTPUT" | awk '{print $(NF)}' | tr -d ',')
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Dateigröße in Bytes auslesen
|
|
||||||
# macOS rsync gibt aus: "Total transferred file size: 86137390 B"
|
|
||||||
TOTAL_BYTES=$(grep "Total transferred file size:" "$RSYNC_OUTPUT" | awk '{print $5}')
|
|
||||||
# Konvertiere String in Integer
|
|
||||||
TOTAL_BYTES=$((TOTAL_BYTES))
|
|
||||||
|
|
||||||
# Formatiere Größe in menschenlesbares Format
|
|
||||||
TOTAL_SIZE=$(format_bytes "$TOTAL_BYTES")
|
|
||||||
|
|
||||||
# Fallback falls keine Werte gefunden wurden
|
|
||||||
[ -z "$TOTAL_FILES" ] && TOTAL_FILES="0"
|
|
||||||
|
|
||||||
# Temporäre Datei löschen
|
|
||||||
rm -f "$RSYNC_OUTPUT"
|
|
||||||
|
|
||||||
# Setze Besitzer und Rechte auf dem Server
|
|
||||||
log "Setze Besitzer und Rechte..."
|
|
||||||
ssh "$SERVER" "chown -R smbuser:smbuser \"$REMOTE_PATH\" && chmod -R 777 \"$REMOTE_PATH\" && find \"$REMOTE_PATH\" -type f -exec chmod 666 {} \;" 2>&1 | tee -a "$LOGFILE"
|
|
||||||
|
|
||||||
# Erfolgsmeldung ausgeben
|
|
||||||
log "Backup abgeschlossen: $TOTAL_FILES Dateien, $TOTAL_SIZE übertragen"
|
|
||||||
|
|
||||||
# Optional: Notification für macOS anzeigen
|
|
||||||
notify "Abgeschlossen" "$TOTAL_FILES Dateien übertragen ($TOTAL_SIZE)"
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,290 +0,0 @@
|
|||||||
#!/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 "$@"
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
#!/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"
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
@ECHO OFF
|
|
||||||
CHCP 65001 >NUL
|
|
||||||
REM **************************************************
|
|
||||||
REM Dieser command sichert die Inhalt von bfds in windows
|
|
||||||
REM auf der OFFSITE platte (Veracrypt Partition) mittels
|
|
||||||
REM SMB Freigaben von bfds und xcopy.
|
|
||||||
REM **************************************************
|
|
||||||
SETLOCAL
|
|
||||||
|
|
||||||
|
|
||||||
REM **************************************************
|
|
||||||
REM Einbinden der Veracrypt Partition
|
|
||||||
REM **************************************************
|
|
||||||
echo Festplatte NASOFFSITE1 wird entschlüsselt und eingebunden
|
|
||||||
SET VOLUME_LABEL=NASOFFSITE1
|
|
||||||
SET VERACRYPT_PATH="C:\Program Files\VeraCrypt\VeraCrypt.exe"
|
|
||||||
SET VOLUME_MOUNT_PATH="B:\"
|
|
||||||
SET VOLUME_PASSWORD=123456
|
|
||||||
REM get the Password for the volume from the user
|
|
||||||
SET /P VOLUME_PASSWORD=Bitte geben Sie das Passwort für die Festplatte %VOLUME_LABEL% ein:
|
|
||||||
%VERACRYPT_PATH% /q /v "\Device\Harddisk2\Partition1" /l B /p "%VOLUME_PASSWORD%"
|
|
||||||
|
|
||||||
SET SOURCE=\\bfds
|
|
||||||
SET DESTINATION="B:\\"
|
|
||||||
|
|
||||||
echo Festplatte NASOFFSITE1 wird gesucht
|
|
||||||
IF NOT EXIST %DESTINATION% (
|
|
||||||
echo Festplatte NASOFFSITE1 nicht gefunden, bitte in Veracrypt als Laufwerk B:\ einbinden!
|
|
||||||
PAUSE
|
|
||||||
exit /B
|
|
||||||
)
|
|
||||||
|
|
||||||
CALL :RunRobocopy "ebooks"
|
|
||||||
CALL :RunRobocopy "movies"
|
|
||||||
CALL :RunRobocopy "music"
|
|
||||||
CALL :RunRobocopy "peggy"
|
|
||||||
CALL :RunRobocopy "rob"
|
|
||||||
exit /B %ERRORLEVEL%
|
|
||||||
|
|
||||||
REM **************************************************
|
|
||||||
REM Funktion zum Ausführen von robocopy
|
|
||||||
:RunRobocopy
|
|
||||||
SET COPYPATH=%~1
|
|
||||||
IF NOT EXIST %SOURCE%\%COPYPATH% (
|
|
||||||
echo Quelle nicht gefunden! Bitte öffne die SMB Freigbe: %SOURCE%\%COPYPATH%
|
|
||||||
PAUSE
|
|
||||||
exit /B %ERRORLEVEL%
|
|
||||||
)
|
|
||||||
SET SCRIPT_PATH=%~dp0
|
|
||||||
SET TODAY=%DATE:~6,4%%DATE:~3,2%%DATE:~0,2%
|
|
||||||
SET LOGFILE="%SCRIPT_PATH%robocopy_log_%COPYPATH%_%TODAY%.txt"
|
|
||||||
echo LOGFILE: %LOGFILE%
|
|
||||||
robocopy %SOURCE%\%COPYPATH% %DESTINATION%\%COPYPATH% /E /mt /z /J /COPY:DAT /R:3 /W:5 /LOG+:%LOGFILE% /TEE
|
|
||||||
REM Erklärung der Parameter:
|
|
||||||
REM /E: Kopiert Unterverzeichnisse inklusive leerer Verzeichnisse
|
|
||||||
REM /mt: Multithreaded copying
|
|
||||||
REM /z: Kopiert Dateien im Restart-Modus (d.h. kopiert Dateien, die bereits existieren)
|
|
||||||
REM /COPY:DAT: Kopiert Dateiattribute, Zeitstempel und Sicherheitsinformationen
|
|
||||||
REM /R:3: Anzahl der Wiederholungsversuche bei Fehlern
|
|
||||||
REM /W:5: Wartezeit zwischen den Wiederholungsversuchen
|
|
||||||
REM /J: Kopiert mit unbuffered I/O (empfohlen für große Dateien)
|
|
||||||
REM /LOG+: Protokolliert den Kopiervorgang in eine Datei
|
|
||||||
REM /TEE: Protokolliert den Kopiervorgang auch in der Konsole
|
|
||||||
GOTO :EOF
|
|
||||||
REM **************************************************
|
|
||||||
|
|
||||||
REM **************************************************
|
|
||||||
REM Partiton wieder aushängen
|
|
||||||
REM **************************************************
|
|
||||||
%VERACRYPT_PATH% /d B /q
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
bfds soll ein funktionierendes off-site backup bekommen
|
|
||||||
|
|
||||||
Dazu sollte am besten eine USB-HDD direkt an bfds gehangen werdn das automatisch überspielt wird.
|
|
||||||
|
|
||||||
Oder die Platte kommt an den Lappi und ein rsync zieht sich alle Änderungen von bfds:/mnt/bfds nach /run/media/rob/BFDS-OFFSITE-1/
|
|
||||||
|
|
||||||
Label HDD1: BFDS-OFFSITE-1
|
|
||||||
Label HDD2: BFDS-OFFSITE-2
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# FIRST Encrypt!
|
|
||||||
## von Hand und mit Dolphin
|
|
||||||
|
|
||||||
# only run when BFDS-OFFSITE-1 or BFDS-OFFSITE-2 is attached
|
|
||||||
# find correct drive `ls -l /dev/disk/by-label/BFDS-OFFSITE-1` or `lsblk -o name,mountpoint,label,size,uuid /dev/sdb1 | grep BFDS-OFFSITE-`
|
|
||||||
# BFDS-OFFSITE-1 UUID: 45f76efd-1cb0-4ade-b610-0443eb8079e9
|
|
||||||
|
|
||||||
# find correct drive `ls -l /dev/disk/by-label/BFDS-OFFSITE-1` or `lsblk -o name,mountpoint,label,size,uuid /dev/sdb1 | grep BFDS-OFFSITE-`
|
|
||||||
|
|
||||||
echo "#####################################################"
|
|
||||||
echo "## ##"
|
|
||||||
echo "## BFDS-OFFSITE BACKUP ##"
|
|
||||||
echo "## ##"
|
|
||||||
echo "#####################################################"
|
|
||||||
echo "## FIRST Encrypt HDD! von Hand und mit Dolphin ##"
|
|
||||||
echo "#####################################################"
|
|
||||||
|
|
||||||
string=`ls -l /dev/disk/by-label/BFDS-OFFSITE-*`
|
|
||||||
if [[ $string != *"BFDS-OFFSITE-"* ]]; then
|
|
||||||
echo "\n ABBRUCH! Keine angeschlossene OFFSITE Festplatte gefunden."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# run backup
|
|
||||||
sourceDir="bfds:/mnt/bfds/" # on BFDS
|
|
||||||
destinationDir="/run/media/rob/BFDS-OFFSITE-1/BFDS"
|
|
||||||
rsync -a -zz --stats --progress $sourceDir $destinationDir
|
|
||||||
|
|
||||||
|
|
||||||
read -p "Backupprozess beendet. Taste drücken für weiter.."
|
|
||||||
Reference in new issue
Block a user