{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreid75cw6efmp6sc5uswdf5o42ie3qjid37vlu6rkpi33h5thsa7tiy",
    "uri": "at://did:plc:nkxz2ojdvmieg2nhphvputvp/app.bsky.feed.post/3mmgr76sdvk62"
  },
  "coverImage": {
    "$type": "blob",
    "ref": {
      "$link": "bafkreidpidtiuidzmhleq2fh2hhv36tdfo5mpuwie4b5v7awqpqsflnhnu"
    },
    "mimeType": "image/png",
    "size": 987840
  },
  "description": "Nachdem ich zuerst OpenSSH und dann Postfix und Dovecot mit Post-Quantum-Kryptografie ausgestattet habe, kamen einige Rückfragen: Wie sieht das eigentlich für Nginx aus? Kann man das auf dem Webserver genauso einfach aktivieren? Kurze Antwort: Ja. Noch kürzer sogar als bei E-Mail.\n\nSpannend finde ich dabei, dass ausgerechnet der Webserver die meisten Nachfragen erzeugt hat. SSH und E-Mail laufen hier längst mit X25519MLKEM768, aber die Leser wollten vor allem wissen, wie das für HTTPS […]",
  "path": "/2026/03/07/post-quantum-tls-fuer-nginx-x25519mlkem768-auf-freebsd-15/",
  "publishedAt": "2026-05-22T10:49:51.000Z",
  "site": "https://www.kernel-error.de",
  "tags": [
    "FreeBSD",
    "nginx",
    "PostQuantum",
    "Security",
    "TLS",
    "Verschlüsselung",
    "OpenSSH",
    "Postfix und Dovecot",
    "ML-KEM-768",
    "FIPS 203",
    "Store now, decrypt later",
    "HTTP/3 (QUIC) aktiviert",
    "HTTP/3 Beitrag",
    "Cloudflare",
    "Martin Peuker",
    "Items",
    "SSH",
    "E-Mail",
    "HTTPS RR und SVCB Records",
    "fragen"
  ],
  "textContent": "Nachdem ich zuerst OpenSSH und dann Postfix und Dovecot mit Post-Quantum-Kryptografie ausgestattet habe, kamen einige Rückfragen: Wie sieht das eigentlich für Nginx aus? Kann man das auf dem Webserver genauso einfach aktivieren? Kurze Antwort: Ja. Noch kürzer sogar als bei E-Mail.\n\nSpannend finde ich dabei, dass ausgerechnet der Webserver die meisten Nachfragen erzeugt hat. SSH und E-Mail laufen hier längst mit **X25519MLKEM768** , aber die Leser wollten vor allem wissen, wie das für HTTPS geht. Vermutlich weil jeder eine Webseite hat, aber nicht jeder seinen eigenen Mailserver betreibt?! Es kommt ja immer darauf an, was man macht und welche Daten man übermittelt. Aber SSH oder E-Mail würde mich selbst nervöser machen als normales surfen. Wobei…. Ich melde mich ja auch an, hm. OK, immer MFA. Na, eine normale E-Mail ist ja schon immer eine Postkarte, wenn man keine zusätzliche Verschlüsselung nutzt (was kaum jemand macht).\n\n### Worum geht es?\n\nWer die Vorgeschichte noch nicht kennt: **X25519MLKEM768** ist ein hybrider Schlüsselaustausch, der klassisches X25519 (Curve25519 ECDH) mit dem Post-Quantum-Algorithmus ML-KEM-768 kombiniert. Standardisiert vom NIST als FIPS 203. Der Vorteil des hybriden Ansatzes: Selbst wenn sich ML-KEM irgendwann als unsicher herausstellt, bleibt X25519 als Absicherung. Und andersherum genauso.\n\nDas „Store now, decrypt later“ Szenario kennt ihr vielleicht schon aus den anderen Beiträgen. Jemand schneidet heute euren TLS-verschlüsselten Datenverkehr mit und entschlüsselt ihn in ein paar Jahren mit einem Quantencomputer. Bei HTTPS betrifft das alles, was über die Leitung geht: Formulardaten, Login-Credentials, API-Aufrufe, Session-Cookies. Ob das in der Praxis relevant ist? Kommt auf euer Bedrohungsmodell an. Aber der Aufwand für die Absicherung ist so gering, dass es keinen Grund gibt, es nicht zu tun.\n\n### Es hängt an OpenSSL, nicht an Nginx\n\nDas ist eigentlich die zentrale Erkenntnis aus allen drei Beiträgen: Ob PQC funktioniert oder nicht, entscheidet fast ausschließlich die OpenSSL-Version. Nginx, Postfix, Dovecot, OpenSSH, sie alle delegieren den Schlüsselaustausch an OpenSSL (oder LibreSSL, BoringSSL, je nach System). Die Anwendung selbst muss lediglich die gewünschte Gruppe konfigurieren können. Und das können alle genannten Programme seit Jahren.\n\nKonkret braucht ihr **OpenSSL 3.5** oder neuer. Erst ab dieser Version ist ML-KEM nativ im Default-Provider enthalten, ohne externen OQS-Provider, ohne liboqs, ohne selbst kompilieren. FreeBSD 15 liefert das von Haus aus. Bei den meisten Linux-Distributionen sieht es Stand heute leider noch anders aus. Ubuntu 24.04 hat OpenSSL 3.0, Debian 12 hat 3.0, RHEL 9 hat 3.0. Für ein aktuelles OpenSSL müsst ihr dort entweder selbst bauen oder auf neuere Releases warten.\n\n### Voraussetzungen prüfen\n\nAuf meinem FreeBSD 15:\n\n\n    $ openssl version\n    OpenSSL 3.5.4 30 Sep 2025 (Library: OpenSSL 3.5.4 30 Sep 2025)\n\nNginx muss natürlich gegen dieses OpenSSL gelinkt sein. Das prüft ihr so:\n\n\n    $ nginx -V 2>&1 | grep -oE 'OpenSSL [0-9]+\\.[0-9]+\\.[0-9]+'\n    OpenSSL 3.5.4\n\nUnd dann die entscheidende Frage: Kennt OpenSSL die Gruppe X25519MLKEM768?\n\n\n    $ openssl list -tls-groups | grep -i mlkem\n      X25519MLKEM768\n      SecP256r1MLKEM768\n      SecP384r1MLKEM1024\n\nWenn X25519MLKEM768 in der Liste auftaucht, kann es losgehen.\n\n### Nginx konfigurieren\n\nIn Nginx heißt die relevante Direktive **ssl_ecdh_curve**. Der Name ist etwas irreführend, denn sie steuert nicht nur ECDH-Kurven, sondern alle Key-Exchange-Gruppen die OpenSSL kennt. Also auch hybride PQC-Gruppen.\n\nMeine Konfiguration in der TLS-Defaults-Datei, die per `include` in alle vHosts eingebunden wird:\n\n\n    ssl_ecdh_curve  X25519MLKEM768:X25519:secp384r1:prime256v1;\n\nDas war’s. Eine Zeile. **X25519MLKEM768** steht als bevorzugte Gruppe ganz vorne. Dahinter folgen die klassischen Kurven als Fallback für Clients, die noch kein ML-KEM sprechen. Die Reihenfolge ist die Präferenz.\n\nWer die Direktive lieber pro vHost setzen möchte, statt global, kann das natürlich auch tun. Ich bevorzuge eine zentrale TLS-Datei, weil ich sonst bei jedem TLS-Update zwanzig Configs anfassen müsste.\n\nZusätzlich habe ich die TLS 1.3 Cipher Suites explizit gesetzt:\n\n\n    ssl_conf_command  Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256;\n    ssl_conf_command  Options PrioritizeChaCha;\n\nChaCha20 als erste Wahl, weil es auf Clients ohne AES-NI (ältere Smartphones, ARM-Geräte) deutlich schneller ist. Auf Servern mit AES-NI ist der Unterschied minimal. `PrioritizeChaCha` sorgt dafür, dass der Server ChaCha20 bevorzugt, wenn der Client es an erster Stelle anbietet.\n\nDie komplette TLS-Konfiguration sieht bei mir so aus:\n\n\n    # Protokolle\n    ssl_protocols              TLSv1.2 TLSv1.3;\n    ssl_prefer_server_ciphers  on;\n\n    # Key-Exchange-Gruppen (Reihenfolge = Präferenz)\n    ssl_ecdh_curve             X25519MLKEM768:X25519:secp384r1:prime256v1;\n\n    # TLS 1.3 Cipher Suites\n    ssl_conf_command           Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256;\n    ssl_conf_command           Options PrioritizeChaCha;\n\n    # TLS 1.2 Cipher Suites (nur ECDSA, kein RSA)\n    ssl_ciphers                ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256;\n\n    # Session Handling\n    ssl_session_cache          shared:SSL:50m;\n    ssl_session_timeout        1d;\n    ssl_session_tickets        off;\n\n    # OCSP Stapling\n    ssl_stapling               on;\n    ssl_stapling_verify        on;\n\n    # HSTS\n    add_header Strict-Transport-Security \"max-age=63072000; includeSubDomains; preload\" always;\n\nDanach die Konfiguration testen und Nginx neu laden:\n\n\n    # nginx -t\n    nginx: the configuration file /usr/local/etc/nginx/nginx.conf syntax is ok\n    nginx: configuration file /usr/local/etc/nginx/nginx.conf test is successful\n    # service nginx reload\n\n### Überprüfen\n\nFunktioniert es? Mit `openssl s_client` lässt sich das schnell prüfen:\n\n\n    $ openssl s_client -connect www.kernel-error.de:443 \\\n        -groups X25519MLKEM768 -brief </dev/null 2>&1 | grep -E 'Protocol|group|Cipher'\n    Protocol version: TLSv1.3\n    Ciphersuite: TLS_CHACHA20_POLY1305_SHA256\n    Negotiated TLS1.3 group: X25519MLKEM768\n\n**TLSv1.3 mit X25519MLKEM768**. Läuft. Der hybride Post-Quantum-Schlüsselaustausch ist aktiv.\n\nUnd was passiert, wenn ein Client kein ML-KEM kann?\n\n\n    $ openssl s_client -connect www.kernel-error.de:443 \\\n        -groups X25519 -brief </dev/null 2>&1 | grep -E 'Protocol|group|Cipher'\n    Protocol version: TLSv1.3\n    Ciphersuite: TLS_CHACHA20_POLY1305_SHA256\n\nSauberer Fallback auf X25519. Kein Fehler, keine Unterbrechung. Der Client bekommt einfach die stärkste Gruppe, die beide Seiten gemeinsam haben.\n\n### Browser-Support\n\nDas Schöne bei HTTPS im Vergleich zu E-Mail oder SSH: Die Browser haben Post-Quantum-Kryptografie teilweise schon vor den Servern implementiert. Chrome verwendet seit Version 124 (April 2024) X25519MLKEM768 als bevorzugte Gruppe. Firefox seit Version 124 ebenfalls. Safari seit macOS 15 Sequoia und iOS 18. Edge zieht mit Chrome mit.\n\nWenn ihr also Nginx mit X25519MLKEM768 konfiguriert, profitieren die meisten eurer Besucher sofort davon. Ohne dass sie irgendetwas tun müssen. Das ist bei SSH und E-Mail anders, da sind die Clients noch nicht so weit. Womit sich auch erklärt, warum das Thema bei Webservern mehr Aufmerksamkeit bekommt.\n\n### HTTP/3 und QUIC\n\nWer wie ich HTTP/3 (QUIC) aktiviert hat, bekommt PQC dort automatisch mit. QUIC verwendet TLS 1.3 als Transportverschlüsselung und nutzt dieselbe `ssl_ecdh_curve` Konfiguration. Kein zusätzlicher Konfigurationsaufwand.\n\n\n    listen [::]:443 quic reuseport;\n    listen 443 quic reuseport;\n\nWer QUIC noch nicht nutzt: Der Overhead ist minimal, der Vorteil bei mobilen Verbindungen deutlich spürbar. Mehr dazu in meinem HTTP/3 Beitrag.\n\nDavon abgesehen, wie ist das eigentlich mit Microsoft? Cloudflare macht ja schon knapp zu 66% PQC im HTTP Traffic. Es ist 2026, fragen wir doch mal eine AI: _claude „Sag mal, wie ist das eigentlich bei Microsoft Produkten, wie Exchange oder IIS im Bezug auf PQC? Wird das schon unterstützt oder kommt das bald?“_\n\n\n    ● Gute Frage — Microsoft ist da tatsächlich in einer interessanten Position:\n\n      Windows / Schannel (TLS-Stack)\n\n      - Windows 11 24H2 / Windows Server 2025 haben experimentelle Unterstützung für ML-KEM (X25519MLKEM768) in TLS 1.3 bekommen — allerdings zunächst nur als Preview/Feature-Flag, nicht standardmäßig aktiv.\n      - Der zugrunde liegende TLS-Stack (Schannel) muss das können, damit IIS und Exchange davon profitieren.\n\n      IIS\n\n      - IIS nutzt Schannel direkt. Sobald Schannel auf dem jeweiligen Windows Server PQC-Key-Exchange unterstützt und es aktiviert ist, kann IIS das theoretisch sofort.\n      - Stand meines Wissens (Mai 2025): Noch kein produktiver PQC-Support in IIS. Die Preview in Windows Server 2025 ist eher für Tests gedacht.\n\n      Exchange\n\n      - Exchange Online (Microsoft 365): Microsoft hat angekündigt, PQC schrittweise in ihre Cloud-Dienste zu integrieren. Für TLS-Verbindungen zwischen Microsoft-Datacentern wurde bereits mit PQC experimentiert.\n      - Exchange On-Premises: Hängt komplett am darunterliegenden Windows Server / Schannel. Solange Schannel kein produktives PQC kann, kann Exchange es auch nicht.\n\n      Microsofts Roadmap\n\n      - Microsoft hat ein \"Quantum-Safe Program\" und arbeitet aktiv an PQC-Integration in Windows, Azure und M365.\n      - Die Priorität liegt auf TLS 1.3 mit ML-KEM (hybrid, also X25519MLKEM768.\n      - Einen festen Zeitplan für \"PQC by default\" in Exchange/IIS gibt es meines Wissens noch nicht.\n\n      Fazit\n\n      Microsoft ist hintendran verglichen mit dem Open-Source-Stack. OpenSSL 3.5+ / LibreSSL / BoringSSL haben PQC-Support bereits produktionsreif. Bei Microsoft wartet man darauf, dass Schannel das nativ und stabil liefert — und bis das\n      in Exchange On-Prem ankommt, dauert es erfahrungsgemäß nochmal länger.\n\n      Für Exchange Online dürfte Microsoft das irgendwann einfach serverseitig einschalten, ohne dass Admins etwas tun müssen. Für On-Prem heißt es: warten auf den nächsten Windows Server Release, der PQC in Schannel GA (General Availability) hat.\n\n      Caveat: Mein Wissensstand ist Mai 2025 — es kann sein, dass Microsoft seitdem konkretere Termine genannt hat. Wäre ggf. einen Blick in den Microsoft Security Blog wert.\n\nKlingt gut. Ich muss ja zugeben, dass ich, seit ich nicht mehr mit Martin Peuker bei Items arbeite, irgendwie komplett von der Microsoft-Welt abgekoppelt bin. Oh, ist das jetzt korrekt von der AI? Keine Ahnung, „klingt“ richtig.\n\n### Was das nicht leistet\n\nDen Absatz kennt ihr inzwischen aus den anderen Beiträgen, aber er gehört dazu: Wir sichern hier den **Schlüsselaustausch** ab, nicht die **Authentifizierung**. Die TLS-Zertifikate nutzen weiterhin klassische Algorithmen (in meinem Fall ECDSA P-384). Für Post-Quantum-Signaturen bräuchte man ML-DSA (ehemals CRYSTALS-Dilithium) in den Zertifikaten, aber keine öffentliche CA stellt solche Zertifikate aus. Das wird kommen, aber noch nicht heute.\n\nIn der Praxis heißt das: Ein Angreifer mit Quantencomputer könnte die Serverauthentifizierung angreifen, müsste das aber in Echtzeit tun. „Store now, decrypt later“ greift dort nicht. Der Schlüsselaustausch und damit die Vertraulichkeit eurer Daten ist durch X25519MLKEM768 geschützt. Auch in Zukunft.\n\n### Fazit\n\nEine Zeile in der Nginx-Konfiguration, ein Reload, fertig. Euer Webserver verhandelt danach mit jedem modernen Browser einen quantensicheren Schlüsselaustausch. Vollständig abwärtskompatibel für ältere Clients. Kein Risiko, kein Aufwand, kein Nachteil.\n\nDie eigentliche Hürde ist nicht Nginx, sondern die OpenSSL-Version auf eurem System. Wer FreeBSD 15 oder ein System mit OpenSSL 3.5+ hat, kann sofort loslegen. Alle anderen müssen auf ihre Distribution warten oder selbst bauen.\n\nDamit habe ich jetzt SSH, E-Mail und Webserver mit Post-Quantum-Kryptografie abgedeckt. Fehlt eigentlich nur noch DNS. Aber DoH und DoT laufen ja auch über TLS … *grübel*\n\n **Update:** Inzwischen habe ich HTTPS RR und SVCB Records für alle Dienste deployt. Damit wissen Clients schon beim DNS-Lookup, dass HTTP/3 und QUIC verfügbar sind.\n\n**Update 2:** Wer wissen will, ob die eigenen Besucher tatsächlich PQC nutzen: Nginx kann die ausgehandelte Key-Exchange-Gruppe loggen. Die Variable `$ssl_curve` zeigt pro Verbindung, ob `X25519MLKEM768`, klassisches `X25519` oder etwas anderes verhandelt wurde. Einfach ins bestehende Log-Format einfügen, irgendwo nach `$ssl_cipher`:\n\n\n    log_format combined_pqc\n      '$remote_addr - $remote_user [$time_local] '\n      '\"$request\" $status $body_bytes_sent '\n      '\"$http_referer\" \"$http_user_agent\" '\n      '$ssl_protocol $ssl_cipher $ssl_curve';\n\nIm Log sieht das dann so aus. Ein Chrome mit PQC-Support:\n\n\n    203.0.113.42 - - [07/Apr/2026:13:22:36 +0200] \"GET / HTTP/2.0\" 200 56687 \"-\" \"Mozilla/5.0 [...] Chrome/146.0.0.0\" TLSv1.3 TLS_CHACHA20_POLY1305_SHA256 X25519MLKEM768\n\nUnd ein älterer Client ohne PQC:\n\n\n    198.51.100.7 - - [07/Apr/2026:14:05:11 +0200] \"GET / HTTP/2.0\" 200 56687 \"-\" \"Mozilla/5.0 [...] Chrome/109.0.0.0\" TLSv1.3 TLS_AES_256_GCM_SHA384 X25519\n\nDer Unterschied steht ganz am Ende: `X25519MLKEM768` vs. `X25519`. Ein Reload, ein paar Wochen sammeln, und ihr habt echte Zahlen statt Theorie. Ich werde die Ergebnisse in einem eigenen Beitrag auswerten, sobald genug Daten zusammengekommen sind.\n\nWie immer: Bei Fragen, fragen.",
  "title": "Post-Quantum TLS für Nginx — X25519MLKEM768 auf FreeBSD 15 konfigurieren"
}