From e3fbbbada7f9dafb0dfa07934cc49d0c26563d38 Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Fri, 24 Apr 2026 20:24:27 +0200 Subject: [PATCH] ci(deploy): revert to rsync via SSH port 222 (Hetzner shell port) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hetzner Webhosting exposes SSH on TWO ports: port 22 — SFTP only, refuses remote command exec port 222 — full SSH with shell, supports rsync Previous deploys hit "exec request failed on channel 0" because we were using port 22. Switch back from lftp to plain rsync, but route it through port 222 with --rsync-path=/usr/bin/rsync (Hetzner's locked-down PATH doesn't include rsync by default) and BatchMode=yes to disable interactive prompts. Mirrors the working local command: rsync -avz --rsync-path=/usr/bin/rsync \ -e "ssh -p 222 -i ~/.ssh/id_ed25519_gitea -o BatchMode=yes" \ ./ apibny@www691.your-server.de:/usr/www/users/apibny/www.cameleer.io Keeps host-key pinning (StrictHostKeyChecking + UserKnownHostsFile) which the local command omits because the user's personal known_hosts already trusts the host. Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitea/workflows/deploy.yml | 38 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 0b0b45d..1484670 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -96,43 +96,33 @@ jobs: chmod 600 ~/.ssh/id_ed25519 printf '%s\n' "$SFTP_KNOWN_HOSTS" > ~/.ssh/known_hosts chmod 644 ~/.ssh/known_hosts - # 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 + # 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 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 lftp openssh-client + $SUDO apt-get install -y --no-install-recommends rsync openssh-client fi - - name: Deploy via lftp (mirror over SFTP) + - name: Deploy via rsync 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 mirror --delete + # Fail loudly if any secret is missing — otherwise rsync --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}" - # `-u USER,` (with trailing comma = empty password) tells lftp not - # to prompt for a password; auth happens via the key passed to ssh - # by sftp:connect-program. Heredoc body is unindented so lftp's - # parser doesn't mistake leading whitespace for a continuation. - # `debug 3` prints the ssh command lftp invokes — useful if this - # ever breaks again. - lftp <