Files

3.2 KiB

homelab-infra

Shared CI/CD templates, base Dockerfiles, and compose snippets for all homelab projects. Change once here, every project picks it up.

Repo structure

.gitea/workflows/
  build-and-push.yml        ← reusable workflow (called by project repos)

base-images/
  python-git-ssh/
    Dockerfile              ← Python 3.12 + git + openssh (build once)

entrypoints/
  git-pull-exec.sh          ← pull-before-exec entrypoint for live code updates

compose-snippets/
  watchtower.yml            ← auto-pull on image update
  act_runner.yml            ← Gitea Actions self-hosted runner (deploy on Pi)

How a project uses the shared workflow

In your project repo, create .gitea/workflows/build.yml:

name: Build

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  build:
    uses: thethreemagi/homelab-infra/.gitea/workflows/build-and-push.yml@main
    with:
      image_name: your-project-name
    secrets:
      REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
      REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}

Add two secrets to the project repo (Gitea → repo → Settings → Secrets):

  • REGISTRY_USER — your Gitea username (thethreemagi)
  • REGISTRY_TOKEN — a PAT with write:packages scope

On push to main, the workflow builds a multi-tag image and pushes to git.thewichersfamily.com/thethreemagi/your-project-name:latest.

One-time server setup (Gitea + runner)

1. Enable Actions in Gitea

Edit your Gitea app.ini (check your Gitea compose volume mount for the path):

[actions]
ENABLED = true

Restart Gitea: docker compose restart gitea

2. Generate runner registration token

Gitea → Site Administration → Actions → Runners → Create Runner → copy token.

3. Deploy act_runner on Pi 5

Copy compose-snippets/act_runner.yml to /srv/act-runner/docker-compose.yml. Add to .env:

RUNNER_TOKEN=<token from step 2>
docker compose up -d

Verify: Gitea → Site Administration → Actions → Runners → homelab-pi5 online.

4. Generate registry PATs

Runner PAT (push images):

  • Gitea → Settings → Applications → Generate Token → scope: write:packages
  • Set as REGISTRY_TOKEN secret in each project repo

Pi pull PAT (Watchtower pulls):

  • Gitea → Settings → Applications → Generate Token → scope: read:packages
  • On Pi: docker login git.thewichersfamily.com

5. Deploy Watchtower on Pi

Use compose-snippets/watchtower.yml. Polls every 5 min, restarts containers on new image digest.

Adding a new project

  1. Ask Claude to create the repo via MCP (needs write:user scope on token)
  2. Claude adds .gitea/workflows/build.yml calling this shared workflow
  3. Add REGISTRY_USER + REGISTRY_TOKEN secrets to repo
  4. Update project docker-compose.yml: image: git.thewichersfamily.com/thethreemagi/<name>:latest
  5. Push — CI runs automatically

Runner note: ARM64 vs x86

Runner runs on Pi 5 — native ARM64 builds, no QEMU needed. If moved to x86 NAS later, uncomment the QEMU steps in build-and-push.yml.

Requires Gitea 1.21+

Reusable workflows require Gitea 1.21+. Check: Site Administration → Configuration → Gitea Version.