Installing the Forgejo Runner Binary

This guide walks you through downloading, verifying, and installing the Forgejo runner binary on Linux. By the end, you’ll have a runner registered with your Forgejo/Codeberg instance and running as a systemd service that starts automatically on boot.

Prerequisites

  • A Linux machine (x86_64 or ARM64)
  • wget or curl, jq, gpg, and systemd
  • Docker installed and running (required for running jobs)
  • A Forgejo or Codeberg account with permission to create runners

Step 1: Download and Verify the Binary

First, determine your architecture and fetch the latest release:

# Detect architecture (converts x86_64 → amd64, aarch64 → arm64)
export ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')

# Get the latest version tag from Forgejo's API
export RUNNER_VERSION=$(curl -s https://data.forgejo.org/api/v1/repos/forgejo/runner/releases/latest | jq -r .name | cut -c 2-)

# Construct the download URL
export FORGEJO_URL="https://code.forgejo.org/forgejo/runner/releases/download/v${RUNNER_VERSION}/forgejo-runner-${RUNNER_VERSION}-linux-${ARCH}"

# Download the binary and its signature
wget -O forgejo-runner "${FORGEJO_URL}" || curl -o forgejo-runner "${FORGEJO_URL}"
wget -O forgejo-runner.asc "${FORGEJO_URL}.asc" || curl -o forgejo-runner.asc "${FORGEJO_URL}.asc"

Verify the GPG Signature

Forgejo signs releases with their GPG key. Verify the binary before running it:

# Import Forgejo's public key
gpg --keyserver hkps://keys.openpgp.org --recv EB114F5E6C0DC2BCDD183550A4B61A2DC5923710

# Verify the signature
gpg --verify forgejo-runner.asc forgejo-runner && echo "✓ Verified" || echo "✗ Verification failed"

If verification fails, do not run the binary—re-download and try again.


Step 2: Install the Binary

Make the binary executable and move it to a directory in your PATH:

chmod +x forgejo-runner
sudo cp forgejo-runner /usr/local/bin/forgejo-runner

Test the installation:

forgejo-runner -v
# Should output something like: forgejo-runner version 8.0.0 ...

Step 3: Create a Dedicated Runner User

Run the runner as a dedicated non-root user for security:

# Create user with a home directory
sudo useradd --create-home --shell /bin/bash forgejo-runner-user

# Add to docker group so the runner can spawn job containers
sudo usermod -aG docker forgejo-runner-user

Note: Log out and back in (or reboot) for the docker group change to take effect.


Step 4: Generate the Initial Configuration

Switch to the runner user and generate a default config file:

sudo su - forgejo-runner-user
forgejo-runner generate-config > ~/runner-config.yml

This creates ~/runner-config.yml with sensible defaults. We’ll customize it next.


Step 5: Configure the Runner

Edit ~/runner-config.yml (or use sed/cat as shown below) to make three changes:

1. Set Labels

Labels determine which jobs this runner can execute. Replace the empty labels: [] with your desired labels:

labels:
  - ubuntu-latest:host
  - ubuntu-22.04:host
  - docker:host

Tip: Use label:host format for runners that execute jobs directly on the host. See Forgejo docs for more label formats.

2. Add Your Forgejo/Codeberg Connection

Log into your Forgejo or Codeberg instance:

  1. Go to Settings → Actions → Runners
  2. Click Create new runner
  3. Copy the generated configuration (it contains url, uuid, and token)

Paste it under connections: in your config:

connections:
  forgejo:
    url: https://codeberg.org/          # or your Forgejo instance URL
    uuid: your-runner-uuid-here
    token: your-runner-token-here

3. Save the file

Your runner-config.yml should now have both labels and connections populated.


Step 6: Test the Runner Manually

Before setting up systemd, verify everything works:

# Still as forgejo-runner-user
forgejo-runner daemon -c ~/runner-config.yml

You should see output indicating the runner connected and is waiting for jobs. Check your Forgejo/Codeberg runner list—it should show as Online. Press Ctrl+C to stop.


Step 7: Create a Systemd Service

Run the runner automatically on boot and restart on failure.

Create the service file

# Exit back to your sudo user (Ctrl+D or 'exit')
sudo nvim /etc/systemd/system/forgejo-runner.service

Paste the following configuration:

[Unit]
Description=Forgejo Runner
Documentation=https://forgejo.org/docs/latest/admin/actions/
After=docker.service
Requires=docker.service

[Service]
Type=simple
User=forgejo-runner-user
WorkingDirectory=/home/forgejo-runner-user
ExecStart=/usr/local/bin/forgejo-runner daemon -c /home/forgejo-runner-user/runner-config.yml
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=10
TimeoutStopSec=infinity

# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/home/forgejo-runner-user

[Install]
WantedBy=multi-user.target

Security notes: The hardening options above restrict the service’s filesystem access. Adjust ReadWritePaths if your runner needs access to other directories.


Step 8: Enable and Start the Service

sudo systemctl daemon-reload
sudo systemctl enable --now forgejo-runner.service
sudo systemctl status forgejo-runner.service

The runner should now be active (running). Verify in your Forgejo/Codeberg UI that the runner appears Online.


Troubleshooting

IssueSolution
Runner shows OfflineCheck journalctl -u forgejo-runner -f for errors; verify url, uuid, token in config
docker: permission deniedEnsure forgejo-runner-user is in the docker group and you’ve rebooted/logged out
Jobs stuck in PendingCheck labels match job requirements; verify Docker is running
Binary won’t runRe-verify GPG signature; ensure architecture matches (uname -m)

Updating the Runner

When a new version is released:

# Stop the service
sudo systemctl stop forgejo-runner

# Re-run Step 1 (download & verify new binary)
# ... download commands from Step 1 ...

# Replace binary
sudo cp forgejo-runner /usr/local/bin/forgejo-runner

# Restart
sudo systemctl start forgejo-runner

References:

  1. Installation from binary, Forgejo Docs Latest v16

Author’s note: The technical content and steps in this post are my own. AI was used only for grammar correction and formatting improvements.