MaroonRides infrastructure: one Contabo VPS (prod-server) running NixOS and a
single-node k3s cluster (prod) reconciled by Flux.
tofu/: Contabo instance + NixOS install,maroonrides.appDNS records, Cloudflare tokens, R2 backup bucket, Tailscale policy, Flux webhooksnixos/: host configurationkubernetes/: Flux tree.apps/baseis the platform,apps/prodthe apps
State is infra.tfstate in the maroonrides-tofu-state R2 bucket. tofu/.env
(loaded by mise) holds AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and
OP_ACCOUNT. CI uses OP_SERVICE_ACCOUNT_TOKEN instead of OP_ACCOUNT.
Item tofu-credentials in the Maroon Rides Deployment 1Password vault:
| Section | Fields | Permissions |
|---|---|---|
cloudflare |
api_token |
Account: API Tokens Edit, Workers R2 Storage Edit; zone: Zone Read, DNS Edit |
github |
token |
Maroon-Rides/infra: Webhooks read/write |
contabo |
client_id, client_secret, username, password |
Contabo API |
tailscale |
client_id, client_secret |
OAuth client, all scopes |
- Create the
maroonrides-tofu-stateR2 bucket and thetofu-credentialsitem tofu apply -target=module.contabo.contabo_instance.prod_server- Fill
nixos/hosts/prod-server/addresses.nixfrom the Contabo panel tofu applyinstalls NixOS through nixos-anywhere and creates everything elsessh maroonrides@<ip> sudo tailscale up- Set
PUBLIC_IPV4inkubernetes/clusters/prod/kustomization.yaml, push - Create a 1Password Connect server for the vault, saved as item
1password-connect mise run bootstrap prod-server
api and auth run on both servers until DNS flips; tau-ceti keeps serving them.
- Scale
maroonrides-apito 0 on tau-ceti,pg_dumpthe database - Restore the dump into
maroonrides-dbon prod - Add
apiandauthtopublic_ingress_hostsintofu/config/dns.tf, apply - Remove
kubernetes/apps/tau-ceti/maroonridesfrom homelab