Running a self-hosted GitHub Actions Runner
Log in easily into your CI environment
Shelley handles the setup.
Prefer a terminal?
curl -fsSL https://exe-staging.dev/deploy/github-actions-runner/prompt.txt | ssh exe.dev new --prompt=/dev/stdinThere's very little to it; you're following the GitHub instructions, but then doing a little bit of systemd work to make sure the runner keeps running.
First, create a new VM with ssh exe.dev new. This will create
a new VM. SSH into it with ssh vmname.exe.xyz. The trickiest
bit is to find the GitHub URLs. Replace the placeholders in the following:
- https://github.com/organizations/ORG/settings/actions/runners/new?arch=x64&os=linux
- https://github.com/USER/REPO/settings/actions/runners/new?arch=x64&os=linux
Copy and paste the instructions from GitHub's instructions into your shell session. It's pretty quick and easy until "run.sh".
To make sure the runner restarts after a reboot, we can create a systemd service:
Create the service file at /home/exedev/actions-runner/gh-actions-runner.service:
cat > /home/exedev/actions-runner/gh-actions-runner.service << 'EOF'
[Unit]
Description=GitHub Actions Runner
After=network.target
[Service]
Type=simple
User=exedev
WorkingDirectory=/home/exedev/actions-runner
ExecStart=/home/exedev/actions-runner/run.sh
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
Then copy the service file to systemd directory
sudo cp /home/exedev/actions-runner/gh-actions-runner.service /etc/systemd/system/
And start the service:
sudo systemctl daemon-reload
sudo systemctl enable --now gh-actions-runner.service
Verify the service is running
sudo systemctl status gh-actions-runner.service
gh-actions-runner.service - GitHub Actions Runner
Loaded: loaded (/etc/systemd/system/gh-actions-runner.service; enabled; preset: enabled)
Active: active (running) since Sun 2025-11-09 04:33:28 UTC; 41s ago
Main PID: 1151 (run.sh)
Tasks: 15 (limit: 2384)
Memory: 93.2M (peak: 101.6M)
CPU: 1.447s
CGroup: /system.slice/gh-actions-runner.service
/bin/bash /home/exedev/actions-runner/run.sh
/bin/bash /home/exedev/actions-runner/run-helper.sh
/home/exedev/actions-runner/bin/Runner.Listener run
Nov 09 04:33:30 ...exe.dev run.sh[1159]: Connected to GitHub
Nov 09 04:33:31 ...exe.dev run.sh[1159]: Current runner version: '2.329.0'
Nov 09 04:33:31 ...exe.dev run.sh[1159]: 2025-11-09 04:33:31Z: Listening for Jobs
You're all set!
What you get#
- A self-hosted runner, registered with your GitHub organization or repository
- The
gh-actions-runnersystemd service, which restarts the runner after a reboot Listening for Jobsinsudo systemctl status gh-actions-runner.service
What's running, and where
gh-actions-runner.service, managed by systemd
Deploy with Shelley#
Click Deploy and Shelley will set up GitHub Actions runner on a new VM, then check that it works. No config-file wrangling required.
Have these ready; Shelley asks for them:
GITHUB_RUNNER_URL: the--urlin the./config.shcommand on GitHub's new self-hosted runner page, for your organization or repositoryGITHUB_RUNNER_TOKEN: the--tokenin the same command; it expires after an hour
Prefer a terminal?
curl -fsSL \
https://exe-staging.dev/deploy/github-actions-runner/prompt.txt \
| ssh exe.dev new --prompt=/dev/stdinWhat Shelley is told
GITHUB_RUNNER_URL=<fill-this-in>
GITHUB_RUNNER_TOKEN=<fill-this-in>
Set up GitHub Actions runner on this VM by following the exe.dev recipe at https://exe-staging.dev/deploy/github-actions-runner.md from top to bottom.
The values at the top of this message are mine:
- GITHUB_RUNNER_URL: the `--url` in the `./config.sh` command on GitHub's new self-hosted runner page, for your organization or repository
- GITHUB_RUNNER_TOKEN: the `--token` in the same command; it expires after an hour
Ask me for any that still say <fill-this-in> before you need them.
The recipe's example VM name is my-github-actions-runner. This VM's name is the output of `hostname`: use it wherever the recipe writes my-github-actions-runner. Skip the step that creates the VM; you are on it.
You are done when all of these are true. Check each one yourself:
- A self-hosted runner, registered with your GitHub organization or repository
- The `gh-actions-runner` systemd service, which restarts the runner after a reboot
- `Listening for Jobs` in `sudo systemctl status gh-actions-runner.service`
GitHub's instructions are on the page I open in my browser; reproduce
them here. Download the latest Linux x64 runner from
https://github.com/actions/runner/releases into ~/actions-runner, check
its SHA-256, and run ./config.sh --unattended with my URL and token and
--name "$(hostname)". Don't start run.sh by hand: the systemd service
runs it. Never echo the token back.
Finish with the URLs I should open.
Also at /deploy/github-actions-runner/prompt.txt. The recipe it follows is /deploy/github-actions-runner.md.
Updated Oct 17, 2026 · Markdown · manifest.json · Something wrong? Tell us