hoe deze omgeving werkt

Desired state van server tot repository — NixOS, OpenTofu, bewaking en versleutelde geheimen bij 3n.

✓ deze pagina is zelf via deze pipeline uitgerold

voor wie dit nieuw is

Deze site draait op een server: een computer in een datacenter die dag en nacht aanstaat (hier een gehuurde VPS, een virtuele server, van een paar euro per maand). Servers worden traditioneel met de hand ingericht: iemand logt in, typt commando's, klikt instellingen aan. Dat werkt — tot niemand meer precies weet wat er ooit is aangeklikt, waarom, en of het op de volgende server ook zo moet.

Hier is dat omgedraaid. Alles wat deze omgeving is, staat beschreven in tekstbestanden, en die bestanden zijn de baas. Vergelijk het met een thermostaat: je loopt niet naar de verwarming om aan de vlam te draaien, je stelt de gewenste temperatuur in en het systeem regelt het verschil zelf weg. Zo werkt het hier ook — de bestanden beschrijven de gewenste toestand (desired state), en de machines maken de werkelijkheid daaraan gelijk. Wie iets wil veranderen, verandert de beschrijving; nooit de machine zelf.

Die beschrijvingen leven in git: een systeem dat van elke wijziging bijhoudt wie hem deed, wanneer en waarom, en waarin je elke oude versie kunt terughalen. De verzameling bestanden plus die hele geschiedenis heet een repository (kortweg repo); de onze staan bij GitHub. Onbekende termen? Onderaan staat een begrippenlijst.

het principe

Alles wat hier draait volgt één regel: de gewenste toestand staat in git, en de werkelijkheid wordt daaraan gelijkgemaakt — nooit andersom. Niemand logt op een server in om iets aan te passen, niemand klikt instellingen aan in een webinterface. Een wijziging is een commit; gereedschap werkt het verschil tussen is en moet weg. Dat levert drie dingen op die met handwerk niet te krijgen zijn: elke verandering is te beoordelen vóór hij gebeurt, elke verandering is omkeerbaar, en afwijkingen (drift) worden zichtbaar in plaats van dat ze zich stilletjes opstapelen.

de animatie

Zo stroomt een verandering door de opzet. De repo in het midden is de bron van waarheid; links zit de mens, rechts de twee uitvoerders die elk hun eigen laag gelijktrekken.

mens / product owner
Intentie — "verplichte reviews naar 2" of "nieuwe dienst op de machine"
pull request — het reviewmoment
Het voorstel toont exact wat er zou veranderen: tofu plan of een Nix-diff. Je beoordeelt het verschil, niet de code.
git — bron van waarheid
main ís de gewenste toestand. Wat hier niet staat, hoort niet te bestaan.
laag 1 · machine · NixOS
dev.3n.nl haalt main elke tien minuten zélf op en herbouwt zich atomair. Niemand duwt; er zijn geen centrale sleutels.
laag 2 · repo-omgeving · OpenTofu
Na de merge brengt tofu apply GitHub in lijn: repositories, branch protection, rechten.
controle — drie ringen
De statuspagina toont de draaiende commit, de machine meldt elke vijf minuten zijn eigen gezondheid, en een externe partij kijkt van buiten mee.

laag 1 — de machine, met NixOS

NixOS is een Linux-distributie waarbij het complete systeem — pakketten, diensten, firewall, gebruikers — uit één declaratieve configuratie komt. Deze machine is opgebouwd met nixos-anywhere (installatie over SSH op een kale VPS) en disko (schijfindeling, óók declaratief). Vier eigenschappen dragen het ontwerp:

atomair & omkeerbaar

Elke rebuild is een nieuwe generatie. Bevalt hij niet, dan is rollback — of een keuze in het bootmenu — de complete terugweg. Er bestaat geen half-geüpdatete toestand.

pull, niet push

De machine haalt main elke tien minuten zelf op met een sleutel die alleen mag lezen. Er is dus geen laptop, CI-runner of AI-sessie die sleutels naar servers bewaart — er valt niets te stelen dat overal bij kan.

geen drift mogelijk

Op de server staat geen configuratiebestand om te bewerken. Wil je weten wat er draait: kijk in git. De statuspagina op / wordt uit diezelfde configuratie gegenereerd en toont de draaiende commit.

zelfherstellend

Zet iemand met de hand een dienst uit, dan zet de eerstvolgende tien-minuten-ronde hem gewoon weer aan: handmatige ingrepen zijn tijdelijke afwijkingen van de gewenste staat. Uit is pas uit als het in git staat.

laag 2 — de repo-omgeving, met OpenTofu

Dezelfde gedachte, één laag hoger: ook de omgeving waarin de code leeft is desired state. Met OpenTofu en de GitHub-provider staat in configuratietaal (HCL) beschreven welke repositories er bestaan en welke regels erop gelden: beveiligde branches, verplichte reviews, zichtbaarheid, rechten. Een wijziging gaat via een pull request; de automatisering draait tofu plan en zet het resultaat als commentaar op de PR — X to add, Y to change, Z to destroy. Dat plan is het reviewmoment: wie goedkeurt weet exact wat er gaat gebeuren, en na de merge is apply een bewuste, aparte knop.

OpenTofu is de open-source-voortzetting van Terraform onder de Linux Foundation (vrije MPL 2.0-licentie; zie het manifest). Hier is bewust voor OpenTofu gekozen, mede om features als native state-encryptie: de administratie van wat er beheerd wordt (de state) is versleuteld en kan daardoor veilig in de repo zelf bewaard worden, zonder extra cloud-afhankelijkheid.

de bewaking — drie ringen

Een omgeving die zichzelf bestuurt, moet zichzelf ook kunnen betrappen. Daarom liggen er drie ringen om de machine heen, van binnen naar buiten:

