The `Forgejo Runner` is a daemon that fetches workflows to run from a Forgejo instance, executes them, sends back with the logs and ultimately reports its success or failure.
It needs to be installed separately from the main Forgejo instance. For security reasons it is **not recommended** to install the runner on the same machine as the main instance.
Each `Forgejo Runner` release is published for all supported architectures as:
If the runner will be using Docker or Podman, ensure the `runner` user had access to the docker/podman socket.
If you are using Docker, run:
```shell
$ usermod -aG docker runner
```
### Setting up the container environment
The `Forgejo runner` relies on application containers (Docker, Podman, etc.) or system containers (LXC) to execute a workflow in an isolated environment. They need to be installed and configured independently.
- **Docker:**
See the [Docker installation](https://docs.docker.com/engine/install/) documentation for more information.
- **Podman:**
While Podman is generally compatible with Docker, it does not create a socket for managing containers by default (because it doesn't usually need one).
If the Forgejo runner complains about "daemon Docker Engine socket not found", or "cannot ping the docker daemon", you can use Podman to provide a Docker compatible socket from an unprivileged user and pass that socket on to the runner by executing:
For jobs to run in LXC containers, the `Forgejo runner` needs passwordless sudo access for all `lxc-*` commands on a Debian GNU/Linux `bookworm` system where [LXC](https://linuxcontainers.org/lxc/) is installed. The [LXC helpers](https://code.forgejo.org/forgejo/lxc-helpers/) can be used as follows to create a suitable container:
> **NOTE:** Multiarch [Go](https://go.dev/) builds and [binfmt](https://github.com/tonistiigi/binfmt) need `bookworm` to produce and test binaries on a single machine for people who do not have access to dedicated hardware. If this is not needed, installing the `Forgejo runner` on `bullseye` will also work.
The `Forgejo runner` can then be installed and run within the `myrunner` container.
> **Warning:** LXC containers do not provide a level of security that makes them safe for potentially malicious users to run jobs. They provide an excellent isolation for jobs that may accidentally damage the system they run on.
- **Host:**
There is no requirement for jobs that run directly on the host.
> **Warning:** there is no isolation at all and a single job can permanently destroy the host.
### Registering the runner
To receive tasks from the Forgejo instance, the runner needs to be registered.
To register the runner, switch user to the `runner` user account, and return to the home directory:
```shell
$ sudo su runner
$ whoami
runner
$ cd ~
$ pwd
/home/runner
```
From here, follow the [registration instructions](#standard-registration).
### Configuration
The default configuration for the runner can be
displayed with `forgejo-runner generate-config`, stored in a
`config.yml` file, modified and used instead of the default with the
`--config` flag.
```yaml
$ forgejo-runner generate-config > config.yml
# Example configuration file, it's safe to copy this as the default config file without any modification.
To automatically start the runner when the system starts, copy [this file](https://code.forgejo.org/forgejo/runner/src/branch/main/contrib/forgejo-runner.service) to `/etc/systemd/system/forgejo-runner.service`.
Then run `systemctl daemon-reload` to reload the unit files. Run `systemctl start forgejo-runner.service` to test the new service. If everything works, run `systemctl enable forgejo-runner.service` to enable auto-starting the service on boot.
Use `journalctl -u forgejo-runner.service` to read the runner logs.
## OCI image installation
The [OCI images](https://code.forgejo.org/forgejo/-/packages/container/runner/versions)
are built from the Dockerfile which is [found in the source directory](https://code.forgejo.org/forgejo/runner/src/branch/main/Dockerfile). It contains the `forgejo-runner` binary.
One way to run the Docker image is via Docker Compose. To do so, first prepare a `data` directory with non-root permissions (in this case, we pick `1001:1001`):
```shell
#!/usr/bin/env bash
set -e
mkdir -p data
touch data/.runner
mkdir -p data/.cache
chown -R 1001:1001 data/.runner
chown -R 1001:1001 data/.cache
chmod 775 data/.runner
chmod 775 data/.cache
chmod g+s data/.runner
chmod g+s data/.cache
```
After running this script with `bash setup.sh`, define the following `docker-compose.yml`:
Here, we're not running the `forgejo-runner daemon` yet because we need to register it first. Please note that in a recent install of docker `docker-compose` is not a separate command but should be run as `docker compose`.
Follow the [registration instructions](#standard-registration) below by starting the `runner` service with `docker-compose up -d` and entering it via:
```shell
docker exec -it runner /bin/sh
```
In this shell, run the `forgejo-runner register` command as described below. After that is done, take the service down again with `docker-compose down` and modify the `command` to:
Here, the sleep allows the `docker-in-docker` service to start up before the `forgejo-runner daemon` is started.
More [docker compose](https://docs.docker.com/compose/) examples [are provided](https://codeberg.org/forgejo/runner/src/branch/main/examples/docker-compose) to demonstrate how to install the OCI image to successfully run a workflow.
## Standard registration
The `Forgejo runner` needs to connect to a `Forgejo` instance and must be registered before doing so. It will give it permission to read the repositories and send back information to `Forgejo` such as the logs or its status.
A special kind of token is needed and can be obtained from the `Create new runner` button:
- in `/admin/actions/runners` to accept workflows from all repositories.
- in `/org/{org}/settings/actions/runners` to accept workflows from all repositories within the organization.
- in `/user/settings/actions/runners` to accept workflows from all repositories of the logged in user
- in `/{owner}/{repository}/settings/actions/runners` to accept workflows from a single repository.
INFO Enter the Forgejo instance URL (for example, https://next.forgejo.org/):
https://code.forgejo.org/
INFO Enter the runner token:
6om01axzegBu98YCpsFtda4Go2DuJe7BEepzz2F3HY
INFO Enter the runner name (if set empty, use hostname: runner-host):
my-forgejo-runner
INFO Enter the runner labels, leave blank to use the default labels (comma-separated, for example, ubuntu-20.04:docker://node:20-bookworm,ubuntu-18.04:docker://node:20-bookworm):
INFO Registering runner, name=my-forgejo-runner, instance=https://code.forgejo.org/, labels=[docker:docker://node:20-bullseye].
DEBU Successfully pinged the Forgejo instance server
INFO Runner registered successfully.
```
This will create a `.runner` file in the current directory that looks like:
```json
{
"WARNING": "This file is automatically generated by act-runner. Do not edit it manually unless you know what you are doing. Removing this file will cause act runner to re-register as a new runner.",
To decide which labels to use, see [Choosing labels](../actions/#choosing-labels).
The same token can be used multiple times to register any number of runners, independent of each other.
## Offline registration
When Infrastructure as Code (Ansible, kubernetes, etc.) is used to deploy and configure both Forgejo and the Forgejo runner, it may be more convenient for it to generate a secret and share it with both.
The `forgejo forgejo-cli actions register --secret <secret>` subcommand can be used to register the runner with the Forgejo instance and the `forgejo-runner create-runner-file --secret <secret>` subcommand can be used to configure the Forgejo runner with the credentials that will allow it to start picking up tasks from the Forgejo instances as soon as it comes online.
The secret must be a 40-character long string of hexadecimal numbers. The first 16 characters will be used as an identifier for the runner, while the rest is the actual secret. It is possible to update the secret of an existing runner by running the command again on the Forgejo machine, with the last 24 characters updated.
For instance, the command below would change the secret set by the previous command:
The registration command on the Forgejo side is mostly idempotent, with the exception of the runner labels. If the command is run without `--labels`, they will be reset, and the runner won't set them back until it is restarted. The `--keep-labels` option can be used to preserve the existing labels.
## Enabling IPv6 in Docker & Podman networks
When a `Forgejo runner` creates its own Docker or Podman networks, IPv6 is not enabled by default, and must be enabled explicitly in the `Forgejo runner` configuration.
**Docker only**: The Docker daemon requires additional configuration to enable IPv6. To make use of IPv6 with Docker, you need to provide a `/etc/docker/daemon.json` configuration file with at least the following keys:
```json
{
"ipv6": true,
"experimental": true,
"ip6tables": true,
"fixed-cidr-v6": "fd00:d0ca:1::/64",
"default-address-pools": [
{ "base": "172.17.0.0/16", "size": 24 },
{ "base": "fd00:d0ca:2::/104", "size": 112 }
]
}
```
Afterwards restart the Docker daemon with `systemctl restart docker.service`.
> **NOTE**: These are example values. While this setup should work out of the box, it may not meet your requirements. Please refer to the Docker documentation regarding [enabling IPv6](https://docs.docker.com/config/daemon/ipv6/#use-ipv6-for-the-default-bridge-network) and [allocating IPv6 addresses to subnets dynamically](https://docs.docker.com/config/daemon/ipv6/#dynamic-ipv6-subnet-allocation).
**Docker & Podman**:
To test IPv6 connectivity in `Forgejo runner`-created networks, create a small workflow such as the following:
```yaml
---
on: push
jobs:
ipv6:
runs-on: docker
steps:
- run: |
apt update; apt install --yes curl
curl -s -o /dev/null http://ipv6.google.com
```
If you run this action with `forgejo-runner exec`, you should expect this job fail:
[ipv6.yml/ipv6] Cleaning up container for job ipv6
[ipv6.yml/ipv6] Cleaning up network for job ipv6, and network name is: FORGEJO-ACTIONS-TASK-push_WORKFLOW-ipv6-yml_JOB-ipv6-network
[ipv6.yml/ipv6] 🏁 Job failed
```
To actually enable IPv6 with `forgejo-runner exec`, the flag `--enable-ipv6` must be provided. If you run this again with `forgejo-runner exec --enable-ipv6`, the job should succeed:
[ipv6.yml/ipv6] Cleaning up container for job ipv6
[ipv6.yml/ipv6] Cleaning up network for job ipv6, and network name is: FORGEJO-ACTIONS-TASK-push_WORKFLOW-ipv6-yml_JOB-ipv6-network
[ipv6.yml/ipv6] 🏁 Job succeeded
```
Finally, if this test was successful, enable IPv6 in the `config.yml` file of the `Forgejo runner` daemon and restart the daemon:
```yaml
container:
enable_ipv6: true
```
Now, `Forgejo runner` will create networks with IPv6 enabled, and workflow containers will be assigned addresses from the pools defined in the Docker daemon configuration.
## Packaging
### NixOS
The [`forgejo-actions-runner`](https://github.com/NixOS/nixpkgs/blob/ac6977498b1246f21af08f3cf25ea7b602d94b99/pkgs/development/tools/continuous-integration/forgejo-actions-runner/default.nix) recipe is released in NixOS.
Please note that the `services.forgejo-actions-runner.instances.<name>.labels` key may be set to `[]` (an empty list) to use the packaged Forgejo instance list. One of `virtualisation.docker.enable` or `virtualisation.podman.enable` will need to be set. The default Forgejo image list is populated with docker images.
IPv6 support is not enabled by default for docker. The following snippet enables this.
```nix
virtualisation.docker = {
daemon.settings = {
fixed-cidr-v6 = "fd00::/80";
ipv6 = true;
};
};
```
If you would like to use docker runners in combination with [cache actions](#cache-configuration), be sure to add docker bridge interfaces "br-\*" to the firewalls' trusted interfaces: