Use rsync instead of scp for the DR-spare backup.conf/README sync

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.
This commit is contained in:
Claude
2026-08-14 19:15:58 +00:00
parent 63774e0500
commit f6e5bb4ea3
+7 -1
View File
@@ -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