Self-Hosted Runners

Self-hosted runners give you complete control over your GitHub Actions execution environment. Run workflows on your own infrastructure, access private networks, use specialized hardware, and scale to meet your organization's needs—all while maintaining security and compliance.

Scale Infrastructure Enhanced Security Ephemeral Runners
What Are Self-Hosted Runners?

Self-hosted runners are machines that you manage and operate, which run GitHub Actions workflows. Unlike GitHub-hosted runners, which run on GitHub's infrastructure, self-hosted runners run on your own servers, cloud instances, or even local machines. You have full control over the operating system, installed software, hardware specifications, and network access.

Organizations choose self-hosted runners for several reasons. Some need access to private networks—databases, internal APIs, or on-premises infrastructure that GitHub-hosted runners cannot reach. Others require specialized hardware like GPUs for machine learning workloads, or large memory configurations for memory-intensive builds. Many organizations also use self-hosted runners to reduce costs, especially for large-scale CI/CD operations where GitHub-hosted minutes can become expensive.

Self-hosted runners are completely free—you only pay for your own infrastructure. This makes them cost-effective for organizations with high-volume CI/CD needs or already existing cloud infrastructure.
When to Use Self-Hosted Runners

Access to private networks: If your workflows need to deploy to internal servers, access private databases, or interact with on-premises infrastructure, self-hosted runners are essential. GitHub-hosted runners cannot access private networks behind your firewall.

Specialized hardware: Machine learning training needs GPUs. iOS development needs macOS hardware. Performance testing needs large memory or specific CPU architectures. Self-hosted runners let you bring your own hardware.

Cost control: For organizations running thousands of workflow minutes per month, GitHub-hosted runner costs can add up. Self-hosted runners on your existing cloud infrastructure can be more economical, especially if you already have reserved instances or spot capacity.

Custom environments: You need specific versions of tools, libraries, or operating systems not available on GitHub-hosted runners. Self-hosted runners can run any OS and have any software pre-installed.

Compliance and data residency: Some organizations have regulatory requirements that data must not leave certain geographic regions or must remain within their infrastructure. Self-hosted runners give you control over where workflows execute.

Self-hosted runners require maintenance. You're responsible for security updates, hardware reliability, and capacity planning. This is a trade-off for the additional control and capabilities.
Setting Up a Self-Hosted Runner

Setting up a self-hosted runner is straightforward. Go to your repository, organization, or enterprise settings, navigate to Actions → Runners, and click "New runner." GitHub provides a script tailored to your operating system that downloads the runner software and registers it with your account.

The runner software is a small application that polls GitHub for jobs, executes them, and reports results. It runs on Linux, Windows, macOS, and even ARM architectures. Once installed and registered, the runner appears in your list and is ready to accept jobs. You can configure multiple runners to handle parallel workloads.

# Installing a runner on Ubuntu (example)
mkdir actions-runner && cd actions-runner
curl -o actions-runner-linux-x64-2.320.0.tar.gz -L https://github.com/actions/runner/releases/download/v2.320.0/actions-runner-linux-x64-2.320.0.tar.gz
tar xzf ./actions-runner-linux-x64-2.320.0.tar.gz
./config.sh --url https://github.com/owner/repo --token AAAAAAAA
./run.sh
After configuration, the runner runs as a service. You can install it as a system service to start automatically on boot, using the provided `svc.sh` script.
Runner Groups and Labels

As you scale, you'll want to organize your runners. Runner groups allow you to create collections of runners with similar characteristics. For example, you might have a group for "linux-production," another for "windows-testing," and a third for "gpu-ml."

Labels are how workflows select which runner to use. When you add a runner, you can assign custom labels. In your workflow, you specify `runs-on: self-hosted` to use any self-hosted runner, or `runs-on: [self-hosted, linux, gpu]` to require specific labels. This gives you fine-grained control over job routing.

# Workflow targeting specific runner labels
jobs:
  ml-training:
    runs-on: [self-hosted, linux, gpu]
    steps:
      - run: python train_model.py

  build-windows:
    runs-on: [self-hosted, windows, build]
    steps:
      - run: msbuild MyProject.sln
Ephemeral Runners: Clean, Isolated, Secure

Ephemeral runners are self-hosted runners that are destroyed after each job. This is a critical security and reliability feature. With ephemeral runners, each workflow runs in a fresh, clean environment. No leftover files, no cached credentials, no cross-job contamination.

To configure ephemeral runners, add `--ephemeral` when configuring the runner. The runner will execute exactly one job, then shut down. You then need a mechanism to provision new runners—typically using autoscaling groups, Kubernetes, or cloud VM provisioning.

Ephemeral runners are the recommended best practice for self-hosted runners, especially for organizations with multiple repositories or untrusted workflows. They prevent one job from affecting another and ensure consistent, reproducible builds. Many organizations use tools like actions-runner-controller for Kubernetes, or Terraform to auto-scale runners in the cloud.

# Configure ephemeral runner (destroys after one job)
./config.sh --url https://github.com/owner/repo --token AAAAAAAA --ephemeral
./run.sh

# Example autoscaling with AWS and Terraform
resource "aws_autoscaling_group" "github_runners" {
  desired_capacity = 0
  min_size = 0
  max_size = 50
  ...
}
Ephemeral runners are essential for security. They ensure that even if a workflow is compromised, the runner is destroyed before any other job can access it.
Security Best Practices

Use ephemeral runners whenever possible. This is the single most important security practice. Ephemeral runners eliminate persistent state and reduce the attack surface.

