Forgejo runner on NixOS


# Introduction

Starting out I had a simple goal - get my server to automatically rebuild and deploy this site on each commit. I didn't want to use docker so most of the guides online were out of the question.

It took a while but I got it running. To save you similar pain I wanted to document how to get it running.

I didn't find any sources specifically on this online (other than the module's documentation) so I decided to make my own.

This post assumes familiarity with agenix and an already running Forgejo instance using the NixOS module.


# TL;DR

relevant parts of my module


# Resources I used


# Security

The runner executes commands on the host machine - there is no sandboxing, it can destroy your machine. To quote the documentation: "Warning: there is no isolation at all and a single job can permanently destroy the host."

Make sure not to register your runner through the Site Administration menu - it will become global and available to every user on your instance. Refer to the registration section for more information.


# The module

This is the config for my runner. It's on the same machine as the Forgejo instance, it uses no containers.


    services.gitea-actions-runner = {
      package = pkgs.forgejo-runner;
      instances = {
        chmura = {
          enable = true;
          name = config.networking.hostName;
          url = "http://localhost:${toString config.services.forgejo.settings.server.HTTP_PORT}";
          tokenFile = config.age.secrets.forgejo-runner-token.path;
          labels = [
            "native:host"
          ];
          hostPackages = with pkgs; [
            nix
            nodejs
            git
            bash
            fd
            ripgrep
          ];
          settings = {
            log.level = "info";
            runner = {
              file = ".runner";
              capacity = 2;
              timeout = "3h";
              insecure = false;
              fetch_timeout = "5s";
              fetch_interval = "2s";
            };
          };
        };
      };
    };
  

# name

In the instances attrset I only have a single runner, as I don't need any more. I might setup a second one on another machine - if you want to read about that, let me know!

I'm not sure if instances.<name> and instances.<name>.name have to be set to the same string. The module sets the latter to your hostname, I did that for both just to be safe.

This will create a systemd service with the name gitea-runner-<name>.

# url

Since I'm running both Forgejo and the runner on the same machine I just point at its port on localhost. I'm not sure whether I should use http or https there; it's the same machine so there shouldn't be any issues with http.

# tokenFile

Explained in the registration section of the Forgejo documentation, standard agenix setup aside from that.

# labels

As I don't use any containers and want the runner to use the host machine, I created a native label and made it run on host. There's a bit more to know here if you want to do stuff on the host machine, I'll get to that later.

# hostPackages

A list of packages available to the runner. The default one unfortunately doesn't include nix, I added fd and rg for convenience when writing workflows.

# settings

Explained in the configuration section of the Forgejo documentation, I kept them there to make sure they're actually being set and for myself.


# Workflows

So far I only wrote a single workflow - the one that builds and deploys the website. It's simple but I spend around half a day figuring out how to make it work:


    name: Deploy website

    on:
      push:
        branches:
          - master
        paths:
          - 'front/**'
          - '.forgejo/workflows/deploy-front.yaml'

    jobs:
      deploy:
        runs-on: native
        steps:
          - uses: actions/checkout@v3
          - run: |
              nix build -L .#pozfront -o /srv/web/poz.pet
  

This is mostly standard GitHub Actions stuff, if you ever used that you should be familiar with this. Notice the runs-on: native - there is no container here.

Now, the part I spent half a day on: by default the runner only has permissions for its WorkingDirectory. This means the -o /srv/web/poz.pet will fail. To get around that, manually add the directories to the service's ReadWritePaths:


    systemd.services.gitea-runner-chmura.serviceConfig = {
        ReadWritePaths = "/srv/web";
    };
  

I'm certain there is a nicer way to do this, I might improve it and post an update. The ideal way would probably be to make a PR to the NixOS module but right now this works with no issues and that's what's important here.


That's it! You should now have a declaratively configured Forgejo runner on your host machine with no containers.

As always, if that's not the case feel free to contact me for help. I'd be happy to help! :-)

Post licensed under the CC BY-SA 4.0