#!/bin/bash set -euo pipefail # --------------------------------------------------------------------------- # restic-backup.sh — user-level backup script # Deployed to: ~/.local/bin/restic-backup.sh # # Runs as a regular user — no sudo required. # Config: ~/.config/restic/env and ~/.config/restic/excludes.txt # --------------------------------------------------------------------------- log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; } # Load environment — set -a auto-exports all variables to child processes set -a && source "${XDG_CONFIG_HOME:-$HOME/.config}/restic/env" && set +a # --------------------------------------------------------------------------- # Server reachability check with retry # --------------------------------------------------------------------------- BACKUP_HOST="${BACKUP_SERVER%%:*}" BACKUP_PORT="${BACKUP_SERVER##*:}" MAX_RETRIES=3 RETRY_MIN=600 # 10 min RETRY_MAX=1800 # 30 min server_reachable() { (echo >/dev/tcp/"${BACKUP_HOST}"/"${BACKUP_PORT}") 2>/dev/null } wait_for_server() { local attempt=1 while ! server_reachable; do if [ "$attempt" -ge "$MAX_RETRIES" ]; then log "ERROR: Backup server ${BACKUP_SERVER} unreachable after ${MAX_RETRIES} attempts. Giving up." exit 1 fi local delay=$(( RANDOM % (RETRY_MAX - RETRY_MIN + 1) + RETRY_MIN )) log "Backup server unreachable (attempt ${attempt}/${MAX_RETRIES}). Retrying in $(( delay / 60 )) min..." sleep "$delay" (( attempt++ )) done log "Backup server reachable." } log "=== Backup started on $(hostname) (${MACHINE_NAME}) as $(whoami) ===" wait_for_server # --------------------------------------------------------------------------- # Backup # --------------------------------------------------------------------------- log "Running restic backup..." # Word-split BACKUP_PATHS intentionally — each path is a separate argument # shellcheck disable=SC2086 restic backup \ $BACKUP_PATHS \ --exclude-file "${XDG_CONFIG_HOME:-$HOME/.config}/restic/excludes.txt" \ --one-file-system \ --verbose # --------------------------------------------------------------------------- # Retention # --------------------------------------------------------------------------- log "Applying retention policy (daily=${KEEP_DAILY} weekly=${KEEP_WEEKLY} monthly=${KEEP_MONTHLY})..." restic forget \ --keep-daily "${KEEP_DAILY}" \ --keep-weekly "${KEEP_WEEKLY}" \ --keep-monthly "${KEEP_MONTHLY}" \ --prune log "=== Backup finished on $(hostname) (${MACHINE_NAME}) ==="