Comprehensive runner image with Python, Node.js 20, Ruby, Go 1.22,
Docker CLI, kubectl, Helm, yq, gh, make, jq, rsync, zstd, and all
standard tools. Mirrors GitHub ubuntu-24.04 hosted runner so workflows
are swappable between Gitea and GitHub with no friction.
Add Node.js 20 LTS (required for all Forgejo JS actions), Python 3.12,
Ruby, Go 1.22, Docker CLI, kubectl, Helm, yq, gh, zstd, and common
build/system tools. Mirrors GitHub ubuntu-24.04 hosted runner capability
so jobs work without needing container: overrides for standard tasks.
Replace Alpine-based legion-runner with a minimal Ubuntu 24.04 image.
The act_runner binary is copied from the official image via multi-stage
build. Job-specific tooling (Ruby, Node, Python, etc.) belongs in
per-job container images specified via container: in workflows, not
in the base runner image.
Rename: legion-runner → ci-base
The Buffering middleware was causing 413 on large Docker layer pushes
by spooling entire request bodies to disk before forwarding. Docker's
chunked blob upload protocol (PATCH/PUT with Content-Range) requires
streaming, not buffering.
Replace with IngressRoute CRDs + Certificate resources for direct
streaming passthrough. responseForwarding.flushInterval=100ms ensures
prompt chunk delivery to the registry backend.
code.forgejo.org maintains up-to-date mirrors of common GitHub Actions
(checkout, upload-artifact, etc.) and is the recommended source for
Gitea Actions runners.
- external-secrets.yaml: GITEA_INSTANCE_URL changed from cluster-internal
URL to https://git.neuralplatform.ai so runner can register externally
- gitea.yaml: add GITEA__actions__DEFAULT_ACTIONS_URL=gitea so all
actions/* references resolve from gitea.com, not github.com
- Dockerfile: track runner image (Python 3.12 + build deps) in repo
- Add Headscale VPN entry to services table with note about direct TLS
- Add Grafana/Prometheus/Alertmanager/Alloy to platform services
- Add VPN section with Headscale DNS configuration notes
- Add tea CLI section (replaces raw Gitea API examples)
- Expand namespace table with service detail and cert-manager note
- Terraform now owns infra only (namespaces, Cloudflare, R2), not k8s config
- Argo CD manages all k8s resources via git
- Secrets: Vault -> ExternalSecret -> ESO -> k8s Secret (no Terraform secrets)
- Updated Common Operations for new GitOps flow
- Added tea CLI note, corrected repo paths
PVC manifests: add volumeName to bind new PVCs to existing PVs whose
old PVCs were accidentally deleted during Terraform->ArgoCD migration.
All PVs patched to Retain to prevent data loss on pod restart.
kube-prometheus-stack: replace invalid adminPassword.valueFrom.secretKeyRef
(Helm values don't support k8s secretKeyRef syntax) with correct
admin.existingSecret + admin.passwordKey pattern.
- Fix gitea_domain default from git.neuralplatform.dev → git.neuralplatform.ai
so Traefik serves the correct Let's Encrypt cert when accessed via VPN/LAN
- Add docs/vpn-comparison.md: full evaluation of WireGuard/Tailscale/Headscale/Netbird/Netmaker
gitea-runner: add container.options to mount /usr/local/bin/kubectl:ro
from the Legion host into every act_runner job container. Eliminates
per-run curl download in CI workflows.
ingress: change registry ingress hostname from registry.nook.family to
registry.neuralplatform.ai. Matches the domain used in Neuron CI and
neuron.yaml image reference. DNS CNAME + tunnel route already added.
- Added Cloudflare Access bypass for git.neuralplatform.ai/api/actions/*
restricted to Legion public IP (72.204.75.49)
- Runner now registers and communicates with git.neuralplatform.ai directly
- Job containers clone from https://git.neuralplatform.ai (proper name)
Job containers use bridge network by default, so they can't resolve
gitea.git.svc.cluster.local. host network inherits k3s host routing
which can reach cluster service IPs directly.
Switch from :host to :docker execution so jobs run inside containers.
- Labels use docker://ghcr.io/catthehacker/ubuntu:act-22.04 (Python 3.10,
Node 18, Docker CLI — everything CI jobs need pre-installed)
- config.yaml passes docker.sock through to job containers for build/push
- Capacity set to 2 parallel jobs
Fixes: 'Cannot find: node in PATH' — actions/checkout@v4 requires Node
- Fix act-runner workingDir: /data on both init and main containers so
.runner registration file is found at daemon startup
- Add servers/legion/README.md with full service catalog and deploy docs
- Update root README.md to be an index pointing to key docs
- Fix monitoring.tf comment: grafana.neuralplatform.ai (not nook.family)
- Fix AGENTS.md router model to TP-Link Deco BE5000
- gitea-runner.tf: Secret for Gitea runner registration token
- apps/gitea-runner.yaml: Gitea act-runner deployment (init container
registers with Gitea, main container runs daemon) — serves all Gitea
Actions CI jobs on self-hosted,linux,x64,legion labels
- variables.tf: Add gitea_runner_token variable
- ddclient.tf: Switch to official ghcr.io/ddclient/ddclient image,
remove linuxserver wrapper that was exhausting inotify instances
- ddclient.tf: dynamic DNS daemon that keeps dot.nook.family A record
pointing at the home public IP via Cloudflare API (updates every 5m)
- adguard.tf: cert-manager Certificate for dot.nook.family via DNS-01,
updated TLS config block with DoT paths and port 853
- apps/adguard.yaml: mount adguard-dot-tls secret, expose port 853,
init container enforces TLS/DoT settings on every restart
- adguard.tf: fix stale neuralplatform.dev → neuralplatform.ai rewrite
Android Private DNS: set to dot.nook.family
Router: forward TCP 853 → 192.168.68.77
Routes all warning/critical alerts to the Neural Platform Slack workspace.
Suppresses Watchdog and info-level noise. Groups by namespace+alertname,
repeats every 4h. Uses bot token auth via chat.postMessage API.