# SOP-003: Gitea Actions Runner Setup (Heimdall) **Status:** Active **Created:** June 2, 2026 **Last Updated:** June 2, 2026 **Owner:** Nathan Castaldi **Applies To:** Gitea Actions auto-deploy workflow --- ## Purpose Install and register a Gitea Actions runner on Heimdall so that the `.gitea/workflows/auto-deploy.yml` workflow can execute when PRs are merged to `main`. The runner calls the Komodo REST API to redeploy any stack whose folder changed in the push — no per-stack webhook URLs required. --- ## Prerequisites - [ ] SSH access to Heimdall (`10.0.0.151`) - [ ] Docker and Docker Compose running on Heimdall - [ ] Gitea instance accessible at `https://git.castaldifamily.com` - [ ] Admin or repo-owner access to the `nathan/homelab` Gitea repository - [ ] Komodo service user created with Stack → Execute permissions (see [Step 4](#step-4--create-komodo-service-user-and-api-key)) - [ ] API key + secret copied and ready to add as Gitea secrets --- ## Step 1 — Retrieve a Runner Registration Token 1. In Gitea, go to **Repository** → `nathan/homelab` → **Settings** → **Actions** → **Runners** 2. Click **Create new Runner** 3. Copy the **registration token** — you will need it in Step 3 > **Note:** Tokens are single-use. If you lose it, generate a new one. --- ## Step 2 — Create the Runner Compose File on Heimdall SSH into Heimdall and create the runner stack directory: ```bash mkdir -p /opt/gitea-runner ``` Create `/opt/gitea-runner/compose.yaml`: ```yaml name: gitea-runner services: runner: image: gitea/act_runner:latest container_name: gitea-runner restart: unless-stopped environment: GITEA_INSTANCE_URL: "https://git.castaldifamily.com" GITEA_RUNNER_REGISTRATION_TOKEN: "${GITEA_RUNNER_REGISTRATION_TOKEN}" GITEA_RUNNER_NAME: "heimdall-runner" GITEA_RUNNER_LABELS: "ubuntu-latest:docker://node:20-bullseye-slim" volumes: - /var/run/docker.sock:/var/run/docker.sock - runner-data:/data volumes: runner-data: ``` Create `/opt/gitea-runner/.env`: ```env GITEA_RUNNER_REGISTRATION_TOKEN= ``` > **Security:** The `.env` file contains a credential. Do not commit it to Git. > The token is consumed on first registration; after that the runner stores its > own credentials in the `runner-data` volume. --- ## Step 3 — Start the Runner ```bash cd /opt/gitea-runner docker compose up -d ``` Watch the startup logs to confirm registration: ```bash docker compose logs -f runner ``` Expected output (within ~10 seconds): ``` INFO Registering runner ... runner=heimdall-runner INFO Runner registered successfully. INFO Starting runner ... name=heimdall-runner ``` Verify the runner appears in Gitea: - Go to **Repository** → **Settings** → **Actions** → **Runners** - `heimdall-runner` should show **Online** --- ## Step 4 — Create Komodo Service User and API Key The workflow authenticates to Komodo using a dedicated service user with minimal permissions. Do not use your personal admin account. ### 4a — Create the service user 1. Log into Komodo UI (`https://komodo.castaldifamily.com`) 2. Go to **Settings** → **Users** → **New User** 3. Set type to **Service** 4. Name it something like `gitea-ci` 5. Grant **Execute** permission on **Stacks** only — no write or delete access 6. Save the user ### 4b — Generate an API key 1. Open the `gitea-ci` user → **Api Keys** → **New Api Key** 2. Copy both the **key** and the **secret** immediately — the secret is not shown again ### 4c — Add secrets to Gitea In Gitea: **Repository** → **Settings** → **Secrets and Variables** → **Actions** → **New secret** Add all three: | Secret name | Value | |---|---| | `KOMODO_URL` | `https://komodo.castaldifamily.com` | | `KOMODO_API_KEY` | API key from step 4b | | `KOMODO_API_SECRET` | API secret from step 4b | > **Security:** Never commit these values to the repo. The workflow reads them > from Gitea secrets at runtime. --- ## Step 5 — Verify End-to-End 1. Make a trivial change to any stack folder (e.g., add a blank line to `nodes/heimdall/sonarr/compose.yaml`) 2. Commit and push directly to `main` (or merge a PR) 3. In Gitea, go to **Repository** → **Actions** — the `Auto-Deploy Changed Stacks` run should appear 4. Click the run → expand the **Detect changed stacks and trigger Komodo webhooks** step 5. Confirm output resembles: ``` === Changed files === nodes/heimdall/sonarr/compose.yaml Queued for deploy: sonarr (node: heimdall) === Triggering Komodo deployments === → sonarr ... HTTP 200 OK All deployments triggered successfully. ``` 6. In Komodo UI, verify the `sonarr` stack shows a recent deployment event --- ## Troubleshooting | Symptom | Check | |---|---| | Runner shows **Offline** in Gitea | `docker compose logs runner` on Heimdall; check `GITEA_INSTANCE_URL` reachability | | Job never picks up | Runner label must match `runs-on` in the workflow (`ubuntu-latest`) | | `HTTP 401` / `403` on DeployStack call | Check `KOMODO_API_KEY` / `KOMODO_API_SECRET` secrets are set correctly in Gitea | | `HTTP 404` on DeployStack call | Stack name in repo folder does not match the name registered in Komodo UI | | `HTTP 404` logged as WARNING, not failure | Expected — stack exists in repo but isn't registered in Komodo yet | | Job shows `HEAD~1` diff error | Ensure `fetch-depth: 2` is set in the checkout step | --- ## Rollback To stop the runner without removing its registration: ```bash cd /opt/gitea-runner && docker compose stop runner ``` To fully deregister and remove: ```bash cd /opt/gitea-runner && docker compose down -v ``` Then delete the runner from **Gitea → Repository → Settings → Actions → Runners**.