diff --git a/config.json b/config.json new file mode 100644 index 0000000..09ccf09 --- /dev/null +++ b/config.json @@ -0,0 +1,160 @@ +{ + "modno": 14, + "version": 4, + "instance": "nuclide.systems", + "repos": [ + { + "id": "media-repo", + "uri": "rclone:jottacloud:media", + "guid": "8a176298b0a7b2a3cddd66e0c02548ed6c4490427a70e4cd0050b69ea22f9f41", + "password": "QPTnL2m8EyzRgNOOH7J7wS1YAJejzIGt", + "prunePolicy": { + "schedule": { + "cron": "0 4 1 * *", + "clock": "CLOCK_LAST_RUN_TIME" + }, + "maxUnusedPercent": 10 + }, + "checkPolicy": { + "schedule": { + "cron": "0 4 1 * *", + "clock": "CLOCK_LAST_RUN_TIME" + }, + "readDataSubsetPercent": 10 + }, + "commandPrefix": { + "env": [ + "GOMEMLIMIT=1600MiB", + "GOGC=50" + ] + } + }, + { + "id": "services-repo", + "uri": "rclone:jottacloud:services", + "guid": "22f55fc6de605ace48e1acc7e6e3834c3881db9a48726a817f81488876b76559", + "password": "tHeHNpA2XIA6TDsflEXoG6K2bXa55E6g", + "prunePolicy": { + "schedule": { + "cron": "0 5 * * 0", + "clock": "CLOCK_LAST_RUN_TIME" + }, + "maxUnusedPercent": 10 + }, + "checkPolicy": { + "schedule": { + "cron": "0 5 1 * *", + "clock": "CLOCK_LAST_RUN_TIME" + }, + "readDataSubsetPercent": 10 + }, + "commandPrefix": {} + } + ], + "plans": [ + { + "id": "services-backup-plan", + "repo": "services-repo", + "paths": [ + "/mnt/pve/unas/backup/home-assistant", + "/mnt/pve/unas/backup/immich", + "/mnt/pve/unas/backup/nextcloud", + "/mnt/pve/unas/services/coder", + "/mnt/pve/unas/services/gitea", + "/mnt/pve/unas/services/karakeep", + "/mnt/pve/unas/services/memos", + "/mnt/pve/unas/services/n8n", + "/mnt/pve/unas/services/nextcloud", + "/mnt/pve/unas/services/pocketid-backup", + "/mnt/pve/unas/services/traccar", + "/mnt/pve/unas/services/vaultwarden", + "/mnt/pve/unas/services/shared-db-garage", + "/mnt/pve/unas/media/documents/public/paperless-ngx" + ], + "schedule": { + "cron": "0 1 * * 1,2,3,4,5", + "clock": "CLOCK_LOCAL" + }, + "retention": { + "policyTimeBucketed": { + "daily": 7, + "weekly": 4, + "monthly": 6, + "yearly": 1 + } + }, + "hooks": [ + { + "conditions": [ + "CONDITION_SNAPSHOT_START" + ], + "actionCommand": { + "command": "bash /opt/backrest/scripts/pocketid-prestage.sh" + } + }, + { + "conditions": [ + "CONDITION_SNAPSHOT_START" + ], + "actionCommand": { + "command": "bash /opt/backrest/scripts/garage-prestage.sh" + } + }, + { + "conditions": [ + "CONDITION_SNAPSHOT_START" + ], + "actionCommand": { + "command": "bash /opt/backrest/scripts/n8n-prestage.sh" + } + } + ] + }, + { + "id": "video-projects-plan", + "repo": "media-repo", + "paths": [ + "/mnt/pve/unas/media/video-projects" + ], + "schedule": { + "cron": "0 4 * * 1,2,3,4,5", + "clock": "CLOCK_LOCAL" + }, + "retention": { + "policyTimeBucketed": { + "weekly": 4, + "monthly": 6, + "yearly": 1 + } + } + }, + { + "id": "media-backup-plan", + "repo": "media-repo", + "paths": [ + "/mnt/pve/unas/media/images/library" + ], + "schedule": { + "cron": "30 1 * * 1,2,3,4,5", + "clock": "CLOCK_LOCAL" + }, + "retention": { + "policyTimeBucketed": { + "weekly": 4, + "monthly": 6, + "yearly": 1 + } + } + } + ], + "auth": { + "disabled": true + }, + "sync": { + "identity": { + "keyId": "ecdsa.qgItJptNkYnW8s3aa1BJhkyHIHe_ihtJ_xLBfnzneZ0", + "ed25519priv": "-----BEGIN EC PRIVATE-----\nMHcCAQEEILjrBLGNjimGsu1ddL4ZIvLcDU8zt50GBiQclPP3Ih9UoAoGCCqGSM49\nAwEHoUQDQgAEDo671mLUGrWapLFALmB9o+9i1D+ZpDre378gPmf9/qyPDkvVCD95\nogXI0nucpNbccdG2qGNgMIEJ46c9FyYN1w==\n-----END EC PRIVATE-----\n", + "ed25519pub": "-----BEGIN EC PUBLIC-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEDo671mLUGrWapLFALmB9o+9i1D+Z\npDre378gPmf9/qyPDkvVCD95ogXI0nucpNbccdG2qGNgMIEJ46c9FyYN1w==\n-----END EC PUBLIC-----\n" + } + } +} \ No newline at end of file diff --git a/scripts/garage-prestage.sh b/scripts/garage-prestage.sh new file mode 100755 index 0000000..83f934b --- /dev/null +++ b/scripts/garage-prestage.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -e + +CT104="root@192.168.1.40" +STAGING="/mnt/pve/unas/services/shared-db-garage" + +mkdir -p "$STAGING" + +# Rsync Garage data and meta dirs (hot copy — Garage is append-only, safe to snapshot) +rsync -rlptD --no-owner --no-group --delete "$CT104":/opt/stacks/shared-db/garage/data/ "$STAGING/data/" +rsync -rlptD --no-owner --no-group --delete "$CT104":/opt/stacks/shared-db/garage/meta/ "$STAGING/meta/" + +echo "[$(date)] garage-prestage: done ($(du -sh $STAGING | cut -f1))" diff --git a/scripts/n8n-prestage.sh b/scripts/n8n-prestage.sh new file mode 100755 index 0000000..7857130 --- /dev/null +++ b/scripts/n8n-prestage.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -e + +CT104="root@192.168.1.40" +STAGING="/mnt/pve/unas/services/n8n" + +# Rsync n8n data (config, nodes, storage) — skip logs and temp files +rsync -rlptD --no-owner --no-group --delete \ + --exclude='*.log' \ + --exclude='crash.journal' \ + --exclude='*.json' \ + "$CT104":/opt/stacks/n8n/data/ "$STAGING/" + +echo "[$(date)] n8n-prestage: done" diff --git a/scripts/pocketid-prestage.sh b/scripts/pocketid-prestage.sh index 97af2b6..68a54e8 100755 --- a/scripts/pocketid-prestage.sh +++ b/scripts/pocketid-prestage.sh @@ -2,16 +2,16 @@ set -e STAGING="/mnt/pve/unas/services/pocketid-backup" -CT110="root@192.168.1.5" +CT109="root@192.168.1.8" # Export inside container then docker cp to host -ssh "$CT110" 'docker exec pocket-id /app/pocket-id export /app/pocket-id-export.zip && docker cp pocket-id:/app/pocket-id-export.zip /tmp/pocketid-export.zip && docker exec pocket-id rm /app/pocket-id-export.zip' +ssh "$CT109" 'docker exec pocket-id /app/pocket-id export /app/pocket-id-export.zip && docker cp pocket-id:/app/pocket-id-export.zip /tmp/pocketid-export.zip && docker exec pocket-id rm /app/pocket-id-export.zip' # Pull to staging on UNAS (accessible from CT 103) -scp "$CT110":/tmp/pocketid-export.zip "$STAGING/pocketid-export.zip" -scp -r "$CT110":/opt/stacks/pocketid/data/keys "$STAGING/" +scp "$CT109":/tmp/pocketid-export.zip "$STAGING/pocketid-export.zip" +scp -r "$CT109":/opt/stacks/pocketid/data/keys "$STAGING/" -# Cleanup CT 110 temp -ssh "$CT110" 'rm -f /tmp/pocketid-export.zip' +# Cleanup CT 109 temp +ssh "$CT109" 'rm -f /tmp/pocketid-export.zip' echo "[$(date)] pocketid-prestage: done" diff --git a/unas-sync.sh b/unas-sync.sh new file mode 100755 index 0000000..7ce6985 --- /dev/null +++ b/unas-sync.sh @@ -0,0 +1,36 @@ +#!/bin/bash +set -e +LOG=/var/log/rclone-unas-sync.log +BWLIMIT="05:30,7.5M 01:00,20M" + +echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) unas-sync starting" | tee -a "$LOG" + +# Job 1: Immich originals → JottaCloud Photos (visible at jottacloud.com/photo) +rclone sync /mnt/pve/unas/media/images/library/ jottacloud:Photos/ \ + --transfers=4 --checkers=8 \ + --bwlimit "$BWLIMIT" \ + --log-file="$LOG" --log-level INFO + +# Job 2: irreplaceable personal data +rclone sync /mnt/pve/unas/ jottacloud:UNAS/ \ + --transfers=4 --checkers=8 \ + --bwlimit "$BWLIMIT" \ + --exclude "media/images/library/**" \ + --exclude "media/images/upload/**" \ + --exclude "media/images/thumbs/**" \ + --exclude "media/images/encoded-video/**" \ + --exclude "media/images/profile/**" \ + --exclude "media/images/backups/**" \ + --exclude "media/movies/**" \ + --exclude "media/emulation/**" \ + --exclude "media/Torrents/**" \ + --exclude "media/music/**" \ + --exclude "media/podcasts/**" \ + --exclude "services/**" \ + --exclude "backup/**" \ + --exclude "backup-staging/**" \ + --exclude "dump/**" \ + --exclude "test_perm" \ + --log-file="$LOG" --log-level INFO + +echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) unas-sync done" | tee -a "$LOG" diff --git a/walg-offsite-sync.sh b/walg-offsite-sync.sh new file mode 100755 index 0000000..fd1aeee --- /dev/null +++ b/walg-offsite-sync.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -e +LOG=/var/log/rclone-walg-offsite.log +rclone sync garage-s3:ct113-pg-backup/ jottacloud:WAL-G/ct113-pg-backup/ \ + --transfers=2 --checkers=4 --log-file="$LOG" --log-level INFO +rclone sync garage-s3:lobe-pg-backup/ jottacloud:WAL-G/lobe-pg-backup/ \ + --transfers=2 --checkers=4 --log-file="$LOG" --log-level INFO +rclone sync garage-s3:immich-pg-backup/ jottacloud:WAL-G/immich-pg-backup/ \ + --transfers=2 --checkers=4 --log-file="$LOG" --log-level INFO +rclone sync garage-s3:ct109-portainer-backup/ jottacloud:WAL-G/ct109-portainer-backup/ \ + --transfers=2 --checkers=4 --log-file="$LOG" --log-level INFO