Gitea self-hosted runners

I just fired up a local instance of Gitea for stuff I don’t want Micro$oft and GitHub training CoPilot on, or want anyone else scraping. However, one challenge with such a setup is running your trusty CI/CD workflows without GitHub’s infrastructure.

Docker Compose to the rescue! After some wrong turns and some rubber ducking with Claude, I managed to construct a relatively simple Docker Compose file to keep a minimum number of ephemeral runner replicas up and registered with Gitea without requiring a complex Kubernetes setup.

services:
  gitea-runner:
    image: docker.io/gitea/act_runner:nightly
    restart: always
    environment:
      GITEA_INSTANCE_URL: "XXX"
      GITEA_RUNNER_REGISTRATION_TOKEN: "XXX"
      GITEA_RUNNER_EPHEMERAL: 1
    deploy:
      replicas: 4
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    tmpfs:
      - /data
    entrypoint: /bin/sh
    command:
      - -c
      - |
        # Remove any existing registration
        rm -f /data/.runner
        # Register the runner
        act_runner register --no-interactive \
          --instance "$${GITEA_INSTANCE_URL}" \
          --token "$${GITEA_RUNNER_REGISTRATION_TOKEN}" \
          --ephemeral
        # Start the daemon in ephemeral mode
        act_runner daemon

Now I can have my self-hosted Gitea instance run the same CI/CD jobs that GitHub used to. The runners are fairly lightweight, so they run fine on the same Proxmox VE VM I have allocated for Gitea itself (12C / 8G RAM / 256G SSD). Hope this helps someone else navigating the self-hosted world!