Railway

Deploy Github Actions Runner

Runs your GitHub Actions workflow jobs on your own server

Deploy Github Actions Runner

Deploy and Host a GitHub Actions Self-Hosted Runner on Railway

Self-host GitHub Actions runners when hosted minutes stop being a good fit. A self-hosted runner is the same official agent GitHub ships, running on machines you control — you pick the CPU and memory, and jobs can reach private services a GitHub-hosted machine cannot. Teams reach for this when builds outgrow the minute allowance, when a job needs more RAM than a hosted runner offers, or when a deployment step must reach infrastructure that never touches the public internet.

Deploy GitHub Actions runners on Railway and the agent registers itself. This template runs GitHub's own ghcr.io/actions/actions-runner image with a startup script that fetches its registration from the GitHub API, so there is no expiring token to paste in. You supply a token and the repository or organisation to join; the container re-registers before each job and serves a private health endpoint reporting whether GitHub sees the runner online.

Diagram of the single runner service on Railway

Getting Started with GitHub Actions Runners on Railway

Before deploying, create the token. For a single repository, a classic token with repo scope works, or a fine-grained one with Administration: read & write. For an organisation runner, use admin:org or Self-hosted runners: read & write. Set it as GITHUB_PAT and GITHUB_SCOPE to owner/repository or just owner — a pasted GitHub URL also works.

There is no web interface to open, because a runner dials out to GitHub rather than accepting traffic. Confirm it on GitHub: open Settings → Actions → Runners on the repository or organisation you targeted and, within a minute, a runner named railway- plus a short identifier appears as Idle with the labels self-hosted, linux, x64 and railway. If it never appears, read the deployment logs — a rejected token is reported plainly there, and the health check fails rather than reporting a healthy service doing nothing.

Once the runner is idle, point a workflow at it by setting runs-on to self-hosted or any label you configured. The quickest check is the Runner self-test workflow in the source repository: dispatch it from the Actions tab and it prints the runner name, operating system and the CPU and memory limits it sees, then checks out a repository and runs a build step. A green run whose log opens with Runner name: 'railway-…' proves the job ran on your Railway container.

Three successful GitHub Actions runs on the self-hosted runner Completed job steps including checkout and a build step

About Hosting GitHub Actions Runners

GitHub Actions runs workflows on machines called runners, and GitHub's own are metered by the minute. A self-hosted runner is the same agent — the open-source project at github.com/actions/runner — connected to your repository from hardware you provide. GitHub still queues jobs, matches them by label, streams logs and enforces permissions; only execution moves, and GitHub bills no minutes for it.

Key characteristics of this deployment:

  • Registers itself by calling GitHub's API at startup for a just-in-time configuration.
  • Ephemeral by default — a fresh registration per job and a cleared workspace, GitHub's recommended posture. Set RUNNER_EPHEMERAL=false for one long-lived registration.
  • Honest health reporting/healthz succeeds only while GitHub reports the runner online.
  • Finishes work before restarting, so a redeploy does not kill a build mid-run.

The architecture is deliberately one service: a runner keeps no durable state, since actions/cache stores to GitHub rather than local disk.

Why Deploy GitHub Actions Runners on Railway

Railway suits this workload well:

  • No GitHub Actions minutes are consumed by jobs that run here
  • More CPU and memory than the standard hosted runner, with a slider instead of a plan change
  • Jobs can reach other Railway services over the private network
  • Deploys straight from the source repository, so the runner image is yours to modify
  • No servers to patch, and no runner agent to upgrade by hand

Common Use Cases

  • Escaping minute limits where a test suite runs on every push and burns the allowance.
  • Memory-hungry builds — monorepo type-checking, Rust or C++ compiles, bundling that fails on a hosted runner.
  • Deployment jobs touching private infrastructure, such as migrations against a private database.
  • Keeping source off third-party machines where policy requires builds you control.

Dependencies for GitHub Actions Runners

  • ghcr.io/actions/actions-runner:latest — GitHub's official runner image, built on Ubuntu 24.04, shipping git, curl, jq and the agent.

No other services: job state lives on GitHub and artifacts upload there, so no database, cache or object storage is needed.

