EN

Vom Ansible-Stack zu NixOS: Mein Edge-Hosting deklarativ neu gebaut

Mein Edge-Hosting lief mit Debian, Ansible, OpenResty und HTTP/3 eigentlich völlig unauffällig. Warum ich den produktiven Server trotzdem auf NixOS 26.05 umgezogen habe — und wo der Unterschied zwischen Orchestrierung und echter Deklaration liegt.

Teilen:

Inhalt

Der Edge lief. Eigentlich hätte ich ihn einfach in Ruhe lassen können.

Auf dem   Proxmox-LXC lief mein Edge-Hosting seit Monaten stabil:   Debian als Basis, verwaltet mit   Ansible, davor   OpenResty mit nativem HTTP/3 und dahinter getrennte PHP-8.4-FPM-Pools pro Domain. Die VHosts wurden sauber aus group_vars/sites_php.yml und group_vars/sites_proxy.yml generiert.

Ein funktionierendes Setup.

Beim routinemäßigen Aufräumen bin ich dann über ein paar Dinge gestolpert.

In sites-available lagen noch drei alte Nginx-VHosts. Dazu zwei PHP-Pools und Zertifikatsreste von Diensten, die ich vor über einem Jahr abgestellt hatte. Ansible hatte über die Jahre genau das getan, was in den Playbooks stand. Aber was ich irgendwann aus den Variablen gelöscht hatte, existierte auf dem Host einfach weiter.

Da habe ich mich gefragt, ob Ansible für genau diesen Server noch das richtige Werkzeug ist. Orchestrierung löscht nicht automatisch das, was du nicht mehr erwähnst.

Der Unterschied zwischen Konvergenz und Deklaration

Ansible beschreibt gewünschte Zustände und arbeitet weitgehend idempotent. Wenn eine Variable definiert ist, sorgt das Playbook dafür, dass Datei, User und Service vorhanden sind.

Das Problem liegt auf der anderen Seite: Wenn ich eine Domain aus meiner Variablen-Datei entferne, weiß das Zielsystem nichts davon. Ansible führt die Tasks für diese Domain schlicht nicht mehr aus. Der VHost bleibt in /etc/nginx/sites-enabled/ liegen, der System-User bleibt im Betriebssystem, und der PHP-Pool läuft weiter, bis man ihn von Hand aufräumt oder explizit state: absent dafür baut.

Auf einem klassischen, persistenten Host kann sich so über die Jahre erstaunlich viel Drift ansammeln.

Klassisches Linux:  Systemkonfiguration = Basis-OS + Updates + Historie aller Änderungen
NixOS:              Systemkonfiguration = reproduzierbares Ergebnis der aktuellen Flake-Konfiguration

Deshalb habe ich den Schnitt gemacht und den Edge im August auf NixOS 26.05 migriert.

Die Architektur auf dem Edge

Am Netzwerkfluss hat sich nichts geändert. Nach außen steht die OPNsense-Firewall, die TCP 80/443 und UDP 443 (für HTTP/3 QUIC) an den internen Edge-Container weiterleitet.

WAN ──► OPNsense (NAT TCP/UDP 443) ──► NixOS Edge LXC
                                        ├── OpenResty (HTTP/3 + Lua)
                                        ├── PHP-FPM Pools (nerdbear, bearwave, ...)
                                        └── Upstream Proxies (Forgejo, Vaultwarden)

Der Unterschied liegt darin, wie der Host definiert wird. Die gesamte Betriebssystem-Konfiguration liegt in einem Git-Repository:

  • hosts/edge.nix: Host-Definition, SSH-Keys, Firewall-Regeln und globale Dienste.
  • sites/php.nix: PHP-Sites als strukturierte Attribute.
  • sites/proxy.nix: Reverse-Proxy-Ziele inklusive Puffer- und Timeout-Werte.
  • sites/shared.nix: Redirects und Aliase.

Mehr Abstraktion wollte ich an der Stelle bewusst nicht. Eine PHP-Site wie nerdbear.de oder bearwave.app ist in Nix nur ein kompakter Datensatz:

"nerdbear.de" = {
  type = "php";
  user = "nerdbear";
  phpVersion = "8.4";
  deployRootSubdir = "index";
  docrootSubdir = "index/public";
  tls = {
    enable = true;
    mode = "external";
    certName = "nerdbear.de";
  };
};

