NixOS host configurations for GEWIS CBC, plus the OpenTofu that provisions them.
| Host | Role | Provisioned by | Updated by |
|---|---|---|---|
pcgewisc |
Bar service PC: SudoSOS POS and Spotify on a touchscreen | Not yet installable | — |
pcgewisinfo |
Info-screen kiosk; also DHCP and print server for the booth LAN | Installed by hand | comin, polling main |
s3-01 |
Garage 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/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/garage-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/s3-01/ OpenTofu root: XCP-ng VM + nixos-anywhere (s3-01)
terraform/talos-hosts/ OpenTofu root: 3-node Talos cluster
terraform/talos-bootstrap/ OpenTofu root: in-cluster bootstrap (Cilium, sealed-secrets, Flux)
terraform/openbao-config/ OpenTofu root: OpenBao mounts and secrets
terraform/garage-buckets/ OpenTofu root: Garage buckets + their credentials in OpenBao
terraform/grafana-config/ OpenTofu root: Grafana organizations and datasources
terraform/postgres-databases/ OpenTofu root: Postgres roles + their credentials in OpenBao
terraform/authentik-config/ OpenTofu root: authentik's AD source, providers and applications
flux/ Flux GitOps tree, reconciled into the cluster
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 |
netbird.nix |
gewis.netbird.* — GEWIS mesh client, off unless a host enables it |
service-pc.nix |
gewis.servicePc.* — GNOME session, pinned apps and RDP for service PCs, off unless 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 other one does 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 secrets/tofu.yaml for the state
encryption passphrase. Recipients are declared in .sops.yaml, where the
admins group is the one to extend when someone else needs access.
sops secrets/s3-01.yaml
sops secrets/pcgewisinfo.yaml
sops secrets/tofu.yaml
sops secrets/talos.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.
pcgewisinfo — push to main; comin polls the repo and switches the host.
Every push rebuilds it, including commits that only touch s3-01.
Both live under terraform/, each its own root with its own state, so an apply
to one cannot touch the other. s3-01 — see docs/s3-01.md:
cd terraform/s3-01 && tofu applytalos-* — see docs/talos.md; a Talos template must be
imported into Xen Orchestra once first, then:
cd terraform/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.