If you're tired of fighting with remote CI/CD pipelines and want full control over your Gitea workflows locally, setting up a Gitea instance with an Action Runner on your localhost is the way to go. This setup lets you:
- Test workflows without pushing to remote servers.
- Build and push Docker images using Buildx directly from your machine.
- Keep all your environment configuration versioned and portable.
In this guide, we'll go step by step, from file setup to running your first workflow.
Why Local Gitea + Runner?
You might ask: “Why not just use GitHub Actions or GitLab CI?”
Here’s the deal:
- Latency & control – Local runners respond instantly, no waiting for remote agents.
- Private environments – No need to expose your code or secrets to the cloud.
- Custom networking – You can test localhost services, webhooks, and Buildx setups without VPN or tunnels.
This is especially handy if you’re experimenting with self-hosted Docker registries, microservices, or multi-platform builds.
Setup Files
We’ll need a few files to configure everything:
1. ./token.txt
This is your registration token for the runner. Create it first; it’s empty initially:
<registration-token>
Later, you’ll paste the token provided by your Gitea instance. This approach avoids Docker creating a folder instead of a file.
2. ./config.yml
The runner needs to reach your localhost Gitea instance, so we configure it to use the host network:
container:
network: host
This is crucial for workflows that interact with services on your host machine, like Docker registries or APIs.
3. ./docker.compose.yml
Here’s the Docker Compose setup for Gitea and the Action Runner:
networks:
gitea-network:
external: false
services:
gitea:
image: gitea/gitea:1.24.6
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
volumes:
- ./data/gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- 3000:3000
networks:
- gitea-network
gitea-runner:
image: gitea/act_runner:0.2.13
container_name: gitea-runner
depends_on:
- gitea
networks:
- gitea-network
volumes:
- ./token.txt:/token.txt
- ./config.yml:/config.yml
- ./data/act_runner:/data
- ./data/cache:/root/.cache
- /var/run/docker.sock:/var/run/docker.sock
environment:
- CONFIG_FILE=/config.yml
- GITEA_INSTANCE_URL=http://gitea:3000/
- GITEA_RUNNER_REGISTRATION_TOKEN_FILE=/token.txt
restart: on-failure
Why each volume matters:
-
token.txt
– for secure registration. -
config.yml
– host network config. -
data/act_runner
– persists runner data between restarts. -
data/cache
– caches action downloads. -
/var/run/docker.sock
– allows the runner to control Docker on your host.
Running the Setup
- Start everything:
docker compose up -d
Paste the runner's registration token into
./token.txt
.Restart the runner to register:
docker compose restart gitea-runner
Tip: Check logs to confirm registration:
docker logs gitea-runner
Example Workflow
Let’s build a simple Docker image to test our setup.
Dockerfile
FROM busybox:1.36.1
CMD ["echo", "Hello world!"]
Gitea Workflow: ./gitea/workflows/example.yml
name: Workflow Example
on:
- push
jobs:
Build and push image:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup QEMU
uses: docker/setup-qemu-action@v3
- name: Setup Buildx
uses: docker/setup-buildx-action@v3
with:
driver-opts: network=host
- name: Login to registry
uses: docker/login-action@v2
with:
registry: http://localhost:3000
username: <username>
password: <application-token>
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: |
localhost:3000/${{ gitea.repository }}:latest
localhost:3000/${{ gitea.repository }}:${{ gitea.sha }}
Replace <username>
and <application-token>
with your Gitea credentials.
Now you have a fully functional local Gitea + Action Runner environment. You can:
- Test workflows instantly.
- Build Docker images locally using Buildx.
- Experiment with self-hosted CI/CD without touching the cloud.
From here, you can extend the setup: add multiple runners, connect to external registries, or integrate with other local services.
This tutorial was assisted by ChatGPT 5 Mini — your local AI sidekick.
Top comments (0)