From 28ce261a880c10ab80b18239c0650770b5eb71a6 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Sat, 19 Sep 2026 22:26:14 +0000 Subject: [PATCH] Add check-connection.sh read-only PBS connectivity check --- README.backup.md | 17 +++++++++++++++ check-connection.sh | 50 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100755 check-connection.sh diff --git a/README.backup.md b/README.backup.md index a16d1f7..537faba 100644 --- a/README.backup.md +++ b/README.backup.md @@ -15,6 +15,7 @@ Everything lives in `/opt/backup/`. The connection details and credentials | `backup.env.sample` | Template — copy to `backup.env` and fill in real values | | `setup.sh` | Install the client and create the encryption key (run once as root) | | `backup.sh` | Full backup of `/` with client-side encryption | +| `check-connection.sh` | Dry-run connectivity/auth check against the PBS (read-only) | | `restore.sh` | FUSE-mount the encrypted backup to browse/restore files | | `/opt/backup/encryption-key.pem` | Client-side encryption key (store a copy off-host!) | | `/opt/backup/exclude` | Paths excluded from the backup | @@ -79,6 +80,22 @@ The mail body contains the timestamp and the contents of `backup.log`. This only covers `backup.sh` failures — a *missed* run (host down, cron removed) is not detected, so monitor the PBS side too. +## Checking connectivity + +`check-connection.sh` answers "will the next backup probably work?" with +read-only checks: + +1. the files `backup.sh` needs (encryption key, exclude list) exist; +2. `PBS_SERVER:PBS_PORT` is reachable on TCP; +3. an authenticated API round-trip succeeds (it lists existing snapshots for + this host on the PBS — nothing is written). + +It prints a `[ok]` per check and exits 0 on success, 1 on failure: + +``` +./check-connection.sh +``` + Encryption is client-side. The key file has no password (`kdf: none`), so **possession of the key file alone is enough to decrypt** — protect it. diff --git a/check-connection.sh b/check-connection.sh new file mode 100755 index 0000000..e2d35b5 --- /dev/null +++ b/check-connection.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=backup.env +source "$SCRIPT_DIR/backup.env" + +# ============================================================================== +# CONNECTION CHECK +# ============================================================================== +BACKUP_LABEL="${HOSTNAME}-root" +EXCLUDE_FILE="/opt/backup/exclude" + +fail() { + echo "check-connection: FAIL: $*" >&2 + exit 1 +} + +echo "PBS target: ${PBS_SERVER}:${PBS_PORT} datastore=${PBS_DATASTORE} namespace=${BACKUP_NS:-default}" +echo + +# 1. Preflight — the files backup.sh itself requires +[ -s "$ENCRYPTION_KEY_FILE" ] || fail "encryption key not found at $ENCRYPTION_KEY_FILE" +echo "[ok] encryption key present: $ENCRYPTION_KEY_FILE" +[ -f "$EXCLUDE_FILE" ] || fail "exclude list not found at $EXCLUDE_FILE" +echo "[ok] exclude list present: $EXCLUDE_FILE" +echo + +# 2. TCP reachability of the PBS server +if ! timeout 5 bash -c "exec 3<>/dev/tcp/${PBS_SERVER}/${PBS_PORT}" 2>/dev/null; then + fail "cannot open TCP connection to ${PBS_SERVER}:${PBS_PORT} (hostname resolution or firewall?)" +fi +echo "[ok] TCP connection to ${PBS_SERVER}:${PBS_PORT}" +echo + +# 3. Authenticated round-trip: list existing snapshots for this host +if ! SNAP_OUT="$(timeout 30 proxmox-backup-client snapshot list "host/${BACKUP_LABEL}" --ns "$BACKUP_NS" 2>&1)"; then + echo "$SNAP_OUT" >&2 + fail "authenticated request failed — check PBS_AUTH_ID / PBS_PASSWORD in backup.env" +fi +echo "[ok] authentication + API round-trip to the server" +if [ -n "$SNAP_OUT" ]; then + echo "existing snapshots for ${BACKUP_LABEL}:" + echo "$SNAP_OUT" +else + echo " (none yet for ${BACKUP_LABEL} — the first backup has not run)" +fi + +echo +echo "All checks passed. The next backup should succeed." \ No newline at end of file