GitHub Actions — self-hosted runners (homelab)¶
Homelab CI uses repo-scoped self-hosted runners on two pools. GitHub-hosted
ubuntu-latest was blocked by account billing (2026-06-26); all workflows target
these pools.
Runner admin: homelab → Settings → Actions → Runners
Same pattern as tiktooker
(tiktok-ci) and dnd_session_parser
(dnd-session-parser) on WSL.
Pools¶
| Label | Host | Use when |
|---|---|---|
homelab-ci |
WSL on dev PC (CaptainKangapoo) |
Lint, docs deploy, Tailscale ACL — internet only |
homelab-lan |
infra-services (192.168.6.17) |
Komodo webhook, UniFi/Proxmox scans — needs LAN DNS/IPs |
dependabot |
WSL runner 04 (also carries homelab-ci) |
Dependabot PR CI — isolated from the main CI pool |
Workflows use explicit labels so homelab jobs never land on tiktok/dnd runners (those are registered to other repos).
runs-on: [self-hosted, Linux, X64, homelab-ci]
# or
runs-on: [self-hosted, Linux, X64, homelab-lan]
# Dependabot PRs (lint.yml) — dedicated runner 04:
runs-on: ${{ fromJSON(github.actor == 'dependabot[bot]' && '["self-hosted","Linux","X64","homelab-ci","dependabot"]' || '["self-hosted","Linux","X64","homelab-ci"]') }}
Current inventory¶
| Name | Pool | Status |
|---|---|---|
infra-services |
homelab-lan |
Online — systemd on infra-services |
windows-CaptainKangapoo-homelab-runner-01 |
homelab-ci |
Online — WSL systemd |
windows-CaptainKangapoo-homelab-runner-02 |
homelab-ci |
Online — WSL systemd |
windows-CaptainKangapoo-homelab-runner-03 |
homelab-ci |
Online — WSL systemd |
windows-CaptainKangapoo-homelab-runner-04 |
homelab-ci, dependabot |
Dependabot PR CI — WSL systemd |
Install script: scripts/install-homelab-ci-runners-wsl.sh
bash scripts/install-homelab-ci-runners-wsl.sh 3 # CI pool
bash scripts/install-homelab-ci-runners-wsl.sh --dependabot # runner 04
Check live:
gh api repos/notarealemail/homelab/actions/runners --jq '.runners[] | {name, status, labels: [.labels[].name]}'
Register homelab-lan (infra-services)¶
Already installed at /home/someone/actions-runner (2026-06-26). Add the custom
label if the runner only has defaults:
# From dev machine (gh auth)
gh api --method PUT repos/notarealemail/homelab/actions/runners/RUNNER_ID/labels \
-f "labels[]=homelab-lan"
Or re-register with labels:
ssh infra-services
cd ~/actions-runner
./config.sh remove
# New token: GitHub → homelab → Settings → Actions → Runners → New self-hosted runner
./config.sh --url https://github.com/notarealemail/homelab \
--token TOKEN \
--name infra-services \
--labels homelab-lan \
--unattended
sudo ./svc.sh install someone
sudo ./svc.sh start
Service: actions.runner.notarealemail-homelab.infra-services.service
Prereqs on host: git, Python 3.12+, uv optional; LAN DNS for
*.infra.realemail.app, reachability to UDM (192.168.1.1) and Proxmox as needed.
Register homelab-ci (WSL)¶
Mirror the tiktok/dnd WSL layout — one or more runners with the homelab-ci
label only (do not reuse tiktok-ci / dnd-session-parser registrations; those
belong to other repos).
On WSL (Ubuntu), per runner instance — or use the install script:
Manual one-off (token from GitHub → homelab → Settings → Actions → Runners):
DIR=~/actions-runner-homelab-ci-01
mkdir -p "$DIR" && cd "$DIR"
curl -fsSL -o runner.tar.gz \
https://github.com/actions/runner/releases/download/v2.335.1/actions-runner-linux-x64-2.335.1.tar.gz
tar xzf runner.tar.gz
./config.sh --url https://github.com/notarealemail/homelab --token TOKEN \
--name windows-CaptainKangapoo-homelab-runner-01 --labels homelab-ci --unattended
sudo ./svc.sh install someone && sudo ./svc.sh start
Prereqs: git, Python 3.12/3.13, Node 22, npm, Docker optional. Runners
need outbound HTTPS (PyPI, npm, Cloudflare API for docs deploy).
Parallelism: lint.yml runs nine jobs — two or three homelab-ci runners
avoid long queues. Dependabot PRs target runner 04 (homelab-ci + dependabot)
so dependency bumps do not starve human PRs.
Dependabot¶
Config: .github/dependabot.yml
— npm (root), pip (pyproject.toml), GitHub Actions, and docker-compose per
services/* stack.
Same isolation pattern as
dnd_session_parser and
tiktooker (runner-10): one WSL
runner carries both the repo CI label and dependabot. lint.yml switches
runs-on when github.actor == 'dependabot[bot]'.
Register runner 04:
Security workflows¶
Ported from dnd_session_parser — all run on
homelab-ci (Dependabot PRs on runner 04):
| Workflow | Tools | Triggers |
|---|---|---|
| Secrets scan | Gitleaks + TruffleHog OSS | PR, push, weekly Tue 03:30 |
| Dependency Security | pip-audit (uv.lock) + npm audit |
PR (path-filtered), push, weekly Mon 07:00 |
| Semgrep OSS | p/ci ERROR gate |
PR, push, weekly Mon 07:30 |
Gitleaks config: .gitleaks.toml allowlists SOPS ciphertext and repo placeholders. pip-audit baseline: .github/pip-audit-ignore.txt.
No new GitHub secrets are required — scans use GITHUB_TOKEN (Gitleaks) or run offline.
Optional: add DISCORD_WEBHOOK and a dependabot-discord.yml-style workflow if you want PR
notifications like dnd.
Branch protection (GitHub UI): Settings → Branches → main → require status checks:
Gitleaks, TruffleHog OSS, Semgrep OSS (high-confidence gate), and the relevant
Dependency Security jobs once the first runs are green.
Workflow → pool map¶
| Workflow | Pool |
|---|---|
| lint.yml | homelab-ci |
| secrets-scan.yml | homelab-ci / dependabot |
| dependency-security.yml | homelab-ci / dependabot |
| semgrep.yml | homelab-ci / dependabot |
| docs.yml | homelab-ci |
| tailscale-acl.yml | homelab-ci |
| komodo-deploy.yml | homelab-lan |
| network-scan.yml | homelab-lan |
| proxmox-scan.yml | homelab-lan |
| unifi-fix-airplay.yml | homelab-lan |
Troubleshooting¶
Job queued forever¶
No online runner with the requested label. Register a runner or fix labels:
gh api repos/notarealemail/homelab/actions/runners --jq '.runners[] | select(.status==\"online\") | .labels[].name' | sort -u
Wrong pool picked up job¶
Labels are wrong on the runner. LAN jobs must not carry homelab-ci only;
CI runners must not be the sole homelab-lan host unless you accept LAN
workloads on WSL (not recommended — no infra DNS).
Runner offline after reboot¶
# infra-services
ssh infra-services 'sudo systemctl status actions.runner.notarealemail-homelab.infra-services'
# WSL — restart your user systemd unit or ./run.sh
Related¶
- Komodo GitHub webhook relay — why
homelab-lanexists - Cloudflare Pages (docs deploy) —
homelab-ci+ CF secrets - GitHub: Managing self-hosted runners