ci(deploy): switch from rsync to lftp mirror (SFTP-only hosting)
All checks were successful
ci / build-test (push) Successful in 3m55s
All checks were successful
ci / build-test (push) Successful in 3m55s
Hetzner Webhosting accepts SSH for file transfer but refuses remote command exec, failing rsync with: exec request failed on channel 0 rsync error: error in rsync protocol data stream (code 12) rsync over SSH requires spawning a remote rsync binary, which isn't possible on SFTP-only tiers. Switch the mirror to lftp, which speaks SFTP end-to-end. Same semantics (upload + delete removed files), same key + known_hosts pinning via sftp:connect-program. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -96,27 +96,35 @@ jobs:
|
|||||||
chmod 600 ~/.ssh/id_ed25519
|
chmod 600 ~/.ssh/id_ed25519
|
||||||
printf '%s\n' "$SFTP_KNOWN_HOSTS" > ~/.ssh/known_hosts
|
printf '%s\n' "$SFTP_KNOWN_HOSTS" > ~/.ssh/known_hosts
|
||||||
chmod 644 ~/.ssh/known_hosts
|
chmod 644 ~/.ssh/known_hosts
|
||||||
# Ensure rsync + openssh are present even on a minimal runner image.
|
# Hetzner Webhosting accounts are SFTP-only — they accept SSH for file
|
||||||
if ! command -v rsync >/dev/null 2>&1 || ! command -v ssh >/dev/null 2>&1; then
|
# transfer but refuse remote command exec ("exec request failed on
|
||||||
|
# channel 0"). rsync over SSH needs to spawn a remote rsync binary,
|
||||||
|
# so it cannot work here. Use lftp's mirror instead, which speaks
|
||||||
|
# SFTP end-to-end with the same key + known_hosts pinning.
|
||||||
|
if ! command -v lftp >/dev/null 2>&1 || ! command -v ssh >/dev/null 2>&1; then
|
||||||
if command -v sudo >/dev/null 2>&1; then SUDO=sudo; else SUDO=; fi
|
if command -v sudo >/dev/null 2>&1; then SUDO=sudo; else SUDO=; fi
|
||||||
$SUDO apt-get update -qq
|
$SUDO apt-get update -qq
|
||||||
$SUDO apt-get install -y --no-install-recommends rsync openssh-client
|
$SUDO apt-get install -y --no-install-recommends lftp openssh-client
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Deploy via rsync
|
- name: Deploy via lftp (mirror over SFTP)
|
||||||
env:
|
env:
|
||||||
SFTP_USER: ${{ secrets.SFTP_USER }}
|
SFTP_USER: ${{ secrets.SFTP_USER }}
|
||||||
SFTP_HOST: ${{ secrets.SFTP_HOST }}
|
SFTP_HOST: ${{ secrets.SFTP_HOST }}
|
||||||
SFTP_PATH: ${{ secrets.SFTP_PATH }}
|
SFTP_PATH: ${{ secrets.SFTP_PATH }}
|
||||||
run: |
|
run: |
|
||||||
# Fail loudly if any secret is missing — otherwise rsync --delete
|
# Fail loudly if any secret is missing — otherwise mirror --delete
|
||||||
# could be directed at the SSH user's home root.
|
# could be directed at the SSH user's home root.
|
||||||
: "${SFTP_USER:?SFTP_USER secret must be set}"
|
: "${SFTP_USER:?SFTP_USER secret must be set}"
|
||||||
: "${SFTP_HOST:?SFTP_HOST secret must be set}"
|
: "${SFTP_HOST:?SFTP_HOST secret must be set}"
|
||||||
: "${SFTP_PATH:?SFTP_PATH secret must be set}"
|
: "${SFTP_PATH:?SFTP_PATH secret must be set}"
|
||||||
rsync -avz --delete \
|
lftp <<LFTP
|
||||||
-e "ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes -o UserKnownHostsFile=~/.ssh/known_hosts" \
|
set cmd:fail-exit yes
|
||||||
dist/ "$SFTP_USER@$SFTP_HOST:$SFTP_PATH/"
|
set sftp:connect-program 'ssh -a -x -i $HOME/.ssh/id_ed25519 -o StrictHostKeyChecking=yes -o UserKnownHostsFile=$HOME/.ssh/known_hosts'
|
||||||
|
open sftp://$SFTP_USER@$SFTP_HOST
|
||||||
|
mirror --reverse --delete --verbose --parallel=4 dist/ $SFTP_PATH/
|
||||||
|
bye
|
||||||
|
LFTP
|
||||||
|
|
||||||
- name: Post-deploy smoke test
|
- name: Post-deploy smoke test
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
Reference in New Issue
Block a user