Self-Hosted GitHub Actions Runner on Linux: Deploy from Your Homelab

A self-hosted GitHub Actions runner is a machine you control that executes workflows from your GitHub repository. Instead of using GitHub’s hosted runners, you run jobs on your own hardware inside your homelab or private network. This matters for cost, speed, access to local resources, and privacy-sensitive workloads.

In this guide, we set up a self-hosted runner on a Linux machine, connect it to a GitHub repository, and run a workflow that deploys to your homelab.

What a Self-Hosted Runner Does

When you push code or open a pull request, GitHub can send jobs to your runner instead of GitHub’s cloud runners. Your runner executes the steps defined in the workflow YAML and reports results back to GitHub.

Self-hosted runners are useful for homelab deployments, builds that need access to local Docker registries, tests that require internal network access, or workloads with custom licensing requirements.

Requirements

  • A Linux machine on your homelab: Ubuntu, Debian, or any systemd-based distro works
  • GitHub repository with admin or write access
  • Port 443 outbound to github.com
  • Static IP or reliable DNS for the runner machine

Create the Runner

Go to your repository or organization settings, then Actions > Runners > New self-hosted runner. Choose Linux, then copy the download and configure commands shown on the page.

On your homelab machine:

mkdir actions-runner && cd actions-runner
curl -o actions-runner-linux-x64-2.317.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.317.0/actions-runner-linux-x64-2.317.0.tar.gz
tar xzf actions-runner-linux-x64-2.317.0.tar.gz

Configure and run:

./config.sh --url https://github.com/your-username/your-repo --token YOUR_TOKEN
./run.sh

Keep the process running. The easiest production method is a systemd service.

Run as a systemd Service

Create /etc/systemd/system/github-runner.service:

[Unit]
Description=GitHub Actions Self-Hosted Runner
After=network.target

[Service]
Type=simple
User=runner
WorkingDirectory=/home/runner/actions-runner
ExecStart=/home/runner/actions-runner/run.sh
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable --now github-runner

Workflow Example

Create .github/workflows/deploy.yml in your repository:

name: Deploy to Homelab
on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: self-hosted
    steps:
      - uses: actions/checkout@v4
      - run: docker compose -f /opt/myapp/docker-compose.yml up -d --build

When you push to main, the job runs on your runner and deploys directly to your homelab.

Security Considerations

A self-hosted runner has access to your machine and network. Treat it like a privileged account.

  • Run the runner under a dedicated user, not root
  • Restrict network access with a firewall
  • Use secrets for credentials instead of hardcoding them
  • Keep the runner OS and packages updated
  • Avoid using runners on machines that store sensitive data unless isolated

For public repositories, prefer organization-scoped runners over repository-scoped runners so contributors cannot request jobs on your hardware without approval.

Scaling to Multiple Runners

If you have multiple homelab servers, add a runner on each machine. Use labels in your workflow to target specific runners:

runs-on: [self-hosted, linux, proxmox]

Labels let you route database migrations to a database server, container builds to a builder machine, and production deployments to a specific target.

Final Thoughts

Self-hosted GitHub Actions runners are one of the most practical additions to a homelab. They connect your code repository directly to your infrastructure, reduce dependency on cloud runners, and give you full control over execution environment.

If you want to expand your automation setup, read our guides on Ansible homelab automation, self-hosted monitoring stack, and home network segmentation with VLANs.

Related Posts

Leave a Comment