Troubleshoot GitHub Actions via VPN

Setting the scene

GitHub Actions is a CI/CD solution provided by GitHub. It includes 2000 free minutes per month of container execution time—even on free GitHub accounts. In your GitHub repository you specify workflows containing steps and GitHub will handle the necessary infrastructure in the background to run those steps. GitHub Actions feels quite similar to another service, CircleCI, that mostly does the same thing for builds.

Playing catch-up

In my mind, CircleCI has always had the edge because of a single feature: SSH support. SSH access to jobs is really good for debugging tricky build or deploy problems. If you have a pipeline that’s failing then it can be incredibly useful to SSH into the build environment and have a look around to see what’s wrong. CircleCI provide an elegant solution, authenticating you with the same SSH keys you already use to push to GitHub, and configuring a randomised port to provide on-demand SSH sessions to your build environments. On some of the consultancy engagements I’ve worked on, this remote SSH access feels like has saved hours or even days of trial-and-error troubleshooting.

Out of the box, GitHub Actions doesn’t offer the same ability to debug build problems. I’ll explain how you can work around that yourself, using WireGuard.

(If you’d like a refresher on what WireGuard is, I wrote an article yesterday that introduces WireGuard in general).

The challenge

GitHub Actions runs on virtual machines hosted in Azure, on a private network that we have no access to. But that’s not a problem, because we can run arbitrary commands in the virtual machine as part of our pipeline. I’m going to use that ability to run arbitrary commands and deploy WireGuard in the GitHub Actions runner itself.

The approach

First of all, we need to install WireGuard on the Actions runner. GitHub offers a few different options for the runners.
In this example, we’re going to use ubuntu-latest as the runner type. To set up WireGuard on Ubuntu we only need to install the wireguard-dkms package inside the GitHub Action step; wireguard-dkms automatically installs everything else required. With the VPN tools installed installed, we create two key pairs on the runner itself: one key pair for the runner and one key pair for the connecting client.

Next, we build a configuration for the runner and for the client by using a simple template and populating it with the keys generated. At this point, we have everything we need to start the VPN so we print the clients configuration in the job output (so you can copy it), and bring the VPN up with wg-quick. With the runner end ready, all you need to do is copy the displayed WireGuard configuration and bring it up locally.

I’m glossing over some of the details here, but those details are specific to running SSH on a GitHub Actions runner.

The key takeaway is that using WireGuard we can provide remote access to a system that was previously inaccessible and sitting on a private network with little fuss. The same approach can be used for other systems with a similar setup. For the GitHub Action proof of concept, check out the source code or the Action on the marketplace.


I’m a consultant at The Scale Factory where we empower technology teams to deliver more on the AWS cloud, through consultancy, engineering, support, and training. If you’d like to find out how we can support you and your team to set up VPNs and other networking options, get in touch.