Automatischer Redirect auf HTTPS mit Ausnahme eines Ordners
Heute sollte jede Seite einer Website über HTTPS ausgeliefert werden. Manchmal geht das für ein einzelnes Verzeichnis nicht: ein Partner schickt Rückmeldungen an einen alten Endpunkt ohne TLS, ein Gerät im Feld spricht nur HTTP, oder ein ACME-Client muss eine Prüfung beantworten, bevor überhaupt ein Zertifikat existiert. Die Aufgabe lautet dann: alles auf HTTPS umleiten — außer diesem einen Pfad.
Die Regel
In die .htaccess im Wurzelverzeichnis:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{REQUEST_URI} !^/kunden(/|$) [NC]
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Zeile für Zeile: die Rewrite-Engine wird eingeschaltet, umgeleitet wird nur, wenn die Anfrage nicht über TLS
kam (weder direkt noch durch einen Proxy), das Verzeichnis /kunden ist ausgenommen, alles andere geht auf
dieselbe Adresse mit https. Die Query-Zeichenkette wird automatisch mitgenommen, weil das Ziel kein eigenes
? enthält.
Ergebnis für eine Website mit der Ausnahme /kunden:
| Anfrage | Antwort |
|---|---|
http://example.com/ |
301 auf https://example.com/ |
http://example.com/kontakt?ref=mail |
301 auf https://example.com/kontakt?ref=mail |
http://example.com/kunden/api.php |
200, über HTTP ausgeliefert |
Die Präfix-Falle
Eine Bedingung wie !^/kunden/? sieht gleichwertig aus, aber RewriteCond ist am Ende nicht verankert. Das
Muster passt auf jeden Pfad, der mit /kunden beginnt — /kunden-archiv/ und /kundenonly.html sind damit
still ebenfalls von HTTPS ausgenommen. ^/kunden(/|$) trifft das Verzeichnis und sonst nichts.
Dasselbe gilt für den umgekehrten Fehler: !^kunden ohne führenden Schrägstrich passt im Kontext der
.htaccess nie, weil REQUEST_URI immer mit einem Schrägstrich beginnt. Die Umleitung läuft dann genau für
den Ordner, den Du ausnehmen wolltest.
Den ACME-Pfad offen halten
Wenn Zertifikate über Let’s Encrypt mit der http-01-Prüfung erneuert werden, darf die Prüfanfrage nicht
umgeleitet werden, solange das Zertifikat fehlt oder abgelaufen ist. Eine Bedingung mehr hält sie erreichbar:
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/ [NC]
Die Zeile kostet nichts und rettet die Erneuerung, die sonst im unpassendsten Moment scheitert.
HSTS hebt die Ausnahme aus
Eine Seite auf HTTPS schickt meistens auch diesen Header:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Hat ein Browser ihn einmal gesehen, schreibt er jede http://-Anfrage an diesen Host auf https:// um —
bevor sie den Rechner verlässt. Apache bekommt die Anfrage nie zu sehen, also kann keine Rewrite-Regel
eine Ausnahme machen. Für einen menschlichen Besucher ist der HTTP-Ordner damit unerreichbar, während ein
Server-zu-Server-Client, der HSTS ignoriert, weiter durchkommt. Dieser Unterschied ist aus einem
Support-Ticket heraus kaum zu erkennen.
Also entscheiden: entweder der ganze Host ist mit HSTS reines HTTPS, oder die Ausnahme bekommt einen eigenen
Hostnamen, zum Beispiel legacy.example.com, ohne den Header und außerhalb von includeSubDomains.
Die nginx-Fassung
In nginx gibt es keine .htaccess; dieselbe Logik gehört in den Server-Block, der auf Port 80 hört:
server {
listen 80;
server_name example.com;
root /var/www/example;
location ^~ /kunden/ {
try_files $uri $uri/ /index.php?$query_string;
}
location / {
return 301 https://$host$request_uri;
}
}
location ^~ gewinnt gegen den gewöhnlichen Präfix-Vergleich, die Ausnahme wird also zuerst ausgewertet.
Zwei Prüfungen, bevor es fertig ist
Das Verhalten von außen testen, nicht in einem Browser, der eine Umleitung zwischengespeichert haben kann:
curl -sI http://example.com/ | head -n 2
curl -sI http://example.com/kunden/ | head -n 2
Die erste Anfrage muss 301 mit einem Location auf https beantworten, die zweite 200.
Und für Suchmaschinen: Inhalte, die über http und https erreichbar bleiben, sind doppelter Inhalt. Das
ausgenommene Verzeichnis sollte entweder ein Maschinen-Endpunkt sein, nach dem niemand sucht, oder einen
Canonical-Link auf die HTTPS-Adresse tragen — sonst kostet die Ausnahme Rankings, die Du nicht eintauschen
wolltest.
Häufige Fragen
Warum leitet meine Seite nach dem Einbau endlos um?
Weil vor Apache etwas sitzt, das TLS beendet: ein Load Balancer, ein CDN oder ein Reverse Proxy. Apache sieht dann bei jeder Anfrage reines HTTP, %{HTTPS} bleibt off, und der Server leitet eine Anfrage um, die schon über HTTPS kam. Die Bedingung RewriteCond %{HTTP:X-Forwarded-Proto} !https liest den Header, den der Proxy setzt, und beendet die Schleife.
Soll ich 301 oder 302 nehmen?
Erst mit R=302 testen, dann auf R=301 umstellen, wenn die Regeln sitzen. Browser merken sich eine 301 lange und übergehen eine späte Korrektur oft wochenlang — ein falscher Dauer-Redirect verfolgt Dich dann auf dem eigenen Rechner.
Kann ich HSTS behalten und trotzdem einen HTTP-Ordner haben?
Nein. Strict-Transport-Security sagt dem Browser, dass er für die ganze max-age jede Anfrage an diesen Host auf HTTPS hochstuft. Ein Besucher, der die Seite schon kennt, erreicht die HTTP-Fassung nie. Muss ein Verzeichnis auf HTTP bleiben, gehört es auf einen eigenen Hostnamen, der nicht unter Deinem HSTS-Header liegt und nicht in der Preload-Liste steht.
Wohin kommen die Regeln in einer WordPress-.htaccess?
Über den Block „# BEGIN WordPress“. Die WordPress-Regeln enden in einem Front Controller, der die weitere Verarbeitung abbricht, und alles, was Du innerhalb des Blocks einträgst, ist beim nächsten Speichern der Permalinks weg.