3.5 KiB
3.5 KiB
Hetzner single-node bootstrap
This repo’s canonical infrastructure path is:
- provision one Hetzner VM with Terraform
- let cloud-init install k3s (and optionally Tailscale)
- run
scripts/hetzner/bootstrap.shfrom the operator workstation - apply repo-managed platform + project manifests
- bootstrap Forgejo, the runner, repo secrets/variables, and the first CI-driven deploy
Source of truth
Use these docs first:
docs/hetzner-k3s-bootstrap.md— bootstrap + destroy + required envdocs/hetzner-self-hosted-ci-runbook.md— Forgejo/runner/CI flowdocs/k8s-observability.md— Grafana, Loki, Promtail, Headlampdeploy/k8s/README.md— Kubernetes layoutdeploy/k8s/overlays/hetzner-single-node/README.md— overlay details
Current architecture
Infrastructure under infra/terraform/hetzner/ provisions:
- one Hetzner VM
- one firewall
- one private network attachment
- cloud-init for unattended k3s install
Kubernetes platform services deployed from this repo:
- Forgejo
- Forgejo runner
- private registry
- cert-manager
- Traefik via k3s bundled ingress controller
- Grafana
- Loki
- Promtail
- Headlamp
Project services deployed from this repo:
- Redpanda
near-intents-ingestdummy-reactordummy-executordummy-consumer
Bootstrap model
The current bootstrap is workstation-driven after Terraform. cloud-init does not clone this repo onto the node.
scripts/hetzner/bootstrap.sh now:
- loads config and secrets from
scripts/hetzner/bootstrap-secrets.env - resolves
*_PASSvalues throughpass - runs Terraform
- configures DNS through Cloudflare or Porkbun when credentials are present
- fetches kubeconfig from the node
- renders
.state/hetzner/generated-overlay/ - applies platform + project manifests
- bootstraps Forgejo admin/user/repo/runner state
- seeds the repo into Forgejo
- lets Forgejo Actions perform the routine image build + deploy path by default
Legacy local-image bootstrap still exists, but the default/steady-state path is Forgejo Actions.
Required operator inputs
Create and source:
cp scripts/hetzner/bootstrap-secrets.env.example scripts/hetzner/bootstrap-secrets.env
source scripts/hetzner/bootstrap-secrets.env
At minimum you need:
- Hetzner credentials
- SSH public key path
- public domain settings
- registry credentials
- app secret(s)
- Forgejo admin credentials
- Grafana admin credentials
Recommended:
- Tailscale auth key for private admin/control-plane access
- DNS provider credentials
pass-backed secret refs instead of raw env values
Current live/public surfaces
- Forgejo:
https://git.doran.133011.xyz/ - Registry:
https://registry.doran.133011.xyz/ - Grafana:
https://grafana.doran.133011.xyz/ - Headlamp:
https://headlamp.doran.133011.xyz/
Notes
- The Forgejo runner no longer reads a pre-seeded
runner_registration_tokenfrom a secret. Bootstrap generates a one-time token in-cluster and persists the runner config on the Forgejo PVC. - Registry auth is created imperatively during bootstrap from
REGISTRY_USERNAMEandREGISTRY_PASSWORD; manual overlay applies must provideregistry.htpasswdthemselves. - Headlamp login uses a generated Kubernetes service-account token; bootstrap stores it in
passwhenHEADLAMP_ADMIN_TOKEN_PASSis configured. - Ingress is Traefik-based. The old
ingress-nginxpath is obsolete.
Status
This path has been rebuilt successfully and the cluster is operational, but if you want the strongest reproducibility guarantee after any new platform addition, do one more full destroy/rebuild rehearsal.