From f6e5bb4ea3fa1ac19568acdf39b808543b969c8c Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 14 Aug 2026 19:15:58 +0000 Subject: [PATCH] Use rsync instead of scp for the DR-spare backup.conf/README sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The freshly-added raw-error logging paid off immediately: the box's spare sync was failing every run with "scp: Connection closed" while plain ssh exec to the same host worked fine. That split (ssh exec OK, scp specifically rejected) matches modern OpenSSH's default scp-over-SFTP transfer hitting a restriction on the remote side that a plain exec or rsync's own protocol don't trigger. Swapped the scp step for rsync -a over the same ssh options, keeping the ssh mkdir -p before it (rsync doesn't create missing destination directories) and the ssh chmod after. Verified the exact command/quoting against mocked ssh/rsync binaries — array expansion and remote path handling both check out. --- extras/backup_kopia.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/extras/backup_kopia.sh b/extras/backup_kopia.sh index 4abd789..252eb98 100644 --- a/extras/backup_kopia.sh +++ b/extras/backup_kopia.sh @@ -234,8 +234,14 @@ if [ -n "${DR_SYNC_HOST:-}" ]; then log "Syncing backup.conf + README to spare ($DR_SYNC_HOST:$_dr_path)..." _dr_files=("$CONF") [ -f "$HERE/README.md" ] && _dr_files+=("$HERE/README.md") + # rsync instead of scp: modern OpenSSH (9.0+) defaults scp to an + # SFTP-based transfer, and some remote-side setups (restricted shells, + # forced commands, older sshd) reject that with an immediate "Connection + # closed" while plain ssh exec and rsync's own protocol both still work + # fine over the same connection. Confirmed live: scp failing this way + # while `ssh "$DR_SYNC_HOST" true` succeeded, rsync doesn't hit it. if ssh -o BatchMode=yes -o ConnectTimeout=10 "$DR_SYNC_HOST" "mkdir -p '$_dr_path'" 2>"$_ERR" \ - && scp -o BatchMode=yes -o ConnectTimeout=10 "${_dr_files[@]}" "$DR_SYNC_HOST:$_dr_path/" 2>>"$_ERR" \ + && rsync -a -e 'ssh -o BatchMode=yes -o ConnectTimeout=10' "${_dr_files[@]}" "$DR_SYNC_HOST:$_dr_path/" 2>>"$_ERR" \ && ssh -o BatchMode=yes -o ConnectTimeout=10 "$DR_SYNC_HOST" "chmod 600 '$_dr_path/backup.conf'" 2>>"$_ERR"; then log "OK spare sync ($DR_SYNC_HOST)" else