Kalzit ist in früher Entwicklung. Diese Seiten beschreiben, was heute existiert, und ändern sich mit den Meilensteinen.

HTTPS und Reverse Proxys

Kalzit kann HTTPS selbst ausliefern oder hinter einem Reverse Proxy laufen, der TLS übernimmt. Beides funktioniert unter Windows und Linux gleich.

HTTPS mit eigenem Zertifikat

Kalzit nutzt rustls, OpenSSL ist nicht beteiligt. Gib ihm eine Zertifikatskette und einen privaten Schlüssel als PEM-Dateien und eine HTTPS-Adresse:

[server]
http_addr = "0.0.0.0:80"
https_addr = "0.0.0.0:443"
public_url = "https://kalzit.example.com"

[tls]
cert_file = "/etc/kalzit/tls/fullchain.pem"
key_file = "/etc/kalzit/tls/privkey.pem"

Was dann passiert:

  • HTTPS bietet TLS 1.2 und 1.3 (tls.min_version = "1.3" lässt nur 1.3 zu) und HTTP/2.
  • HTTP auf http_addr leitet auf HTTPS um, außer /healthz und /readyz. Mit server.redirect_http_to_https = false liefert Kalzit auf beiden aus, mit http_addr = "" ist HTTP ganz aus.
  • Alle 60 Sekunden prüft Kalzit, ob sich die Dateien geändert haben, und lädt ein erneuertes Zertifikat ohne Neustart. Lässt sich eine neue Datei nicht lesen, bleibt das alte Zertifikat in Gebrauch, und das Log sagt, warum.
  • HTTPS-Antworten tragen Strict-Transport-Security für ein Jahr.

Automatische Zertifikate über ACME (Let’s Encrypt) sind für M5 geplant. Bis dahin erneuerst du die Dateien mit einem Werkzeug deiner Wahl; Kalzit übernimmt sie.

HSTS bleibt hängen. Hat ein Browser den Header einmal gesehen, verweigert er für die ganze Dauer HTTP für diesen Host. Solange du ausprobierst, setz security.hsts_max_age_secs auf ein paar Minuten oder security.hsts = false.

Hinter einem Reverse Proxy

Lass den Proxy TLS übernehmen und Kalzit per HTTP auf der Loopback-Schnittstelle lauschen:

[server]
http_addr = "127.0.0.1:3000"
public_url = "https://kalzit.example.com"

[security]
trusted_proxies = ["127.0.0.1/32", "::1/128"]

trusted_proxies ist wichtig. Kalzit liest X-Forwarded-For, X-Forwarded-Proto und X-Forwarded-Host nur von diesen Adressen; bei allen anderen werden die Header ignoriert, damit sich kein Client als jemand anderes ausgeben kann. Fehlt die Angabe, sieht Kalzit jede Anfrage als HTTP vom Proxy: Sitzungs-Cookies verlieren das Flag Secure, HSTS wird nicht gesendet, und die Anmeldebremse zählt alle Benutzer als eine Adresse.

Als Client-Adresse gilt die erste Adresse in X-Forwarded-For, von rechts gelesen, die kein vertrauenswürdiger Proxy ist. Liefere Kalzit an der Wurzel eines eigenen Hostnamens aus; ein Unterpfad wie /kalzit wird noch nicht unterstützt.

Sendet der Proxy schon HSTS, setz security.hsts = false, damit der Header nicht doppelt kommt.

Caddy

Caddy holt sich selbst ein Zertifikat und setzt die Forwarded-Header von sich aus:

kalzit.example.com {
	reverse_proxy 127.0.0.1:3000
}

nginx

server {
    listen 443 ssl;
    http2 on;
    server_name kalzit.example.com;

    ssl_certificate     /etc/ssl/kalzit/fullchain.pem;
    ssl_certificate_key /etc/ssl/kalzit/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
    }
}

Header, die Kalzit immer sendet

Jede Antwort trägt eine Content Security Policy ohne Inline-Skripte und -Styles, X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, eine Permissions-Policy, die Kamera, Mikrofon und Standort abschaltet, und Cross-Origin-Opener-Policy: same-origin. Datenändernde Anfragen von fremden Origins werden abgelehnt.