---
title: "WordPress hinter einem Reverse Proxy: HTTPS und echte Client-IP sicher erkennen"
date: 2026-09-30T22:44:54+02:00
modified: 2026-11-09T11:42:26+01:00
category: wordpress
type: how_to
author: Marcel Schönfelder
canonical: https://s-edv.com/anleitungen/wordpress-reverse-proxy-https-client-ip-erkennen
keywords:
  - WordPress
  - Reverse Proxy
  - HTTPS
  - nginx
  - Apache
  - Sicherheit
reading_time: 10
---

# WordPress hinter einem Reverse Proxy: HTTPS und echte Client-IP sicher erkennen

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.

**Kurzfassung:** Lassen Sie den Proxy die Header `X-Forwarded-Proto` und `X-Forwarded-For` setzen. WordPress erkennt HTTPS über `is_ssl()` nur, wenn `$_SERVER['HTTPS']` gesetzt ist, deshalb gehört eine kleine Abfrage in die `wp-config.php`. Die Client-IP übernehmen Sie am besten auf Webserver-Ebene mit mod_remoteip (Apache) oder dem Realip-Modul (nginx). Beiden Headern dürfen Sie nur trauen, wenn die Anfrage wirklich von Ihrem Proxy kommt. Zum Schluss prüfen Sie mit einem kurzen Testskript, was WordPress tatsächlich sieht.

## Voraussetzungen

- [ ] WordPress ab Version 6.x.
- [ ] 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:

```nginx
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](https://s-edv.com/anleitungen/caddy-reverse-proxy-automatisches-https-anleitung) und zu [nginx als Reverse Proxy mit TLS](https://s-edv.com/anleitungen/nginx-reverse-proxy-tls-einrichten). Prüfen Sie nach der Änderung die Syntax und laden Sie nginx neu:

```bash
$ sudo nginx -t && sudo systemctl reload nginx
```

> **Prüfen:** `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. So läuft `curl` genau in diese Schleife und bricht 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:

```php
// 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](https://s-edv.com/anleitungen/wordpress-docker-compose-produktiv-sicher-betreiben).

Prüfen Sie die Datei danach auf Syntaxfehler:

```bash
$ php -l wp-config.php
```

> **Prüfen:** `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:

```bash
$ 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](https://s-edv.com/anleitungen/wordpress-https-umstellen-ssl-mixed-content-beheben) ausführlich.

> **Prüfen:** 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`:

Datei: `/etc/apache2/conf-available/remoteip.conf`

```plaintext
RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 10.0.0.10
```

```bash
$ 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. Dann ist `is_ssl()` 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:

```plaintext
SetEnvIfExpr "%{CONN_REMOTE_ADDR} == '10.0.0.10' && %{HTTP:X-Forwarded-Proto} == 'https'" HTTPS=on
```

Die Zeile greift 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. So kann 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:

```nginx
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](https://s-edv.com/anleitungen/wordpress-nginx-php-fpm-konfigurieren-server-block).

### 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:

```php
	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.

> **Prüfen:** 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
<?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:

```bash
$ 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
```

Der direkte Aufruf bleibt bei `is_ssl=false` und der echten Absenderadresse, weil er nicht vom eingetragenen Proxy kommt. 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.

> **Prüfen:** 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](https://wordpressupdate.de/?utm_source=s-edv.com&utm_medium=artikel&utm_campaign=107) ü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](https://s-edv.com/anleitungen/wordpress-fail2ban-wp-login-xmlrpc-serverebene-sperren). Die Speicherdauer beschreiben Sie wie gewohnt in der Datenschutzerklärung.

## 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](https://wordpressupdate.de/?utm_source=s-edv.com&utm_medium=fazit&utm_campaign=107) persönliche Betreuung aus Dresden.

## Weiterführende Anleitungen und Quellen

- [Nginx als Reverse Proxy mit TLS manuell einrichten](https://s-edv.com/anleitungen/nginx-reverse-proxy-tls-einrichten)
- [WordPress auf HTTPS umstellen und Mixed Content beheben](https://s-edv.com/anleitungen/wordpress-https-umstellen-ssl-mixed-content-beheben)
- [WordPress auf nginx mit PHP-FPM konfigurieren](https://s-edv.com/anleitungen/wordpress-nginx-php-fpm-konfigurieren-server-block)
- [Linux-Server absichern mit UFW und Fail2ban](https://s-edv.com/anleitungen/linux-server-absichern-ufw-fail2ban)
- [WordPress Advanced Administration: HTTPS und Reverse Proxy](https://developer.wordpress.org/advanced-administration/security/https/)
- [WordPress Developer Reference: is_ssl()](https://developer.wordpress.org/reference/functions/is_ssl/)
- [Apache HTTP Server: mod_remoteip](https://httpd.apache.org/docs/2.4/mod/mod_remoteip.html)
- [nginx: ngx_http_realip_module](https://nginx.org/en/docs/http/ngx_http_realip_module.html)
