Mit NixOS 20.03 ist für den Apache2 Webserver ganz schön was passiert.
Die Änderungen sind tiefgreifend, aber toll. Deswegen will ich kurz die alte Konfiguration mit der Neuen vergleichen, denn ich denke das sich daraus wunderbar die Vorteile von NixOS aufzeigen lassen.
Was brauche ich?
Als Beispiel schauen wir uns den vHost
vom chaostreff-nuernberg.de an.
Die Anforderungen sind sehr simpel:
- Statisches Webseite Hosting
- HTTP -> Port 80
- HTTPS -> Port 443
- HTTP -> HTTPS Weiterleitung
- Let’s Encrypt Zertifikat
Also wirklich kein Hexenwerk.
Der alte Weg. (<=19.09)
Ich brauche also 2 vHosts. Einen, der die ACME
Challenge aus dem
entsprechenden Directory ausliefert, und einen anderen, der dann HTTPS die
eigentliche Page ausliefert.
services.httpd = {
enable = true;
logFormat = "combined";
virtualHosts = [
{
documentRoot = "/var/www/chaostreff-nuernberg.de";
listen = [{port = 80;}];
hostName = "chaostreff-nuernberg.de";
serverAliases = [ "www.chaostreff-nuernberg.de" ];
globalRedirect = "https://k4cg.org";
extraConfig = ''
Alias /.well-known/acme-challenge/ /var/www/challenges/
<Directory /var/www/challenges/>
AllowOverride None
Require all granted
Satisfy Any
</Directory>
'';
}
{
hostName = "chaostreff-nuernberg.de";
serverAliases = [ "www.chaostreff-nuernberg.de" ];
documentRoot = "/var/www/chaostreff-nuernberg.de/";
listen = [{port = 443;}];
enableSSL = true;
sslServerCert = "/usr/local/acme-tiny/k4cg.org.crt";
sslServerKey = "/usr/local/acme-tiny/k4cg.org.key";
sslServerChain = "/usr/local/acme-tiny/intermediate.crt";
}
];
};
Und die Let’s Encrypt Zertifikate werden via eines Cronjobs mittels acme-tiny regelmässig erneuert. Das findet sich allerdings nicht in der NixOS Konfiguration wieder. Will ich auch im Detail garnicht zeigen, weil es einfach ein hässliches Shell Script ist.
Der neue Weg (>=20.03)
In der neuen Variante haben wir security.acme
bekommen. Dieses NixOS
Optionset stellt einen ACME Client (Lego) bereit. Das wäre an sich noch keine Zauberei.
Was hier geschafft wurde ist ist das Kunststück, diesen Client direkt in die
Apache2 Konfiguration zu integrieren! Durch das abgreifen der Infos und
Default Werte zwischen security.acme
und services.httpd
ergibt sich eine
super schlanke und elegante Konfiguration.
services.httpd = {
enable = true;
logFormat = "combined";
virtualHosts = {
"chaostreff-nuernberg.de" = {
hostName = "chaostreff-nuernberg.de";
serverAliases = [ "www.chaostreff-nuernberg.de" ];
documentRoot = "/var/www/chaostreff-nuernberg.de/";
addSSL = true;
enableACME = true;
};
};
security.acme.certs = {
"chaostreff-nuernberg.de" = {};
};
Was wegfällt ist ein ganzer vHost, manuelles Setzen der SSL Zerts, Challenges
Directory spezifieren und listen
Ports auflisten. Ganz zu
schweigen von einen Cronjob der dann ein Shell Script ausführt um die
LetsEncrypt Zertifikate zu erneuern. All das ist jetzt “under the hood” der
Neuimplementierung des httpd
Services.
Was man vielleicht garnicht so sieht: security.acme
fragt nicht nur
“chaostreff-nuernberg.de” für die Zertifikate an, sondern fügt auch noch alle
weiteren DNS Namen aus dem
services.httpd.virtualHosts."chaostreff-nuernberg.de".serverAliases
Array
als DNS alternative Names in das angefragte Zertifikat ein, obwohl diese
Informationen dem eigentlichen Tool (Lego) so direkt nicht zur Verfügung
stehen. Geil oder?
Besonders hervorheben will ich noch die neuen SSL Optionen
services.httpd.virtualHosts.<name>.addSSL # http + https
services.httpd.virtualHosts.<name>.forceSSL # http -> https
services.httpd.virtualHosts.<name>.onlySSL # https
und auch die lego
Zertifikatserneuerungen über je einen Systemd-Timer pro
Zertifikat.
www.chaostreff-nuernberg.de war natürlich nicht der einzige vHost
in unserem Setup. Durch die
Umstellung und dem nutzen der Vorteile von der deklarativen Settings haben
wir nun ~120 Zeilen Konfiguration weniger. Die paar Bytes weniger sind
aber nicht der Punkt. Es ist leichter zu pflegen und weniger Moving Parts die
ich als Admin jonglieren, äh… orchestrieren muss.