WordPress hinter einem Reverse Proxy: HTTPS und echte Client-IP sicher erkennen
WordPress hinter nginx, Caddy oder Traefik: So erkennt WordPress HTTPS ohne Weiterleitungsschleife und speichert die echte Besucher-IP, ohne gefälschten Headern zu vertrauen. Mit getesteter wp-config-Abfrage, mod_remoteip und Prüfskript.
Mit KI erstellt – redaktionelle Prüfung ausstehend
WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Mehr dazu

Sobald vor WordPress ein Reverse Proxy sitzt, sieht die Website die Welt aus zweiter Hand. Der Proxy nimmt die HTTPS-Verbindung des Besuchers an, entschlüsselt sie und reicht die Anfrage per einfachem HTTP an den Webserver mit WordPress weiter. Für WordPress kommt dann jede Anfrage unverschlüsselt und von derselben internen Adresse. Typische Folgen sind eine Weiterleitungsschleife beim Login und dieselbe Proxy-IP bei allen Besuchern in Kommentaren und Login-Sperren. Diese Anleitung zeigt, wie Sie WordPress das Protokoll und die echte Client-IP sauber mitteilen, ohne dabei eine Hintertür für gefälschte Header zu öffnen.
Voraussetzungen
- WordPress ab Version 6.x, getestet mit WordPress 7.1.2 und PHP 8.4.
- Ein Reverse Proxy mit HTTPS, etwa nginx, Caddy oder Traefik, dessen Header Sie kennen oder ändern können.
- Zugriff auf die Dateien der Installation per SSH oder SFTP, insbesondere auf
wp-config.php. Für mod_remoteip oder das nginx-Realip-Modul brauchen Sie Zugriff auf die Webserver-Konfiguration. - Die interne IP-Adresse des Proxys, wie der WordPress-Server sie sieht.
- Die Rolle Administrator in WordPress.
- Ein aktuelles Backup von Dateien und Datenbank, mindestens aber eine Kopie der
wp-config.php.
Schritt 1: Den Proxy die richtigen Header setzen lassen
WordPress kann nur auswerten, was der Proxy mitschickt. Zwei Header sind entscheidend: X-Forwarded-Proto verrät, ob der Besucher per HTTP oder HTTPS kam, und X-Forwarded-For enthält die IP-Adresse des Besuchers. Den Header Host sollte der Proxy unverändert durchreichen, damit WordPress die richtige Domain sieht. Das WordPress-Handbuch zur Administration über HTTPS nennt für nginx folgende Zeilen, die wir im Labor in dieser Form eingesetzt haben:
location / {
proxy_pass http://10.0.0.20:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
10.0.0.20 steht für Ihren WordPress-Server. $proxy_add_x_forwarded_for hängt die Adresse, von der der Proxy die Anfrage erhalten hat, an einen bereits vorhandenen Header an. Schickt ein Besucher selbst einen gefälschten Header, steht seine echte Adresse trotzdem ganz rechts, der linke Teil der Liste ist frei erfindbar.
Für Caddy und Traefik siehe die Anleitungen zu Caddy als Reverse Proxy und zu nginx als Reverse Proxy mit TLS. Prüfen Sie nach der Änderung die Syntax und laden Sie nginx neu:
sudo nginx -t && sudo systemctl reload nginx
Verifizieren: nginx -t meldet syntax is ok und test is successful. Die Website ist über HTTPS erreichbar, auch wenn WordPress selbst noch Fehler zeigt.
Schritt 2: HTTPS in der wp-config.php erkennen
WordPress entscheidet mit der Funktion is_ssl(), ob eine Anfrage verschlüsselt ist. Sie prüft die Servervariable $_SERVER['HTTPS'] und den Port 443. Den Header X-Forwarded-Proto wertet WordPress von sich aus nicht aus. Hinter einem Proxy hält WordPress deshalb jede Anfrage für unverschlüsselt. Steht die Website auf https://, leitet WordPress den Login immer wieder auf HTTPS um, obwohl der Besucher schon dort ist. Im Labor lief curl genau in diese Schleife und brach nach 50 Weiterleitungen mit Status 302 ab. Im Browser erscheint dann sinngemäß die Meldung, dass die Seite zu oft weitergeleitet wurde.
Die WordPress-Dokumentation schlägt dafür eine Abfrage in der wp-config.php vor. Wir empfehlen eine etwas strengere Fassung, die dem Header nur glaubt, wenn die Anfrage von Ihrem Proxy kommt. Fügen Sie den Block oberhalb der Zeile /* That's all, stop editing! */ ein und tragen Sie die Adresse Ihres Proxys ein, so wie der WordPress-Server sie sieht:
// Nur Anfragen vom eigenen Proxy dürfen Protokoll und Client-IP vorgeben.
$vertrauenswuerdige_proxys = array( '10.0.0.10' );
if ( isset( $_SERVER['REMOTE_ADDR'] ) && in_array( $_SERVER['REMOTE_ADDR'], $vertrauenswuerdige_proxys, true ) ) {
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] )
&& 'https' === strtolower( trim( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) ) {
$_SERVER['HTTPS'] = 'on';
}
}
Ohne die Einschränkung kann jeder, der den WordPress-Server direkt erreicht, den Header selbst senden. Achtung bei Docker: Das offizielle Image wordpress schreibt bereits eine eigene, uneingeschränkte Abfrage auf HTTP_X_FORWARDED_PROTO in die generierte wp-config.php. Ersetzen Sie diesen Block durch den obigen. Wie Sie das Image insgesamt absichern, beschreibt die Anleitung WordPress mit Docker Compose produktiv betreiben.
Prüfen Sie die Datei danach auf Syntaxfehler:
php -l wp-config.php
Verifizieren: php -l meldet No syntax errors detected. Die Anmeldeseite unter /wp-login.php lädt über HTTPS ohne Weiterleitungsschleife. Im Quelltext der Anmeldeseite beginnen die Stylesheet-Adressen mit https://.
Schritt 3: Die Adressen der Website auf HTTPS stellen
Unter Einstellungen > Allgemein stehen die Felder „WordPress-Adresse (URL)“ und „Website-Adresse (URL)“. Beide müssen mit https:// und Ihrer öffentlichen Domain beginnen, nicht mit der internen Adresse des WordPress-Servers. Stellen Sie die Adressen erst um, wenn Schritt 2 erledigt ist. Sonst sperren Sie sich per Schleife aus. Mit WP-CLI:
wp option get home
wp option get siteurl
wp option update home 'https://www.example.de'
wp option update siteurl 'https://www.example.de'
Ist die Website bisher unter http:// gelaufen, stecken die alten Adressen auch in Beiträgen und Einstellungen. Diese Umstellung behandelt die Anleitung WordPress auf HTTPS umstellen und Mixed Content beheben ausführlich.
Verifizieren: Beide Optionen geben die HTTPS-Adresse aus. Startseite und Dashboard laden ohne Mixed-Content-Warnung in der Browserkonsole.
Schritt 4: Die echte Client-IP übernehmen
WordPress liest die Besucheradresse aus $_SERVER['REMOTE_ADDR']. Hinter einem Proxy steht dort dessen Adresse. Kommentare tragen dann alle dieselbe IP, und Login-Sperren treffen den Proxy und damit alle Besucher. Am saubersten setzen Sie die Adresse im Webserver um, dann stimmen auch die Zugriffsprotokolle.
Apache mit mod_remoteip
Das Modul ersetzt die Verbindungsadresse durch die Adresse aus dem angegebenen Header, aber nur für Anfragen von eingetragenen Proxys. Die Apache-Dokumentation warnt ausdrücklich: Ohne RemoteIPInternalProxy oder RemoteIPTrustedProxy vertraut das Modul jedem Absender. Legen Sie eine Datei an, etwa /etc/apache2/conf-available/remoteip.conf:
RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 10.0.0.10
sudo a2enmod remoteip
sudo a2enconf remoteip
sudo apache2ctl configtest && sudo systemctl reload apache2
Wichtig: Ab jetzt steht in REMOTE_ADDR die Adresse des Besuchers und nicht mehr die des Proxys. Die Abfrage aus Schritt 2 vergleicht aber genau diese Variable mit der Proxy-Adresse und greift deshalb nicht mehr. Im Labor war is_ssl() danach wieder false. Verlagern Sie die HTTPS-Erkennung dann ebenfalls in Apache und entfernen Sie den Block aus der wp-config.php. CONN_REMOTE_ADDR enthält laut Apache-Dokumentation weiter die Adresse des Proxys:
SetEnvIfExpr "%{CONN_REMOTE_ADDR} == '10.0.0.10' && %{HTTP:X-Forwarded-Proto} == 'https'" HTTPS=on
Im Test griff die Zeile nur für Anfragen über den Proxy. Damit auch das Zugriffsprotokoll die echte Adresse zeigt, sollte das Logformat %a verwenden, so beschreibt es die Apache-Dokumentation. Das Docker-Image wordpress bringt mod_remoteip bereits aktiviert mit, trägt aber alle privaten Netze als vertrauenswürdig ein, also 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16 und 127.0.0.0/8. Im Labor konnte so jeder Rechner aus diesen Netzen eine beliebige Adresse vorgeben. Beschränken Sie die Liste auf Ihren Proxy.
nginx als Webserver mit dem Realip-Modul
Läuft WordPress auf nginx mit PHP-FPM, übernimmt das Modul ngx_http_realip_module dieselbe Aufgabe. Die Debian-Pakete von nginx enthalten es. Die Direktiven gehören in den server-Block der WordPress-Website, nicht in den Proxy:
set_real_ip_from 10.0.0.10;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
Mit real_ip_recursive on nimmt nginx die letzte Adresse in der Liste, die nicht zu einem vertrauenswürdigen Absender gehört. Auch hier gilt: Das Modul ändert die Absenderadresse, die PHP-FPM an WordPress übergibt, und die Abfrage aus Schritt 2 findet die Proxy-Adresse nicht mehr. Sperren Sie dann den Direktzugriff wie in Schritt 5 und nutzen Sie die einfachere Abfrage aus dem WordPress-Handbuch, die nur den Header prüft. Den Aufbau des übrigen Server-Blocks zeigt die Anleitung WordPress auf nginx mit PHP-FPM konfigurieren.
Ohne Zugriff auf den Webserver: Ergänzung in der wp-config.php
Können Sie nur die Dateien von WordPress ändern, erweitern Sie den Block aus Schritt 2 innerhalb der äußeren if-Abfrage um folgende Zeilen:
if ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
$kette = array_map( 'trim', explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] ) );
$client = end( $kette );
if ( filter_var( $client, FILTER_VALIDATE_IP ) ) {
$_SERVER['REMOTE_ADDR'] = $client;
}
}
Der Code nimmt bewusst den letzten, vom Proxy angehängten Eintrag. Das passt für genau einen Proxy. Bei CDN oder Load Balancer davor ist die Lösung im Webserver robuster, weil sie Ketten mehrerer Proxys auswertet.
Verifizieren: Schreiben Sie einen Testkommentar über die öffentliche Adresse. Unter Kommentare steht beim neuen Eintrag Ihre eigene öffentliche IP und nicht die Adresse des Proxys.
Schritt 5: Mit einem Testskript prüfen und den Direktzugriff sperren
Ein kleines Skript unter einem schwer zu erratenden Namen zeigt, was WordPress wirklich sieht:
<?php
require __DIR__ . '/wp-load.php';
header( 'Content-Type: text/plain' );
echo 'REMOTE_ADDR=', $_SERVER['REMOTE_ADDR'], "\n";
echo 'is_ssl=', var_export( is_ssl(), true ), "\n";
echo 'home=', home_url(), "\n";
Rufen Sie es über die öffentliche Adresse und mit gefälschten Headern direkt am WordPress-Server auf:
curl -s https://www.example.de/pruefung-7f3k.php
curl -s -H 'X-Forwarded-For: 198.51.100.66' -H 'X-Forwarded-Proto: https' http://10.0.0.20/pruefung-7f3k.php
Im Labor blieb der direkte Aufruf bei is_ssl=false und der echten Absenderadresse, weil er nicht vom eingetragenen Proxy kam. Löschen Sie das Skript danach sofort.
Noch besser ist es, wenn der WordPress-Server gar nicht direkt erreichbar ist. Lassen Sie den Webserver nur intern lauschen oder erlauben Sie per Firewall nur den Proxy. Bei Docker binden Sie den Port des WordPress-Containers an 127.0.0.1 oder veröffentlichen ihn gar nicht, wenn der Proxy im selben Docker-Netz läuft.
Verifizieren: Der öffentliche Aufruf zeigt is_ssl=true, Ihre echte IP und die HTTPS-Adresse. Der direkte Aufruf mit gefälschten Headern zeigt is_ssl=false oder scheitert, weil der Server von außen nicht erreichbar ist. Das Testskript ist gelöscht.
Mit der Einrichtung ist die Arbeit nicht abgeschlossen. Proxy, Webserver und WordPress bekommen regelmäßig Updates, danach lohnt ein Blick, ob Client-IP und HTTPS noch stimmen. Wer diese Pflege nicht selbst im Kalender halten möchte, kann sie abgeben: Die WordPress-Wartung von wordpressupdate.de übernimmt Updates von WordPress, Plugins und Themes mit Kompatibilitätsprüfung, wöchentliche Backups auf externen Speicher und die Einrichtung und Wartung der Firewall.
Typische Fehler
| Fehlerbild | Ursache | Lösung |
|---|---|---|
Login endet in einer Weiterleitungsschleife, curl -L zeigt immer wieder 302 | WordPress erkennt HTTPS nicht, $_SERVER['HTTPS'] fehlt | Block aus Schritt 2 einfügen, Proxy-Adresse prüfen |
| Schleife bleibt trotz Block in der wp-config.php | Eingetragene Adresse ist nicht die, die WordPress als REMOTE_ADDR sieht | Adresse mit dem Testskript aus Schritt 5 ermitteln |
| Stylesheets und Bilder laden per HTTP, Seite ohne Gestaltung | Adressen der Website oder Inhalte noch auf http:// | Schritt 3, danach wp search-replace |
| Alle Kommentare tragen dieselbe IP | REMOTE_ADDR ist die Proxy-Adresse | mod_remoteip, Realip-Modul oder Ergänzung aus Schritt 4 |
| Nach Aktivieren von mod_remoteip kehrt die Weiterleitungsschleife zurück | REMOTE_ADDR enthält jetzt die Besucheradresse, die Abfrage in der wp-config.php greift nicht mehr | HTTPS per SetEnvIfExpr mit CONN_REMOTE_ADDR setzen |
| Beliebige IP lässt sich per Header vorgeben | mod_remoteip vertraut ganzen Netzen, etwa der Vorgabe im Docker-Image | Liste auf die Proxy-Adresse beschränken |
Häufige Fragen
Reicht es, FORCE_SSL_ADMIN zu setzen?
Nein. Die Konstante FORCE_SSL_ADMIN erzwingt HTTPS für Anmeldung und Adminbereich. Hinter einem Proxy erzeugt sie laut WordPress-Handbuch sogar die Schleife, solange X-Forwarded-Proto nicht ausgewertet wird.
Gilt das auch für ein CDN vor der Website?
Das Prinzip ist gleich, nur die Kette wird länger. Tragen Sie die vom Anbieter veröffentlichten Adressbereiche als vertrauenswürdig ein, die einfache Ergänzung aus Schritt 4 reicht dafür nicht.
Warum ist die echte IP auch für den Datenschutz relevant?
WordPress speichert bei Kommentaren die IP-Adresse. Steht dort nur die Proxy-Adresse, fehlen Anhaltspunkte bei Missbrauch, etwa für Sperren mit Fail2ban. Die Speicherdauer beschreiben Sie wie gewohnt in der Datenschutzerklärung.
Testumfang
Wir haben den Aufbau mit WordPress 7.1.2 hinter nginx als HTTPS-Proxy nachgestellt, die Weiterleitungsschleife verschwand zuverlässig mit dem Block in der wp-config.php. Auffällig war, dass mod_remoteip diese Abfrage aushebelt, die HTTPS-Erkennung gehört dann in den Apache. Andere Proxy-Lösungen und CDN-Ketten mit mehreren Proxys haben wir nicht geprüft, dort sollten Sie die Prüfung aus Schritt 5 in Ihrer eigenen Umgebung nachvollziehen.
Fazit
Hinter einem Reverse Proxy braucht WordPress zwei Informationen, die es nicht selbst ermitteln kann: das Protokoll des Besuchers und seine IP-Adresse. Beide kommen per Header, und beiden dürfen Sie nur trauen, wenn der Absender Ihr eigener Proxy ist. Eingeschränkte Abfragen und ein gesperrter Direktzugriff beseitigen Schleifen und falsche IPs. Wenn Sie Updates, Backups und Firewall für Ihre Website lieber in feste Hände geben, finden Sie bei der WordPress-Wartung von Marcel Schönfelder persönliche Betreuung aus Dresden.
Weiterführende Anleitungen und Quellen
- Nginx als Reverse Proxy mit TLS manuell einrichten
- WordPress auf HTTPS umstellen und Mixed Content beheben
- WordPress auf nginx mit PHP-FPM konfigurieren
- WordPress Advanced Administration: HTTPS und Reverse Proxy
- WordPress Developer Reference: is_ssl()
- Apache HTTP Server: mod_remoteip
- nginx: ngx_http_realip_module


