diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 074ae21..97b90aa 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -96,27 +96,35 @@ jobs: chmod 600 ~/.ssh/id_ed25519 printf '%s\n' "$SFTP_KNOWN_HOSTS" > ~/.ssh/known_hosts chmod 644 ~/.ssh/known_hosts - # Ensure rsync + openssh are present even on a minimal runner image. - if ! command -v rsync >/dev/null 2>&1 || ! command -v ssh >/dev/null 2>&1; then + # Hetzner Webhosting accounts are SFTP-only — they accept SSH for file + # 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 $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 - - name: Deploy via rsync + - name: Deploy via lftp (mirror over SFTP) env: SFTP_USER: ${{ secrets.SFTP_USER }} SFTP_HOST: ${{ secrets.SFTP_HOST }} SFTP_PATH: ${{ secrets.SFTP_PATH }} 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. : "${SFTP_USER:?SFTP_USER secret must be set}" : "${SFTP_HOST:?SFTP_HOST secret must be set}" : "${SFTP_PATH:?SFTP_PATH secret must be set}" - rsync -avz --delete \ - -e "ssh -i ~/.ssh/id_ed25519 -o StrictHostKeyChecking=yes -o UserKnownHostsFile=~/.ssh/known_hosts" \ - dist/ "$SFTP_USER@$SFTP_HOST:$SFTP_PATH/" + lftp <