Forgejo runner on NixOS

jacekpoz


published: 2024-05-25


last updated: 2024-05-26

time to read: 3:50 minutes


views:


# 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/jacekpoz.pl
  

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/jacekpoz.pl 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. All my info is on the main page, I'd be happy to help. :-)


(c) 2024 jacekpoz