# gitea-runner Self-hosted [Gitea Actions](https://docs.gitea.com/usage/actions/overview) runner. Polls `gitea.phasefinal.com` for jobs from any repo that has a `.gitea/workflows/` directory and runs them in ephemeral docker containers on this host. **Server:** ana-docker (single central runner — see "Topology" below for when to add more) **Image:** `gitea/act_runner:latest` **Outbound only** — no host port published; the runner connects out to gitea, gitea never connects in. ## Topology We run **one central runner on ana-docker**. Reasoning: - gitea is on ana-docker, so runner→API is local - existing fleet tooling (`elway`, `sync-stacks`, `deploy-stack`, `refresh-server-info`) already SSHes from one origin to all hosts; the runner inherits that pattern - single point to manage SSH keys, secrets, and runner upgrades The deploy playbook (`playbooks/deploy-gitea-runner.yaml`) is parameterized by host / runner-name / labels, so spinning up `nh3-docker-runner` or an ESH runner later is a one-line elway invocation — not a copy-pasted playbook. **When to add a site-local runner:** - Cross-site SSH from ana-docker to that site has become unreliable - A workflow needs LAN access to something only reachable from inside that site's network segment - You want failure isolation (NH3 can deploy itself when Anaheim is down) Until one of those bites, one runner is enough. ## Prereqs Before running the deploy playbook: 1. **Verify Gitea Actions is enabled.** In gitea 1.21+ Actions ships on by default, but check `/-/admin/actions` resolves. If not, add `GITEA__actions__ENABLED=true` to the gitea stack env and bounce. 2. **Generate a registration token.** Pick the scope: | Scope | URL | Use when | |---|---|---| | Global (admin) | `https://gitea.phasefinal.com/-/admin/actions/runners` | runner serves any repo on the instance (recommended for the central PFI runner) | | Org/user | `https://gitea.phasefinal.com//-/actions/runners` | runner serves all repos under one owner | | Repo | `https://gitea.phasefinal.com///settings/actions/runners` | runner serves one repo | Register-as-admin is right for our use case: one runner, fleet-wide. 3. **Create an SSH deploy key for the runner** that lets it execute the elway playbooks against fleet hosts. The key lives only on ana-docker (passed in as a workflow secret per repo, or mounted into the runner via volume — see "Wiring deploys" below). 4. **(Optional) Create a Gitea PAT** with `read:repository` scope on `vh/esh-pfi-infrastructure`. Workflows need to check out the management repo to get at the playbooks; the auto-injected `GITHUB_TOKEN` only works for the triggering repo. ## Deploy ```bash # Edit .env first if not using defaults — at minimum paste the registration token $EDITOR stacks/gitea-runner/.env.example # template # First-time deploy scripts/elway ana-docker --playbook playbooks/deploy-gitea-runner.yaml # Site-local runner later (NH3 or ESH) scripts/elway nh3-docker --playbook playbooks/deploy-gitea-runner.yaml \ --var runner_name=nh3-docker-runner --var runner_labels=pfi-fleet,nh3-docker ``` The playbook seeds `.env` from `.env.example` only if absent; for the first run, copy `.env.example` to `/opt/docker/compose/gitea-runner/.env` on the host and paste the registration token in before running, OR let the playbook seed it and edit on the host before the `docker compose up -d` step (it's idempotent — second run will pick up the edited token). After successful registration, the token is consumed (it's one-time use). You can clear `GITEA_RUNNER_REGISTRATION_TOKEN` from `.env`; the runner reads its permanent credentials from `${DATA_DIR}/.runner` on subsequent starts. ## Wiring deploys A workflow that runs on the central runner needs three things: 1. **`runs-on:`** matching a runner label — `pfi-fleet` (cross-fleet) or `ana-docker` (pin to that host). 2. **An SSH key** to reach the deploy target. Stored as a repo or org-level Actions secret named e.g. `DEPLOY_SSH_KEY`. The corresponding public key must be in `~lkraven/.ssh/authorized_keys` on every host the workflow targets. 3. **A token to clone `vh/esh-pfi-infrastructure`** if the workflow wants to invoke an elway playbook from this repo. Stored as `MGMT_REPO_TOKEN` (Gitea PAT, `read:repository` scope). See `stacks/task-board/gitea-workflow-deploy.yaml.example` for a complete deploy workflow that consumes all three. ## Path layout (on ana-docker) | Host path | Container path | Purpose | Restic? | |---|---|---|---| | `/opt/docker/compose/gitea-runner/` | — | compose.yaml + .env | included (via `/opt/docker`) | | `/opt/docker/conf/gitea-runner/data/` | `/data` | `.runner` creds, cache, job workspaces | excluded (regenerable; nothing irreplaceable) | ## Operations ```bash # Tail runner logs ssh ana-docker docker logs -f gitea-runner # List currently registered runners (admin) # https://gitea.phasefinal.com/-/admin/actions/runners # Re-register (lost the .runner file? regenerate token, then:) ssh ana-docker docker compose -f /opt/docker/compose/gitea-runner/compose.yaml down ssh ana-docker rm /opt/docker/conf/gitea-runner/data/.runner # paste new GITEA_RUNNER_REGISTRATION_TOKEN into .env scripts/elway ana-docker --playbook playbooks/deploy-gitea-runner.yaml # Pin to a specific act_runner version # Edit RUNNER_IMAGE in /opt/docker/compose/gitea-runner/.env, then: scripts/elway ana-docker --playbook playbooks/deploy-gitea-runner.yaml ```