1
0
Fork
You've already forked codeberg-actions
0
How to configure self-hosted CI with codeberg
2026年04月19日 08:36:45 +02:00
LICENSE Initial commit 2026年04月17日 20:07:14 +02:00
README.md Actualiser README.md 2026年04月19日 08:36:45 +02:00

codeberg-actions

Setting up CI with Codeberg.org

Codeberg runs Woodpecker CI and, more recently, Actions. They have limited resources, unlike GitHub aka Microsoft, so they will only run Woodpecker for you if you ask nicely.

But you can set up your own CI machine, self-hosted.

This is how I set this up with a spare ArchLinux machine I had idling.

sudo pacman -S forgejo-runner

The Arch package assumed Docker. I don't like that. I want podman so I can run rootless 1

Also my system has /var too small to store a bunch of containers, so I wanted to put it on /home.

I made some (fragile) patches to get this to work for me:

  1. sudo userdel -r forgejo-runner; sudo useradd -m -d /home/forgejo-runner forgejo-runner

    This moves the homedir, sets the shell to /bin/bash instead of /bin/nologin, but more importantly it writes /etc/subuid and /etc/subgid; by default forgejo-runner installs as a system account, which means it does not have subuid rights, which means rootless podman doesn't work. You could do this without deleting the account, by editing /etc/subuid yourself, but it's simpler to get the math right this way.

  2. sudo systemctl edit --full --force forgejo-podman

    This is needed because forgejo-runner expects to be able to talk to a docker socket.

    [Unit]
    Description=Podman Socket for forgejo-runner
    [Service]
    # https://forgejo.org/docs/v11.0/admin/actions/runner-installation/#setting-up-the-container-environment
    User=forgejo-runner
    Group=forgejo-runner
    ExecStart=/usr/bin/podman system service -t 0
    Restart=on-failure
    [Install]
    WantedBy=multi-user.target
    
    sudo systemctl enable --now forgejo-podman
    
  3. sudo su -l forgejo-runner; make sure podman run --rm -it ubuntu:latest works.

  4. Now, getting the service registered was confusing. The forgejo docs don't quite seem to line up with the codeberg docs.

I ended up doing this. This was the fiddliest part:

  1. Go to https://codeberg.org/user/settings/actions/runners and get a REGISTRATION token from "Create new Runner"
  2. as forgejo-runner, run forgejo-runner register pass the registration token in to the prompts
  3. mv .runner .runner.disabled; cat .runner.disabled -> get the UUID and the long term token

Then run uuidgen to get a UUID, and edit /etc/forgejo-runner/config.yaml with

 connections:
 codeberg:
 url: https://codeberg.org/
 uuid: YOUR_UUID
 token: YOUR_LONG_TERM_TOKEN
 labels:
 - archlinux:docker://docker.io/library/archlinux:latest
 - ubuntu-latest:docker://library/ubuntu:24.04
 - python-3.12:docker://docker.io/library/python:3.12
 - python-3.13:docker://docker.io/library/python:3.13
 - python-3.14:docker://docker.io/library/python:3.14

The 'labels' you add are the platforms users can 'runs-on' in their workflow scripts.

  1. I also changed /etc/forgejo-runner/config.yaml to say
runner:
 # increase how many parallel jobs we can handle
 capacity: 4
 # shorten how long each job can run
 timeout: 30m
  1. sudo systemctl edit --full forgejo-runner to tell it about podman and about its new homedir:

    WorkingDirectory=/home/forgejo-runner
    Environment="DOCKER_HOST=unix:///var/run/user/1004/podman/podman.sock"
    

    1004 is from id forgejo-runner so that needs to adapt to your system.

  2. Finally turn it on:

sudo systemctl enable --now forgejo-runner

Monitor with

sudo journalctl -lfu forgejo-runner

and look at https://codeberg.org/user/settings/actions/runners to see if it's detected by Codeberg.

If it's not launching right, it helps to troubleshoot by running it manually (as the forgejo-runner user)

DOCKER_HOST=unix:///var/run/user/1004/podman/podman.sock /usr/bin/forgejo-runner daemon --config /etc/forgejo-runner/config.yaml

Security

Set up subnet isolation so the forgejo-runner can't see your LAN:

# ~/.config/containers/containers.conf 
[containers]
netns = "podman"
#!/bin/sh
set -e
nft add chain inet filter output { type filter hook output priority 0 \; policy accept \; }
# Allow DNS to anywhere
for protocol in tcp udp; do
 nft add rule inet filter output meta skuid forgejo-runner ${protocol} dport 53 accept
done
# Block everything else
for range in 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 127.0.0.0/8 169.254.0.0/16; do
 nft add rule inet filter output meta skuid forgejo-runner ip daddr $range drop
done
for range in fc00::/7 fe80::/10 ::1/128; do
 nft add rule inet filter output meta skuid forgejo-runner ip6 daddr $range drop
done

Run

sudo sh ./block.sh
# After testing a bit, save changes:
sudo nft list ruleset | sudo tee /etc/nftables.conf

Review: https://forgejo.org/docs/latest/admin/actions/security

  • Test if runners have access to the docker socket for possible container escape

Usage

Actions is disabled by default on every repo. For each repo, need to go to https://codeberg.org/$OWNER/$REPO/settings/units and enable Actions. When you do that, an 'Actions' table will show up.

Forgejo-actions is mostly Github-actions compatible, but there's some limitations and differences. Create workflow files in .forgejo/workflows/ in your projects instead of .github/workflows; it will try to run .github/workflows scripts too, but many of them will probably break! You need to port pre-existing workflows.

  1. 'runs-on' is defined by the 'labels' of the runner's config. You can see available labels in https://codeberg.org/user/settings/actions/runners.
  2. To see what you can 'uses:', look in https://data.forgejo.org/actions/ (you can't see their contents directly but you can git clone each)
    1. in particular, there's actions/forgejo-release and actions/upload-artifact and actions/download-artifact which are a bit different than the github versions.
    2. You can also 'uses' actions directly github by prefixing 'https://github.com/' e.g. uses: https://github.com/pypa/gh-action-pypi-publish@release/v1; but a lot of Actions on github are going to assume they can use the github API and not everything is compatible.

  1. other options are lxc, or 'host' most, meaning no containerization which might be safe if wrapped in a systemd service that launches everything in an ephemeral temporary HOME; I haven't investigated this yet. HOST mode would be useful to speed up testing because most of the tool installs in a workflow could be skipped. ↩︎