Gitea Actions: Self-Hosted Runners with act_runner - 夜莺博客

Gitea Actions: Self-Hosted Runners with act_runner

Gitea Actions brings GitHub-style workflows to a self-hosted Git server, and act_runner is the agent that executes them. The combination is attractive for small teams because it needs no external service, but the failure points are all in the plumbing: Actions is disabled by default, registration tokens are scoped by level, and a runner with no matching label will happily sit idle while your workflow queues forever. This guide covers the whole path from enabling Actions to watching a container-based job complete.

Enable Actions on the Gitea instance

Actions are off by default. Add the following to the Gitea configuration and restart the service:

[actions]
ENABLED = true

If you do not see runner settings pages afterwards, this setting is almost always the reason. The runner management URLs follow a predictable pattern depending on the level you want:

  • Instance level: <your_gitea.com>/-/admin/actions/runners
  • Organisation level: <your_gitea.com>/<org>/settings/actions/runners
  • Repository level: <your_gitea.com>/<owner>/<repo>/settings/actions/runners

Registration tokens look like D0gvfu2iHfUjNqCYVljVyRV14fISpJxxxxxxxxxx and stay valid for multiple runner registrations until you reset them. On larger instances it is worth provisioning the token through the CLI or environment so runner deployment can be automated:

gitea --config /etc/gitea/app.ini actions generate-runner-token

openssl rand -hex 24 > /some-dir/runner-token
export GITEA_RUNNER_REGISTRATION_TOKEN_FILE=/some-dir/runner-token

Tokens generated from the environment remain valid until reset through the web interface, which makes them suitable for image builds and autoscaling runners.

Choose the execution mode

act_runner can run jobs directly on the host, in a Docker container, or in Docker-in-Docker rootless mode. The host mode is fastest and least isolated; Docker is the recommended default because each job gets a clean, reproducible environment. If you intend to build container images inside jobs, plan for DinD or a mounted Docker socket and treat the security implications seriously — a job with a mounted socket has effective root on the runner host.

Register the runner

./act_runner register --no-interactive \
  --instance https://gitea.example.com \
  --token <my_runner_token> \
  --name ci-runner-1 \
  --labels ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest

Without --labels, the default label set is applied: ubuntu-latest, ubuntu-22.04 and ubuntu-20.04, each mapped to a container image. A workflow that requests runs-on: ubuntu-24.04 on a runner that only advertises ubuntu-22.04 will queue indefinitely with no useful error — check the labels first when jobs never start.

The interactive equivalent asks four questions in order: instance URL, runner token, runner name (blank uses the hostname) and runner labels.

Containerised deployment is a one-liner:

docker run -e GITEA_INSTANCE_URL=https://your_gitea.com \
  -e GITEA_RUNNER_REGISTRATION_TOKEN=<your_token> \
  -v /var/run/docker.sock:/var/run/docker.sock \
  --name my_runner gitea/act_runner:nightly

Two details matter here. The instance URL must be the ROOT_URL that clients can reach — localhost or 127.0.0.1 will not work from inside a job container. And the image tag should be pinned to a version in production rather than left on nightly.

Generate and tune config.yaml

./act_runner generate-config > config.yaml
./act_runner --config config.yaml daemon

The generated configuration controls concurrency limits, the Docker host and network, container options and log level. Raise concurrency only in step with the runner host's CPU and disk, because parallel Docker jobs are I/O heavy.

Add a workflow and verify execution

mkdir -p .gitea/workflows
cat > .gitea/workflows/build.yml <<'YAML'
name: build
on: [push]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: show environment
        run: uname -a && docker version
YAML

Note the directory: Gitea looks in .gitea/workflows, not .github/workflows. Push a commit and watch the job in the web interface; the runner log on the host shows container creation, step output and exit status.

Verification checklist

  • Runner shows Idle in the admin UI rather than Offline.
  • Job picked up within seconds of the push, not queued with the label warning visible.
  • The runner can reach the Gitea URL used as ROOT_URL, both ways, from inside the job network.
  • Artifact and cache paths are on a volume with space — a full runner disk is the most common cause of inexplicable build failures.
  • Backup the runner's .runner file; re-registering is easy but unnecessary if you back it up.

If you run GitLab beside Gitea, the executor concepts and registration flow are compared in GitLab Runner registration and Docker executor, and a container registry with vulnerability scanning is a natural next step, as covered in Harbor registry vulnerability scanning.

原文链接:https://docs.gitea.com/usage/actions/act-runner