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.

Fragen zu diesem Thema?

Wir unterstützen Sie bei SEO, KI-Einführung und E-Commerce.

Projekt besprechen →