UP | HOME

Table of Contents

#+title [20jun2026] setting up container registry on forgejo

1. Problem

I want to setup a forgejo runner using a custom docker container. Have done something similar on github; I understand the forgejo works similarly.

See forgejo-at-digital-ocean for initial forgejo setup.

2. Container

We have docker-xo-builder added to xo-umbrella2 at xo-umbrella2/pkgs/docker-xo-builer.nix.

To establish nix store location:

$ cd ~/proj/xo-umbrella2
$ nix-build -A xo.docker-xo-builder
/home/roland/nixroot/nix/store/3qw6x1vhcry4v1zs18n8hcqab5mwbmjs-docker-xo-builder.tar.gz
$ ls -l $(readlink -f result)
/home/roland/nixroot/nix/store/3qw6x1vhcry4v1zs18n8hcqab5mwbmjs-docker-xo-builder.tar.gz

We will be uploading this container to docker, and pushing it to forgejo

3. Nginx

3.1. Configure

There's a constraint around how the container registry presents. Forgejo insists that this appears at the domain root, so containers appear under https://conybeare.us/v2/, not https://conybeare.us/git/v2 (even though forgejo itself is proxied via nginx from https://conybeare.us/git)

Additional /etc/nginx/nginx.conf setup:

http {
    ...

    # forgejo
        location /git/ { ... }  # existing

    # forgejo container registry
        location /v2 {
            client_max_body_size 0;
                proxy_request_buffering off;
                proxy_pass https://127.0.0.1:3000;
                proxy_set_header Host $host
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
        }
}

Omitting the trailing slash in location /v2 causes /v2/... to reach forgejo unaltered. This works because forgejo mounts its container-registry at /v2 instead of at /git/v2.

3.2. Test

Ask nginx to verify configuration:

sudo bash
nix run /etc/nginx/nix@nginx -- -t

Then restart:

sudo systemctl reload nginx

Verify routing

$ curl -i https://conybeare.us/v2
HTTP/2 401 
server: nginx/1.30.1
date: Sun, 21 Jun 2026 22:47:31 GMT
content-type: application/json
content-length: 50
docker-distribution-api-version: registry/2.0
www-authenticate: Bearer realm="https://conybeare.us/git/v2/token",service="container_registry",scope="*"

{"errors":[{"code":"UNAUTHORIZED","message":""}]}

Here:

HTTP/2 401
"who are you?"
docker-distribution-api-version
forgejo is answering, and it's at the root
https://conybeare.us/git/v2/token
tells docker where to fetch a token. Now under git

4. Forgejo

Create token (visit https://conybeare.us/git | Settings | Applications | Generate Token). We need the token to have write:package permission

We need to give that token to docker:

5. Docker (roly-chicago-24)

(on roly-chicago-24, not vpn1):

$ docker login conybeare.us -u roland
Password: <token per forgejo above>

WARNING! Your credentials are stored unencrypted in '/home/roland/.docker/config.json'.
Configure a credential helper to remove this warning. See
https://docs.docker.com/go/credential-store/

Login Succeeded
$

Next add the docker-xo-builder image

# roly-chicago-24

$ cd ~/proj/xo-umbrella2
$ docker load < $(readlink -f result)
$ docker tag docker-xo-builder:v1 conybeare.us/roland/docker-xo-builder:v1
$ docker push conybeare.us/roland/docker-xo-builder:v1

The last step runs for a while, it has ~331MB of layers to upload.

Once this is done, we can see uploaded package here: https://conybeare.us/git/roland/-/packages

6. Docker (vpn1)

We want docker on vpn1 itself

# vpn1
$ sudo apt-get install docker.io
...

We also need to add the forgejo-runner account to the docker group

# vpn1
$ sudo usermod -aG docker forgejo-runner
$ sudo systemctl restart forgejo-runner

The updated forgejo-runner can open docker.sock to spawn job containers, but we need to give it a label for our new image:

# /etc/forgejo-runner/config.yaml
runner:
  labels:
    - "host:host"
    - "xo-builder:docker://conybeare.us/roland/docker-xo-builder:v1"

and restart

$ sudo systemctl restart forgejo-runner

Created: 2026-08-16 Sun 16:46

Validate