DEV Community

Audi Nugraha
Audi Nugraha

Posted on

Gitea + Action Runner on Localhost: Full Setup Guide for Developers

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:

  1. Latency & control – Local runners respond instantly, no waiting for remote agents.
  2. Private environments – No need to expose your code or secrets to the cloud.
  3. 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>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

  1. Start everything:
docker compose up -d
Enter fullscreen mode Exit fullscreen mode
  1. Paste the runner's registration token into ./token.txt.

  2. Restart the runner to register:

docker compose restart gitea-runner
Enter fullscreen mode Exit fullscreen mode

Tip: Check logs to confirm registration:

docker logs gitea-runner
Enter fullscreen mode Exit fullscreen mode

Example Workflow

Let’s build a simple Docker image to test our setup.

Dockerfile

FROM busybox:1.36.1
CMD ["echo", "Hello world!"]
Enter fullscreen mode Exit fullscreen mode

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 }}
Enter fullscreen mode Exit fullscreen mode

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)