ring 1 · zelfdocumentatie

De machine schrijft elke paar minuten zijn eigen toestand op, en de statuspagina — gegenereerd uit de configuratie zelf — toont welke commit er draait en wanneer de volgende update-check komt.

ring 2 · dead-man's switch

Elke vijf minuten toetst de machine zichzelf en meldt "ik leef en ik ben gezond" aan healthchecks.io. Blijft die melding uit — machine plat, netwerk weg, of de strenge toets faalt — dan volgt vanzelf een alarm. Niets hoeft van buiten naar binnen.

ring 3 · blik van buiten

Een onafhankelijke partij (publieke statuspagina) controleert van buitenaf of de site bereikbaar is — bewust een ándere dienst dan ring 2, zodat de ringen niet samen kunnen uitvallen.

de strenge toets

"Gezond" is hier meer dan "de diensten draaien": de machine haalt zijn eigen homepage op en controleert of die de configuratie toont die wérkelijk actief is. Een webserver die stilletjes met oude instellingen doordraait, is per definitie een alarm.

In de praktijk grijpen de ringen en het zelfherstel in elkaar: valt een dienst uit, dan is er binnen vijf minuten een alarm mét de reden, herstelt de machine zichzelf binnen tien minuten, en wordt de volgende melding vanzelf weer groen — zonder dat iemand iets deed.

updates — dagelijks, autonoom, met een poort

Beveiligingsupdates wachten hier niet op een mens. Elke ochtend bouwt een geautomatiseerde taak de nieuwste versie van alle systeempakketten, en daar zit één poort in: alleen als de complete machineconfiguratie foutloos bouwt, wordt de update doorgezet. De machine haalt hem daarna binnen tien minuten op. Gaat er tóch iets mis, dan is de terugweg een ladder met drie sporten: de wijziging in git terugdraaien (de machine volgt vanzelf), op de machine één generatie terugstappen, of in het uiterste geval de dagelijkse back-up. Dit is een bewuste afweging — veiligheid boven beschikbaarheid — en hij is alleen verantwoord omdat de bewakingsringen er zijn: sneller updaten mag alleen als je ook sneller ziet wanneer het misgaat.

geheimen — versleuteld in git

Eén ding hoort níet leesbaar in git: geheimen, zoals sleutels en toegangs-URL's. Die reizen hier tóch mee in de repo, maar versleuteld, met sops-nix: alleen de beheerder en de machine zelf kunnen ze openen — de machine met een sleutel die wordt afgeleid van zijn eigen SSH-identiteit, dus zonder extra sleutelbeheer. Op GitHub is het bestand onleesbare cijferbrij; op de machine verschijnt het geheim bij activatie op een plek die alleen het systeem kan lezen. Het gevolg: zelfs een volledige herbouw van de server brengt zijn eigen geheimen weer mee, en wat er in git staat blijft voor iedereen veilig om te bekijken.

waarom dit samen sterk is

De lagen sluiten op elkaar aan zonder elkaar te overlappen: OpenTofu beheert wat buiten de machines ligt (de GitHub-omgeving), NixOS beheert de machines zelf, de ringen bewaken het geheel — en git is voor alles dezelfde bron van waarheid. Voor de rolverdeling betekent het dat een mens stuurt op intentie en review, terwijl agents (AI of automatisering) het vertaal- en uitvoerwerk doen. Niets hoeft op vertrouwen: elk voorstel is een diff, elk plan is compleet, elke uitvoering is terug te draaien, elke afwijking wordt gemeld. Deze pagina is er zelf het bewijs van — hij is als bestand in 3n-infra gecommit, door de machine opgehaald en zonder dat iemand op de server heeft ingelogd hier verschenen.

begrippen en afkortingen

VPS
Virtual Private Server — een gehuurde virtuele computer in een datacenter; jouw stukje van een grote machine.
SSH
Secure Shell — de versleutelde verbinding waarmee beheerders (en machines onderling) veilig op afstand inloggen.
git
Versiebeheer: houdt van elke wijziging bij wie, wat, wanneer en waarom, en kan elke oude versie terughalen.
repo
Repository — een verzameling bestanden mét hun complete git-geschiedenis; hier gehost bij GitHub.
commit
Eén vastgelegde wijziging in git, met beschrijving en afzender.
PR
Pull request — een voorstel tot wijziging dat eerst beoordeeld wordt; pas na goedkeuring (de merge) telt het.
CI
Continuous Integration — automatisering die bij elk voorstel controles en bouwstappen draait (hier: GitHub Actions).
IaC
Infrastructure as Code — infrastructuur beschreven in tekstbestanden in plaats van met de hand ingericht.
HCL
HashiCorp Configuration Language — de leesbare configuratietaal waarin OpenTofu-beschrijvingen staan.
state
De administratie van OpenTofu: wat beheert het en hoe zag dat er bij de laatste keer uit. Hier versleuteld in de repo.
flake
Het Nix-formaat dat een complete systeembeschrijving mét vastgepinde versies van alle bouwstenen vastlegt.
generatie
Eén complete, opgeslagen versie van het NixOS-systeem; terugrollen is overstappen naar een vorige generatie.
drift
Het sluipende verschil tussen wat er hoort te draaien en wat er werkelijk draait. Hier: wordt gezien én hersteld.
dead-man's switch
Bewaking op basis van uitblijvende levenstekens: geen bericht is zelf het alarm.
sops / age
Gereedschap (sops) en versleuteling (age) waarmee geheimen veilig versleuteld in git kunnen staan.
branch protection
GitHub-regels die een branch beschermen: bijvoorbeeld verplichte reviews voordat iets naar main mag.

verder lezen