Environment Variables Reference

VariableRequiredDefaultDescription
GITHUB_PATYesToken used to register the runner
GITHUB_SCOPEYesowner/repository or owner
RUNNER_LABELSNoself-hosted,linux,x64,railwayLabels runs-on matches
RUNNER_NAME_PREFIXNorailwayPrefix for the runner name
RUNNER_EPHEMERALNotrueRe-register before every job
RUNNER_GROUP_IDNo1Runner group ID; 1 is Default
RUNNER_WORKNo/home/runner/_workWorking directory for jobs
PORTNo8080Port serving the health endpoint

Deployment Dependencies

Hardware Requirements for Self-Hosting GitHub Actions Runners

The agent is light; your jobs decide the requirement. Size the service to the heaviest workflow you run.

ResourceMinimumRecommended
CPU1 vCPU4–8 vCPU
RAM1 GB4–8 GB
StorageEphemeralEphemeral
RuntimeUbuntu 24.04 containerUbuntu 24.04 container

An idle runner uses a few hundred megabytes, but a monorepo build or Rust compile can use several gigabytes. A job killed for running out of memory appears as an abruptly cancelled workflow rather than a clear error, so leave headroom.

Self-Hosting GitHub Actions Runners

To run the agent yourself, download the release, register it and start it. These commands launch a runner on Linux:

mkdir actions-runner && cd actions-runner
curl -o runner.tar.gz -L https://github.com/actions/runner/releases/latest/download/actions-runner-linux-x64.tar.gz
tar xzf runner.tar.gz
./config.sh --url https://github.com/OWNER/REPOSITORY --token REGISTRATION_TOKEN
./run.sh

That registration token comes from Settings → Actions → Runners → New self-hosted runner and expires after an hour — the step this template removes.

To run the official image with Docker instead:

docker run -d --name gh-runner \
  -e RUNNER_NAME=local-runner \
  ghcr.io/actions/actions-runner:latest \
  ./run.sh --jitconfig ENCODED_JIT_CONFIG

Is Self-Hosting GitHub Actions Free?

The agent is open source under the MIT licence, and GitHub charges nothing for jobs on self-hosted runners on any plan, including free accounts. You pay only infrastructure — on Railway, the compute and memory the service uses, billed by usage rather than build minute.

Limitations of Running GitHub Actions on Railway

Railway containers run no Docker daemon and nothing privileged, so jobs using the container: or services: keys, or any docker build step, will fail. Language toolchain work — Node, Python, Go, Rust, Java, shell — runs normally, and actions/checkout and actions/cache work because both talk to GitHub.

GitHub advises attaching self-hosted runners to private repositories only: a pull request from a fork of a public repository can run its author's code on your runner. Ephemeral mode clears the workspace between jobs, but jobs share one filesystem, so untrusted code belongs on GitHub-hosted runners.

FAQ

What is a GitHub Actions self-hosted runner? The official agent that executes GitHub Actions workflow jobs on your own infrastructure instead of GitHub's. GitHub still schedules jobs and streams logs; only execution moves.

What does this Railway template deploy? One service running GitHub's ghcr.io/actions/actions-runner image with a startup script that registers the runner automatically. No database and no volume, because a runner keeps no durable state.

Why is there no database or storage service in this template? A runner persists nothing worth keeping — job definitions, logs, caches and artifacts all live on GitHub, so a volume would add no benefit and would block scaling out.

How do I send a specific workflow to my self-hosted runner? Set the job's runs-on to self-hosted, or any other label in RUNNER_LABELS. Jobs left on ubuntu-latest keep running on GitHub-hosted machines and consuming minutes.

Can I run more than one job at a time? Each container handles one job at a time. Run more copies of the service for concurrency, giving each a distinct RUNNER_NAME_PREFIX so names cannot collide.


Template Content

More templates in this category

View Template
Rocky Linux
[Jul'26] Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀

codestorm
40
View Template
Foundry Virtual Tabletop
A Self-Hosted & Modern Roleplaying Platform

Lucas
71
View Template
Letta Code Remote
Run a Letta Code agent 24/7. No inbound ports, just deploy.

Letta
51