Files
Provisioning/README.md
T
josh b23ef64ee1
build-and-push / test (push) Successful in 9m57s
build-and-push / build-and-push (push) Has been cancelled
Use ephemeral SSH keys per rebuild instead of static config keys
Generate a fresh ed25519 key pair at rebuild time, inject the public key
into the Proxmox answer file, use the private key for cluster join over
SSH, then remove the key from both the remote host and the database.
This eliminates the need to manage static SSH keys in config/secrets.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-03 21:09:22 -04:00

3.7 KiB

Provisioning

Central control plane for a Proxmox homelab cluster. Handles PXE booting bare metal, unattended Proxmox installation, cluster join, and host lifecycle management.

What it does

  1. Operator registers a host (MAC address + server type)
  2. Operator triggers "rebuild with Proxmox"
  3. Host PXE boots → dnsmasq responds → iPXE chain-loads the Proxmox installer
  4. Installer fetches a per-host answer file (TOML) from Provisioning
  5. Proxmox installs unattended → post-install webhook fires
  6. Host reboots → first-boot script phones home with IP + hardware ID
  7. Provisioning SSHes into the new host → pvecm add joins the cluster
  8. Host registered in Infrastructure → marked ready

Admin dashboard shows real-time progress via SSE.

Deploy

Prerequisites

  • Docker + Docker Compose on the target host
  • Host must be on the same network as the bare-metal nodes (for PXE/DHCP)
  • SSH key pair for root access to new Proxmox nodes
  • Registry access to gitea.thewrightserver.net

Setup

mkdir -p /opt/provisioning/keys
cd /opt/provisioning

# Log in to the container registry
docker login gitea.thewrightserver.net

# Pull the compose file
curl -sO https://gitea.thewrightserver.net/josh/Provisioning/raw/branch/main/docker-compose.yml

# Pull example configs
curl -s https://gitea.thewrightserver.net/josh/Provisioning/raw/branch/main/deploy/provisioning.example.yaml -o provisioning.yaml
curl -s https://gitea.thewrightserver.net/josh/Provisioning/raw/branch/main/deploy/server-types.example.yaml -o server-types.yaml

# Copy your SSH key pair
cp /path/to/id_ed25519 ./keys/

Configure

Edit provisioning.yaml:

  • server.public_url — LAN-reachable URL (e.g. http://192.168.1.100:8080)
  • pxe.interface — NIC name on the host (e.g. eth0, enp2s0)
  • pxe.subnet — LAN CIDR for proxy-DHCP
  • proxmox.existing_node — IP of any current cluster member
  • proxmox.join_fingerprint — from pvecm status on an existing node
  • credentials.root_password_hashmkpasswd -m sha-512
  • infrastructure.base_url — URL of the Infrastructure service
  • infrastructure.server_type_map — maps local type keys to Infrastructure IDs

Edit server-types.yaml with your actual hardware types.

Run

docker compose up -d

Dashboard at http://<host>:8080.

Update

docker compose pull
docker compose up -d

Development

# Run tests
go test ./...

# Run locally (PXE disabled)
cp deploy/provisioning.example.yaml provisioning.yaml
cp deploy/server-types.example.yaml server-types.yaml
# Edit provisioning.yaml: set pxe.enabled=false, infrastructure.base_url=""
go run ./cmd/provisioning -config provisioning.yaml

# Build binary
make build

# Build Docker image locally
make docker

Architecture

cmd/provisioning/       Entry point, wiring, shutdown
internal/
  config/               YAML config + hot-reloaded server types
  db/                   SQLite (WAL, embedded migrations)
  model/                Domain types
  store/                Hand-written SQL (hosts, operations, locks, images)
  statemachine/         Table-driven host state machine
  events/               SSE fan-out hub
  pxe/                  dnsmasq supervisor, iPXE scripts, answer files
  orchestrator/         Lifecycle driver (state transitions, cluster join)
  infra/                Infrastructure API client
  api/                  HTTP handlers (JSON API + dashboard)
  httpserver/           chi router assembly
  web/                  Embedded static assets (CSS, JS)

CI/CD

Gitea Actions workflow (.gitea/workflows/build.yml):

  • Runs go test and go vet on every push to main
  • Builds Docker image and pushes to gitea.thewrightserver.net/josh/provisioning:latest