Daraus generiert NixOS den System-User nerdbear, die Systemd-Unit für den PHP-8.4-Pool mit Unix-Socket unter /run/phpfpm/nerdbear.de.sock und die OpenResty-Konfiguration.

Wenn ich diesen Block aus der Datei lösche und nixos-rebuild switch --flake .#edge ausführe, werden VHost, Systemd-Unit, Socket und die deklarativ erzeugten Systembestandteile mit der neuen Generation entfernt. Was nicht mehr konfiguriert ist, wird nicht mehr mitgeschleppt.

User-Isolation und Dateirechte

Ich halte nichts von globalen Webserver-Benutzern. Wenn auf einem Server zehn verschiedene Webseiten laufen, gehört jede einzelne in ein eigenes Gefängnis.

Domain Linux-User PHP-FPM Socket
nerdbear.de nerdbear /run/phpfpm/nerdbear.de.sock
palencsar.de nerdbear (Shared Root) /run/phpfpm/nerdbear.de.sock

Die Trennung zwischen deklarativer Systemkonfiguration und persistenten Nutzdaten ist dabei strikt:

  • Site-Inhalte (Content): Liegen unter /srv/www/<domain>/index/public/. Das Deployment läuft Git-basiert (Push-to-Deploy via Bare-Repository und Hook) als Benutzer ragnar.
  • Gruppenrechte: Verzeichnisse unter /srv/www/ gehören dem Domain-User und der Gruppe webdeploy mit SetGID (chmod 2775). Neu ausgecheckte Dateien erben automatisch die richtige Gruppenberechtigung.
  • Zertifikate: Werden nicht auf dem Edge erzeugt, sondern zentral über meinen   PowerDNS-Host per ACME bezogen und unter /etc/ssl/hosting/<cert>/ abgelegt. Der Webserver liest sie über die Gruppe tls-cert-readers.

Wo NixOS im Alltag nervt

  NixOS ist kein System für spontane Experimente direkt auf dem Server. Wenn man von   Debian kommt, stolpert man über Eigenheiten, die anfangs schlicht Umgewöhnung verlangen.

Tipp

Kein Standard-FHS: Es gibt kein klassisches /usr/bin/php oder /etc/nginx. Die Binaries und Konfigurationen liegen unveränderlich und gehasht im /nix/store/....

In der Praxis bedeutet das:

  1. Keine schnellen Hotfixes in /etc: Mal eben in /etc herumeditieren und den Fix dort vergessen funktioniert nicht mehr. Die dauerhafte Änderung gehört zurück in die Nix-Konfiguration, danach folgt der Rebuild.

  2. Socket-Berechtigungen: OpenResty läuft als webdeploy, PHP-FPM als jeweiliger Domain-User. Wenn die Socket-Berechtigungen im PHP-Modul nicht penibel auf listen.mode = 0660 und listen.group = webdeploy stehen, antwortet Nginx beim ersten Request mit einem 502 Bad Gateway.

  3. LXC auf Proxmox: In unprivilegierten Containern muss man das UID/GID-Mapping und die nötigen Systemd-Berechtigungen gegenüber dem Proxmox-Host sauber abgleichen, damit Sockets und Dateizugriffe ohne Reibung funktionieren.

Warum sich der Umstieg trotzdem gelohnt hat

Der Vorteil zeigt sich bei Updates und Wartung.

Wenn ich heute eine neue PHP-Version oder OpenResty-Konfiguration ausrolle und etwas hakt, aktiviert nixos-rebuild switch --rollback sofort die vorherige Systemgeneration. Pakete, Services und Konfigurationen springen in Sekunden auf den letzten funktionierenden Stand zurück. Die persistenten Daten unter /srv/www bleiben davon unberührt.

Sollte der Container zerstört werden, brauche ich kein Root-Dateisystem-Backup. Ich erstelle einen leeren NixOS-LXC, binde /srv/www sowie die Zertifikate ein, lasse den Flake durchlaufen — und der Edge steht in wenigen Minuten wieder exakt so da wie zuvor.

Der Wechsel war kein Hype-Projekt. Ich wollte ein System, das sich reproduzierbar kontrollieren lässt, ohne nach einem Jahr raten zu müssen, was auf dem Host eigentlich noch aktiv ist.

Quellverweise: NixOS Manual OpenResty Reference Nix Flakes Guide Ansible Grundlagen
Tags: #NixOS #Hosting #OpenResty #PHP #HTTP/3 #Infrastruktur #Proxmox #Ansible #DevOps

Ähnliche Beiträge