rsync access can be restricted with a custom wrapper script or an official script named “rrsync”. Access to your remote filesystem should always be restricted so you won’t leak any information in case of a security breach.
I’ve used GitHub Actions a lot in the last few months. For web projects I am mostly using a custom script which gets triggered by SSH and does a git pull from the GitHub repository itself. Besides that it does Blue/Green deployment, automatically linking of VHosts and some other stuff.
Recently I had a much simpler requirement: I just wanted to copy the whole GitHub repository to my Uberspace. The GitHub Action definition for this is pretty simple:
name: Deploy to Uberspace
on: [push]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Synchronize Git repository to uberspace
uses: AEnterprise/rsync-deploy@v1.0
env:
DEPLOY_KEY: ${{ secrets.SSH_DEPLOYMENT_KEY }}
ARGS: "-e -c -r --delete"
SERVER_PORT: 22
FOLDER: "./"
SERVER_IP: ${{ secrets.SSH_HOST }}
USERNAME: ${{ secrets.SSH_USERNAME }}
SERVER_DESTINATION: .
You just have to add the parameters SSH_DEPLOYMENT_KEY, SSH_HOST and SSH_USERNAME in your GitHub project settings.

When running the GitHub Action, it copies the whole Git repository (including the .git directory) to the directory SERVER_DESTINATION on your host.
Restricting rsync access

As you might have already guessed it, there is a catch: I am a paranoid person and I am feeling slightly uncomfortable to grant GitHub access to my whole webspace. Unluckily, with Uberspace you get only one user account. So I am not able to use a specific user for restricted file or directory permissions.
There are two ways known to me how you can restrict the access – without having a dedicated rsync user.
Using a wrapper script for checking the rsync command
When using SSH with public/private keys, you can specify which command has to be executed when a given key authenticates. Inside your .ssh/authorized_keys file you have to prepend the command=”” option before your public key:
command="my-script.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaC1y...
As soon as the public key AAAAB3NzaC1y… authenticats, the my-script.sh is executed. Inside the given script you can access the initiated command by GitHub Actions through the environment variable $SSH_ORIGINAL_COMMAND. You can go with http://gergap.de/restrict-ssh-to-rsync.html to see how you can implement it this way.
Meet rrsync
Depending upon your needs, a custom wrapper script might be the way to go. But there is also a second way. The rsync developers had also developed a wrapper script written in Perl. It accepts one of two parameters -ro (read-only) or -wo (write-only) and a base directory for which the access is granted.
To set it up, do the following:
cd ~/bin
curl https://ftp.samba.org/pub/unpacked/rsync/support/rrsync
chmod +x rrsync
vim ~/.ssh/authorized_keys
# add the following line or prepend the options before your deployment key
# command="$HOME/bin/rrsync -wo ~/your_project_directory",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ssh-rsa AAAAB3N...
The parameter -wo ~/your_project_directory restricts rsync to be only able to write to the directory ~/your_project_directory. In case of a security breach your GitHub Action’s SSH key would not be able to copy any files, like .env configuration files, from your host.
A minor advantage is that you don’t have to specify the target directory in your GitHub Action itself. You just have to use
SERVER_DESTINATION: .
in the YAML file. All files will be rsynced to ~/your_project_directory.
Post-deployment tasks
After having rsync’ed your deployment, you probably want also to do some post-depolyment tasks like executing a bash script.
When using rrsync you can not concat multiple commands in the authorized_keys file like
command="$HOME/bin/rrsync -wo ~/your_project_directory && my-post-deployment-script.sh" ...
This is because rsync can not determine that the synchronization process has been ended. This leads to an infinite execution of rsync.
To get a post-deployment script working, you can use nohup:
command="$HOME/bin/rrsync -wo ~/your_project_directory && nohup my-post-deployment-script.sh" ...
Summing it up
I showed you how you can rsync your GitHub project to a remote host and restrict access to the remote filesystem. In my case I went with the rrsync solution.