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]

    runs-on: ubuntu-latest
    - uses: actions/checkout@v2
    - name: Synchronize Git repository to uberspace
      uses: AEnterprise/rsync-deploy@v1.0
        DEPLOY_KEY: ${{ secrets.SSH_DEPLOYMENT_KEY }}
        ARGS: "-e -c -r --delete"
        SERVER_PORT: 22
        FOLDER: "./"
        SERVER_IP: ${{ secrets.SSH_HOST }}
        USERNAME: ${{ secrets.SSH_USERNAME }}

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="",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaC1y...

As soon as the public key AAAAB3NzaC1y… authenticats, the 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 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
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


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 &&" ...

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" ...

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.

I am asking you for a donation.

You liked the content or this article has helped and reduced the amount of time you have struggled with this issue? Please donate a few bucks so I can keep going with solving challenges.

Categories: CI/CD