Run runners in isolated environments. Use separate VMs, containers, or sandboxes for each runner. Don't run multiple runners on the same machine unless you trust all workflows equally.

Minimize permissions. Runners should have the minimum permissions needed to execute workflows. Use service accounts with scoped permissions. Never give runners broad access to production infrastructure.

Keep runner software updated. GitHub regularly releases new runner versions with security patches. Update your runners regularly or use automated update mechanisms.

Use private networking. If runners need to access internal resources, put them in a private subnet or VPC. Use firewalls to restrict inbound and outbound traffic.

Audit runner access. Monitor who has access to register new runners. Runner registration tokens can expose your infrastructure if compromised. Use organization-level runners for better control.

Self-hosted runners have the same access as the machine they run on. If a malicious workflow executes, it could compromise that machine. Always design your runner infrastructure with security in mind.
Autoscaling Self-Hosted Runners

For organizations with variable workload, autoscaling is essential. Instead of keeping many runners idle, you scale up when jobs arrive and scale down when idle. Several approaches exist:

Kubernetes with actions-runner-controller: This popular open-source project runs runners as Kubernetes pods. It automatically scales based on pending jobs and destroys pods after each run. Works on any Kubernetes cluster—EKS, AKS, GKE, or self-managed.

VM autoscaling groups: Use cloud provider autoscaling groups (AWS Auto Scaling, Azure VM Scale Sets, Google Instance Groups). Configure a custom script that registers each new VM as a runner and shuts it down after the job completes.

Serverless ephemeral runners: Some organizations use AWS Lambda or similar serverless platforms to run short-lived jobs, though this is less common due to time limits.

Third-party solutions: Tools like GitHub Actions Runner Controller (ARC) for Kubernetes, or self-hosted runner autoscaling scripts from the community provide robust scaling solutions.

# Example: Kubernetes deployment with actions-runner-controller
apiVersion: actions.summerwind.dev/v1alpha1
kind: RunnerDeployment
metadata:
  name: my-runners
spec:
  replicas: 0
  template:
    spec:
      repository: myorg/myrepo
      ephemeral: true
      resources:
        limits:
          cpu: 2
          memory: 4Gi
GitHub-Hosted vs Self-Hosted Runners

GitHub-Hosted Runners: No maintenance, always up to date, secure isolation per job, limited to available operating systems (Ubuntu, Windows, macOS), limited hardware options, cost per minute for private repositories.

Self-Hosted Runners: You manage everything, any OS or hardware, access to private networks, potential cost savings at scale, need to maintain security, requires capacity planning, ephemeral runners recommended.

Many organizations use a hybrid approach: GitHub-hosted runners for public repositories and general-purpose builds, and self-hosted runners for specialized workloads, private network access, or high-volume internal CI/CD.

You can mix both types in a single workflow. Different jobs can use different runners, giving you the flexibility to use GitHub-hosted for fast, standard jobs and self-hosted for specialized requirements.
Monitoring and Maintenance

Running self-hosted infrastructure requires ongoing attention. Set up monitoring for runner availability, job queue length, and runner health. Use tools like Prometheus, Grafana, or cloud monitoring to track metrics.

Regularly update the runner software. New versions are released frequently with bug fixes and features. Automate updates where possible, or schedule regular maintenance windows.

Monitor disk space. Build artifacts, Docker images, and package caches can accumulate. Ephemeral runners solve this automatically. For persistent runners, implement cleanup scripts to remove old files.

Track costs. If you're running runners in the cloud, monitor your cloud spending. Autoscaling helps, but misconfigured scale groups can lead to unexpected bills.

# Example health check for runner
#!/bin/bash
if ! systemctl is-active --quiet actions-runner; then
  echo "Runner is down. Restarting..."
  systemctl restart actions-runner
fi
Frequently Asked Questions
Are self-hosted runners free?
Yes, the runner software is free. You pay only for your own infrastructure—whether that's existing hardware, cloud VMs, or Kubernetes clusters. GitHub does not charge for self-hosted runner minutes.
Can I run self-hosted runners on Windows?
Absolutely! GitHub provides runner software for Windows, Linux, and macOS. Self-hosted runners are often used for Windows builds where GitHub-hosted Windows runners may be slower or more expensive.
What's the difference between repository, organization, and enterprise runners?
Repository-level runners are only available to that specific repository. Organization-level runners can be used by any repository in the organization. Enterprise-level runners span all organizations in the enterprise. Choose based on your sharing needs.
How do I secure self-hosted runners for public repositories?
Use ephemeral runners exclusively. Never use persistent runners for public repositories. Run each job in an isolated environment (separate VM or container) that is destroyed after the job. Consider using GitHub-hosted runners for public repositories instead.
Can I run Docker containers on self-hosted runners?
Yes! Self-hosted runners can run Docker commands if Docker is installed. This is useful for building and pushing container images from your own infrastructure.
How many jobs can a single runner handle simultaneously?
By default, a runner processes one job at a time. You can configure multiple runners on the same machine by installing the runner software in separate directories and registering each as a separate runner.
What happens if a self-hosted runner goes offline during a job?
If the runner loses connection, the job will eventually time out and fail. For critical workflows, use ephemeral runners and ensure your infrastructure has high availability.
Can I use self-hosted runners with GitHub Enterprise Server?
Yes! Self-hosted runners work with both GitHub.com and GitHub Enterprise Server. They provide the same functionality for on-premises GitHub installations.
Previous: Code Scanning Next: GitHub Packages

Self-hosted runners give you the freedom to run GitHub Actions anywhere. With ephemeral runners and autoscaling, you get the best of both worlds: control and scale.