rsync over SSH (-e ssh) in GitHub Actions
rsync -e ssh tunnels the transfer over SSH so you can deploy to a remote server without a separate rsync daemon.
The most common CI deploy: build artifacts on the runner, then rsync them to a server over SSH using a deploy key. The setup that trips people up is known_hosts.
What it does
When the destination is host:path, rsync runs over a remote shell, SSH by default. -e lets you customize that shell, most often to set a non-standard port or extra SSH options. rsync starts a remote rsync process and pipes data through the SSH connection.
SSH options
| Flag | What it does |
|---|---|
| -e "ssh ..." | Set the remote shell and its options |
| -e "ssh -p 2222" | Connect on a non-standard SSH port |
| -e "ssh -i KEY" | Use a specific private key |
| -e "ssh -o StrictHostKeyChecking=accept-new" | Trust an unknown host key on first connect |
| --rsync-path=CMD | Override the remote rsync command (e.g. sudo rsync) |
Common usage
# Default: rsync uses ssh automatically for host:path
rsync -avz dist/ deploy@example.com:/var/www/app/
# Custom port and an explicit key
rsync -avz -e "ssh -p 2222 -i ~/.ssh/deploy_key" dist/ deploy@host:/srv/app/GitHub Actions deploy step
- name: Deploy over SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.DEPLOY_KEY }}" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -p 22 example.com >> ~/.ssh/known_hosts
rsync -avz --delete -e "ssh -i ~/.ssh/id_ed25519" \
dist/ deploy@example.com:/var/www/app/In CI
A fresh runner has no entry for your server in known_hosts, so the first connection would prompt to confirm the fingerprint and then hang (no TTY). Populate known_hosts with ssh-keyscan host >> ~/.ssh/known_hosts before the rsync step. For better security, pin the expected key rather than trusting whatever keyscan returns.
Common errors in CI
Host key verification failed. rsync error: unexplained error (code 255) means known_hosts has no matching key; run ssh-keyscan first. Permission denied (publickey) means the key is wrong, lacks correct permissions (chmod 600), or is not in the server authorized_keys. "rsync: connection unexpectedly closed (0 bytes received so far)" with "protocol version mismatch -- is your shell clean?" means the remote login prints text (a banner or motd) before rsync runs; quiet the shell startup.