NixOS host configurations for GEWIS CBC, plus the OpenTofu that provisions them.
| Host | Role | Provisioned by | Updated by |
|---|---|---|---|
pcgewisa |
Service PC: Aurora narrowcasting on two screens | nixos-anywhere, by hand | comin, polling main |
pcgewisb |
Bar service PC: Aurora narrowcasting on two screens, DMX to the lights, audio and Spotify Connect | nixos-anywhere, by hand | comin, polling main |
pcgewisc |
Bar service PC: SudoSOS POS and Spotify on a touchscreen | nixos-anywhere, by hand | comin, polling main |
pcgewisd |
Service PC: SudoSOS POS on a touchscreen | nixos-anywhere, by hand | comin, polling main |
pcgewisinfo |
Info-screen kiosk; also DHCP and print server for the booth LAN | nixos-anywhere, by hand | comin, polling main |
s3-01 |
SeaweedFS S3 object store, single node | OpenTofu + nixos-anywhere | tofu apply |
talos-01..03 |
3-node Talos Kubernetes cluster | OpenTofu + Image Factory | tofu apply (talos root) |
The docs are published as a browsable site at
https://gewis.github.io/infra/, built from docs/ on every push to
main. Operational detail lives in docs/service-pc/,
docs/pcgewisinfo/,
docs/s3-01/ and docs/talos/. What runs
inside the Kubernetes cluster — Flux layering, ingress, certificates, DNS,
OpenBao — is docs/cluster/. S3 buckets and the
credentials the cluster reads for them are
docs/seaweedfs-buckets/; the LGTM stack and its
tenancy model are docs/observability/. HA Postgres
and MariaDB placement and their backup model are
docs/databases/.
flake.nix nixosConfigurations + devShell
nix/modules/ shared NixOS modules
nix/hosts/<host>/ per-host configuration
secrets/<host>.yaml sops-encrypted secrets, one file per host
terraform/modules/ shared modules (xcpng-vm, nixos-host)
terraform/10_s3-01/ OpenTofu root: XCP-ng VM + nixos-anywhere (s3-01)
terraform/10_talos-hosts/ OpenTofu root: 3-node Talos cluster
terraform/20_talos-bootstrap/ OpenTofu root: in-cluster bootstrap (Cilium, sealed-secrets, Flux Operator)
terraform/30_flux/ stage marker: Flux reconciles flux/
terraform/40_openbao-config/ OpenTofu root: OpenBao mounts and secrets
terraform/40_postgres-databases/ OpenTofu root: Postgres roles + their credentials in OpenBao
terraform/40_seaweedfs-buckets/ OpenTofu root: SeaweedFS buckets + their credentials in OpenBao
terraform/50_authentik-config/ OpenTofu root: authentik's AD source, providers and applications
terraform/50_ssh-certificates/ OpenTofu root: OpenBao SSH CA, signing role and policy
terraform/60_grafana-config/ OpenTofu root: Grafana organizations and datasources
flux/clusters/gewis-prod/ one Flux Kustomization per layer, entrypoint of the GitOps tree
flux/10_sealed-secrets/ Flux layer: sealed-secrets controller
flux/20_controllers/ Flux layer: operators (cert-manager, Traefik, longhorn, …)
flux/30_config/ Flux layer: cluster-wide objects of those operators
flux/30_openbao/ Flux layer: OpenBao
flux/40_services/ Flux layer: resolver, node exporter, Postgres
flux/50_apps/ Flux layer: authentik, LGTM stack, UI routes
docs/ per-host and cluster operational detail
nix/modules is imported by every host and pulls in:
| Module | Contents |
|---|---|
common.nix |
Flakes, weekly GC, timezone, immutable users, sshd defaults, firewall on |
shell.nix |
zsh as the default user shell, the prompt theme, the base tool set |
motd.nix |
The hostname banner shown at login |
admin.nix |
gewis.admin.* — the cbc administrator account, sudo, ssh with a password and a persisted host key |
comin.nix |
gewis.comin.* — continuous deployment from main |
netbird.nix |
gewis.netbird.* — GEWIS mesh client |
persistence.nix |
gewis.persistence.* — what survives a reboot on a tmpfs root |
tmpfs-root.nix |
gewis.tmpfsRoot.* — disko layout for a tmpfs root with /nix and /persist on one UEFI disk |
service-pc/ |
gewis.servicePc.* — GNOME session, pinned apps, NFC, RDP and the nightly power-off for service PCs |
zabbix-agent.nix |
gewis.zabbixAgent.* — Zabbix agent |
Every gewis.* module is off until a host enables it. xcpng.nix sits
alongside them but is imported only by hosts that run on XCP-ng, because it
carries Xen-specific boot and network settings.
Anything a host needs that the others do not — the kiosk's printers, the S3
box's disk layout — stays in nix/hosts/<host>/.
Normal users get zsh, with completion, autosuggestions, syntax highlighting and
a two-line prompt showing user, host, path, git state, an exit code when the
last command failed, and a nix marker inside a dev shell. Commands over one
second get their duration on the right.
root deliberately keeps bash. nixos-anywhere and nixos-rebuild --target-host pipe POSIX shell fragments over ssh and run them through root's
login shell, so root's shell stays a plain POSIX-compatible bash.
direnv allow # or: nix developThat provides opentofu, nixos-anywhere, sops, age, ssh-to-age,
talosctl, kubectl, nixfmt and jq. Format with nix fmt before
committing.
Flakes only see git-tracked files, so git add new files before building or
running tofu plan; an untracked file is invisible to the build even though it
is plainly on disk.
One sops file per host in secrets/, plus admin-only files for the state
passphrase, the Talos PKI, the sealing key and authentik. Recipients are
declared in nix/recipients.nix; .sops.yaml is generated from it with
nix run .#sops-config, and nix flake check fails if the two drift.
sops secrets/s3-01.yaml
sops secrets/pcgewisa.yaml
sops secrets/pcgewisb.yaml
sops secrets/pcgewisc.yaml
sops secrets/pcgewisd.yaml
sops secrets/pcgewisinfo.yaml
sops secrets/tofu.yaml
sops secrets/talos.yaml
sops secrets/sealed-secrets.yaml
sops secrets/authentik.yamlPrivate age keys are never committed — .gitignore covers *-age.key and
key.txt. This repository is public, so everything in secrets/ is
published as ciphertext.
The service PCs (pcgewisa, pcgewisb, pcgewisc, pcgewisd, pcgewisinfo) —
push to main; comin polls the repo and switches each host. Every push rebuilds them,
including commits that only touch s3-01. Installing a new one is
docs/service-pc/install.md.
The rest lives under terraform/, each its own root with its own state, so an
apply to one cannot touch another. s3-01 — see
docs/s3-01/:
cd terraform/10_s3-01 && tofu applytalos-* — see docs/talos/; a Talos template must be
imported into Xen Orchestra once first, then:
cd terraform/10_talos-hosts && tofu applyOpenTofu state is remote, in Scaleway Object Storage, locked with native S3
conditional writes and encrypted client-side. Every operator uses their own
Scaleway API key in a gitignored .envrc.local; access is granted by IAM on a
dedicated Project, so offboarding is revoking one key and nothing shared gets
rotated. The encryption passphrase comes from secrets/tofu.yaml via .envrc
and is not an access credential.