Playing around with Gitea Actions on Fly.io

A proof of concept for running the Gitea Actions runner on Fly.io

Fly.io is a "serverless" hosting platform usually used for web services, but it can also run long-running tasks. I wanted to try running the Gitea Actions runner there.

Treat this as a proof of concept. There are better ways to do this, but it still was fun to try.

To keep the experiment simple, I ran the runner in "host" mode. Jobs run directly on the host rather than in containers, which kept Docker-in-Docker debugging out of the initial setup.

To get started, I created a new Fly.io app with the following configuration:

# fly.toml
app = "actions-on-fly"
primary_region = "ams"

[[mounts]]
  destination = "/data"
  source = "data"

I mounted a persistent volume to /data so the runner registration persists across restarts.

Since there were no prebuilt Docker images as of publication, I created one and installed the runner in it. The Dockerfile is as follows:

# Dockerfile
FROM ghcr.io/catthehacker/ubuntu:act-latest
# the FROM image is based on ubuntu and has appropriate tools installed to run Gitea Actions

# install act_runner
RUN curl https://dl.gitea.com/act_runner/nightly/act_runner-nightly-linux-amd64 > /usr/local/bin/act_runner && \
    chmod +x /usr/local/bin/act_runner

# add start script
ADD start.sh /start.sh
RUN chmod +x /start.sh && mkdir -p /data
ENTRYPOINT ["/start.sh"]

At startup, the container checks whether the runner is already registered and registers it if needed. The registration token comes from an environment variable, and then the runner starts.

#!/bin/bash
# start.sh

# $ACTIONS_REGISTER_TOKEN is the registration token for the runner that is given by the Gitea runner settings page.

# set /data as the working dir
cd /data

# check if runner is already registered, and if not register it
if [ ! -f .runner ]; then
  # register runner on gitea.com, and set label as fly-runner so it runs as "host" mode
  act_runner register --no-interactive --instance "https://gitea.com" --labels "fly-runner" --token $ACTIONS_REGISTER_TOKEN
fi

# start runner
act_runner daemon

It took only a handful of lines to get the runner working on Fly.io. The issue I ran into was memory: Fly.io terminates apps when they run out of memory. The workload I was testing needed more memory, so I increased the limit. Memory-heavy jobs may therefore need a larger machine than the default configuration.

This remains a proof of concept rather than a recommendation. The blog you are reading right now is built using this runner.

Editor's Note: This blog is no longer built using this approach, but still uses Gitea Actions to build and publish. The post is kept as historical reference.