HTTPS afdwingen in WordPress (zonder redirect-lus)

Je SSL-certificaat is actief (voor een uitleg over certificaattypen, zie [SSL-certificaten in WordPress]({{ '/en/knowledge-base/wordpress/security/ssl-certificate-in-wordpress/' | locale_url }})) maar WordPress laadt nog steeds over HTTP, of je hebt een redirect ingeschakeld en nu krijg je ERR_TOO_MANY_REDIRECTS. Deze gids behandelt de vier methodes die echt werken, op volgorde van veiligheid, plus de twee configuraties (Cloudflare Flexible en niet-vertrouwde reverse proxies) die je in de soep laten lopen als je ze overslaat.

Je SSL-certificaat staat geïnstalleerd, het slotje werkt op https://yoursite.nl, maar als je yoursite.nl in de adresbalk typt kom je nog steeds op http:// uit. Of je hebt een redirect-regel toegevoegd, de site werkte even, en nu gooit elke URL ERR_TOO_MANY_REDIRECTS. Beide situaties komen uit dezelfde wortel: HTTPS afdwingen op WordPress is een probleem in vier lagen, en de meeste tutorials behandelen er maar één.

Waarom je WordPress-site nog steeds over HTTP laadt na het installeren van SSL

Om de hele site naar HTTPS te dwingen moeten vier dingen het met elkaar eens zijn, in deze volgorde:

  1. Een geldig SSL-certificaat staat geïnstalleerd en luistert op poort 443 op het webserverniveau. Werkt https://yoursite.nl niet als je het zelf intypt in een browser, dan gaat geen enkele WordPress-instelling iets oplossen. Stop hier en regel eerst het certificaat.
  2. De webserver geeft een 301-redirect terug van HTTP naar HTTPS voor elke URL. Dit is niet de taak van WordPress. Apache doet dit via .htaccess of een <VirtualHost>-directive, nginx doet het in een server-block. WordPress heeft hier geen controle over.
  3. De URL-instellingen van WordPress zelf (siteurl en home) wijzen naar https:// zodat alle links die WordPress zelf genereert (in menu's, canonical-tags, login-redirects en wp_redirect()-aanroepen) het beveiligde schema gebruiken.
  4. De HTTP-URL's die al in de database zijn opgeslagen worden herschreven naar https://. Oude post-content, widget-instellingen, theme customizer-waarden en plugin-opties kunnen allemaal nog hardcoded http://yoursite.nl/... URL's bevatten die een instellingenwijziging gewoon overleven.

Sla je laag 2 over, dan werkt de homepage maar zoekmachines en bookmarks blijven op HTTP hangen. Sla je laag 3 over, dan krijg je mixed content waarschuwingen. Sla je laag 4 over, dan breekt het slotje zodra een bezoeker een oude blogpost opent.

De methodes hieronder regelen laag 2 en 3. Laag 1 is de taak van je hostingpaneel, en laag 4 wordt grondig behandeld in het mixed content artikel. Het lastigste aan laag 2 goed krijgen is zorgen dat je webservertype overeenkomt met de methode die je kiest: een .htaccess-bestand wordt stilletjes genegeerd op nginx. Geen foutmelding in de log, geen waarschuwing in het dashboard, geen hint dat er iets mis is. Het bestand bestaat gewoon niet voor nginx. Zit je op nginx en volg je een Apache-tutorial, dan kun je een hele middag aan .htaccess zitten te frunniken en je afvragen waarom er niets verandert.

Achterhaal eerst welke webserver je hebt voordat je een methode kiest. De snelste manier is via je hostingpaneel: de meeste panelen (cPanel, Plesk, DirectAdmin) tonen het webservertype op het dashboard of onder "Serverinformatie." Vind je het daar niet, open dan DevTools in je browser (F12 of Ctrl+Shift+I), ga naar het Network-tabblad, herlaad https://yoursite.nl/, klik op het eerste verzoek en zoek in de Response Headers naar een Server:-header. Je ziet dan Apache/2.4.x, nginx/1.x, LiteSpeed of cloudflare (als Cloudflare ervoor zit, lees dan het Cloudflare-deel hieronder voor het achterhalen van het type origin server).

Heb je SSH-toegang:

curl -sI https://yoursite.nl/ | grep -i server

LiteSpeed leest .htaccess-bestanden in een Apache-compatibele modus, dus de Apache-methode werkt daar ook. Pure nginx niet.

Methode 1: WP 5.7+ één-klik HTTPS migratie (de veiligste optie)

Zit je op WordPress 5.7 of nieuwer en is je site rechttoe rechtaan (één domein, geen WP_HOME of WP_SITEURL constanten in wp-config.php), dan zit er in het dashboard al een ingebouwde tool die laag 3 en 4 met één klik afhandelt. WordPress 5.7 introduceerde wp_is_https_supported(), wp_update_urls_to_https() en wp_replace_insecure_home_url() juist om HTTPS-migratie van een project naar een knop te brengen.

Vereisten.

  • WordPress 5.7 of nieuwer.
  • Een geldig SSL-certificaat dat al geïnstalleerd is en bereikbaar op https://yoursite.nl. De tool draait twee keer per dag een echte HTTPS-request tegen je eigen URL via wp_is_https_supported() en zet de knop pas aan als die request slaagt.
  • Site Address en WordPress Address gebruiken hetzelfde domein. Sites waar deze twee verschillen op domeinniveau worden niet ondersteund door de één-klik tool.
  • Geen WP_HOME of WP_SITEURL constanten in wp-config.php. Dit is het addertje dat de meeste lezers vangt. De constanten overschrijven de database-waarden die de migratie wegschrijft, dus de tool weigert te draaien of lijkt te slagen maar valt terug bij de volgende page load.

Stappen.

  1. Log in op de WordPress admin.
  2. Ga naar Tools > Site Health > Status.
  3. Zoek naar het critical issue "Your website does not use HTTPS". Sinds 5.7 is afwezige HTTPS opgewaardeerd van "recommended" naar critical.
  4. Klik op Update your site to use HTTPS. De knop verschijnt alleen als de onderliggende HTTPS-check is geslaagd. Zie je de knop niet, lees dan de troubleshooting hieronder.
  5. WordPress draait wp_update_urls_to_https(), wat de siteurl- en home-opties bijwerkt en HTTP-URL's in de database herschrijft.

Verificatie. Herlaad de front end in een nieuw incognito-venster. Het slotje moet dicht zijn. Bezoek een paar oude blogposts om dat te bevestigen. Controleer dan de database-waarden: ga in wp-admin naar Instellingen > Algemeen en kijk of zowel WordPress-adres (URL) als Siteadres (URL) met https:// begint.

WP-CLI alternatief:

wp option get siteurl
wp option get home

Beide horen https://yoursite.nl terug te geven.

Als de knop niet verschijnt. Controleer wp-config.php op deze regels:

define( 'WP_HOME', '...' );
define( 'WP_SITEURL', '...' );

Bestaan ze, dan is de één-klik tool uitgeschakeld omdat de constanten alles wat de tool wegschrijft toch zouden overschrijven. Twee opties: haal de constanten weg en laat de database de URL's beheren (dan werkt de één-klik tool wel), of houd de constanten en gebruik Methode 4 in plaats hiervan. Er is geen manier om de één-klik tool naast hardcoded constanten te laten werken.

De één-klik tool regelt laag 2 niet. Hij werkt URL's bij en herschrijft opgeslagen content, maar installeert geen server-niveau redirect. Na het draaien heb je nog steeds Methode 2 (Apache) of Methode 3 (nginx) nodig om bezoekers die http://yoursite.nl typen een 301 naar HTTPS te geven.

Methode 2: Apache .htaccess redirect

Draait je origin op Apache (of LiteSpeed, dat .htaccess in Apache-compatibele modus leest), dan is dit de standaard layer-2 fix. Het zegt tegen de server dat hij voor elk binnenkomend HTTP-verzoek een 301-redirect moet geven, voordat WordPress überhaupt geladen wordt.

Vereisten.

  • Apache 2.4 of LiteSpeed.
  • mod_rewrite aan staan. Op de meeste shared hosts staat hij al aan; weet je het niet zeker, check dan de Apache-modulelijst in je hostingpaneel of vraag het aan je host. Heb je SSH-toegang: apachectl -M | grep rewrite moet rewrite_module teruggeven.
  • AllowOverride All (of minimaal AllowOverride FileInfo) voor de WordPress-directory in de hoofd-Apache-config. Shared hosts hebben dat vrijwel altijd zo staan. Heeft jouw host dat niet, dan heeft de regel hieronder geen effect.
  • Schrijfrechten op .htaccess in de WordPress-root.

Stappen.

  1. Open .htaccess in de WordPress-root via SFTP of de bestandsbeheerder van je controlpaneel.

  2. Zoek het bestaande WordPress-blok. Dat ziet er zo uit:

    # BEGIN WordPress
    
    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.php$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]
    
    # END WordPress
  3. Voeg de HTTPS-redirect regel boven het WordPress-blok toe. Plaats hem in zijn eigen <IfModule> zodat hij niet botst met de pretty-permalinks regels van WordPress:

    
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
    
  4. Bewaar het bestand. Wijzig het WordPress-blok zelf niet; dat blok wordt opnieuw aangemaakt bij Instellingen > Permalinks > Wijzigingen opslaan en eigen regels die je daarbinnen zet worden gewoon weggegooid.

Wat deze regel doet, regel voor regel. RewriteEngine On activeert mod_rewrite voor deze directory. RewriteCond %{HTTPS} off controleert de servervariabele HTTPS, die Apache op on zet voor SSL-verbindingen en anders leeg laat. RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L] vangt elk pad, plakt er https:// en de oorspronkelijke host voor en geeft een permanente (301) redirect. De L-flag zegt tegen mod_rewrite om te stoppen met het verwerken van meer regels zodra deze matcht.

Het complete eindresultaat van .htaccess ziet er zo uit:


RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]


# BEGIN WordPress

RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

# END WordPress

Verificatie. Open een nieuw incognito-venster, open DevTools (F12), ga naar het Network-tabblad, vink Preserve log aan en bezoek http://yoursite.nl/some-post/. Het eerste verzoek hoort een 301 Moved Permanently te tonen met een Location-header die naar https://yoursite.nl/some-post/ wijst. Doe dit ook voor de homepage en een paar andere URL's. Als de tweede hop (de https:// URL) zelf weer een redirect geeft die terugwijst naar http://, dan zit je op het randje van een lus. Stop en lees eerst het Cloudflare- en reverse proxy-deel hieronder voordat je verder gaat.

Heb je SSH-toegang:

curl -sI http://yoursite.nl/some-post/

Verwachte output: HTTP/1.1 301 Moved Permanently met Location: https://yoursite.nl/some-post/.

Een kanttekening over .htaccess-prestaties. De officiële Apache-documentatie raadt het gebruik van .htaccess-bestanden af zodra je toegang hebt tot de hoofd-server config, omdat Apache bij elk verzoek op elk directoryniveau naar .htaccess moet zoeken en rewrite-regels in .htaccess per verzoek opnieuw worden gecompileerd in plaats van gecached. Op shared hosting heb je geen keuze; op een VPS of dedicated server zet je dezelfde regels in een <Directory>-blok in je virtual host config en schakel je .htaccess helemaal uit.

Methode 3: nginx server block

Deze methode vereist SSH-toegang tot je server, of een managed host die je nginx-configuratie via hun dashboard laat bewerken.

nginx leest geen .htaccess-bestanden. Hij waarschuwt je er niet voor, hij logt ze niet, hij parseert ze gewoon niet. Zit je op nginx, dan moet de redirect in een server-blok in je hoofd-nginx config of een van de conf.d/ includes staan. Daar ontkom je niet aan.

Vereisten.

  • nginx 1.x.
  • Root-toegang om nginx-configbestanden te bewerken (de meeste managed hosts regelen dit zelf via hun dashboard).
  • De mogelijkheid om nginx te herladen na het bewerken.

Stappen.

  1. Vind de nginx-config van je site. Op Debian en Ubuntu staat die meestal op /etc/nginx/sites-available/yoursite.nl met een symlink in sites-enabled/. Op RHEL en CentOS in /etc/nginx/conf.d/yoursite.nl.conf.

  2. Je hoort twee server-blokken te hebben: een die luistert op poort 80 (HTTP), en een op poort 443 (HTTPS). Heb je alleen een poort-80-blok, dan is je SSL niet daadwerkelijk geconfigureerd op nginx-niveau en moet je dat eerst regelen.

  3. Vervang de hele inhoud van het poort-80-blok door één enkele return 301 directive. Dat hele blok krijgt nu één doel: alles naar HTTPS sturen en stoppen:

    server {
        listen 80;
        listen [::]:80;
        server_name yoursite.nl www.yoursite.nl;
        return 301 https://yoursite.nl$request_uri;
    }
  4. Test de nginx-config voor je herlaadt:

    nginx -t

    Verwachte output.

    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /etc/nginx/nginx.conf test is successful
  5. Herlaad nginx:

    systemctl reload nginx

Waarom return 301 en niet rewrite. De nginx-docs zeggen dat return direct wordt verwerkt zonder regex-evaluatie, wat het meetbaar sneller maakt dan de equivalente rewrite ^ https://... directive. Er is geen reden om rewrite te gebruiken voor een eenvoudige HTTP-naar-HTTPS redirect.

Waarom de redirect naar een hardcoded https://yoursite.nl wijst en niet naar https://$host. Als een bezoeker direct het IP aanspreekt, of een Host-header zet voor een domein dat eigenlijk niet op deze server staat, dan reflecteert $host dat. Door de canonieke hostname hardcoded te zetten, dwing je elke redirect af op de URL die je daadwerkelijk geïndexeerd wilt zien, waardoor je in dezelfde hop ook de www-versus-niet-www ambiguïteit oplost. Wil je www houden, gebruik dan https://www.yoursite.nl$request_uri in plaats hiervan.

Verificatie. Zelfde test als bij Methode 2: open DevTools, bezoek http://yoursite.nl/some-post/ in een incognito-venster met Preserve log aan, en controleer of het eerste verzoek een 301 is met een Location die naar https:// wijst. Check de Server-header in de response: die hoort nginx te zijn. Staat daar Apache of cloudflare, dan heb je de verkeerde laag bewerkt en heeft de wijziging geen effect.

Heb je SSH-toegang:

curl -sI http://yoursite.nl/some-post/

Verwachte output: HTTP/1.1 301 Moved Permanently met Location: https://yoursite.nl/some-post/ en Server: nginx/1.24.0.

Methode 4: wp-config.php constanten

Methode 2 en 3 regelen laag 2 (de redirect op serverniveau). Methode 1 regelt laag 3 en 4 (URL-instellingen en database-content). Wat overblijft is het laag-3 geval waarin de één-klik tool niet werkt: managed hosts die WP_HOME en WP_SITEURL hardcoded in wp-config.php zetten, multisite-installaties en elke omgeving waar de canonieke URL in code moet staan in plaats van in de database.

Wanneer gebruik je deze methode.

  • Je zit op WordPress ouder dan 5.7.
  • Je host definieert al WP_HOME/WP_SITEURL in wp-config.php en je kunt ze niet weghalen.
  • Je wilt de URL vastpinnen in version control in plaats van in de database.
  • De één-klik tool weigert te draaien om een van de redenen uit Methode 1.

Stappen.

  1. Open wp-config.php in de WordPress-root.

  2. Zoek de regel /* That's all, stop editing! Happy publishing. */.

  3. Boven die regel voeg je de constanten toe of werk je ze bij:

    define( 'WP_HOME',    'https://yoursite.nl' );
    define( 'WP_SITEURL', 'https://yoursite.nl' );
  4. Geen trailing slash. Match www versus niet-www aan wat je SSL-certificaat dekt.

  5. Bewaar het bestand.

Wat deze constanten echt doen. De officiële wp-config.php-documentatie is duidelijk: WP_SITEURL "will not change the database stored value" en "the URL will revert to the old database value if this line is ever removed." De constanten overschrijven de home- en siteurl-opties in wp_options op runtime; ze schrijven niets naar de database. Dat is precies wat je wil als de admin onbereikbaar is, als je via Git deployt of als je de canonieke URL in code wil vastpinnen.

FORCE_SSL_ADMIN is hier geen vervanger voor. De naam van de constant is misleidend. force_ssl_admin() is gedocumenteerd als "Determines whether to force SSL used for the Administration Screens", en de scope is alleen wp-admin en wp-login.php. FORCE_SSL_ADMIN op true zetten dwingt de publieke site niet naar HTTPS, redirect HTTP-bezoekers niet en heeft geen effect op URL's buiten het admin-gebied. Het is een security hardening voor je back office, geen site-brede HTTPS-schakelaar. Veel tutorials halen dit door elkaar. Het WordPress login redirect loop artikel behandelt wat er gebeurt als je FORCE_SSL_ADMIN aanzet op een site die de admin niet daadwerkelijk over HTTPS kan serveren.

Verificatie. Herlaad de front end. Inspecteer de paginabron. De <link rel="canonical">-tag, de admin bar URL's en eventuele <base>-tag moeten allemaal met https:// beginnen. Controleer dan wp-admin: die hoort over HTTPS te laden zonder enige redirect-keten.

Als alle vier de methodes (waar van toepassing) op hun plek staan, draai dan een database search-replace om eventuele oude http://yoursite.nl-URL's op te ruimen die nog in post-content, postmeta en opties zijn geserialiseerd. De constanten herschrijven geen opgeslagen content; ze overschrijven alleen wat WordPress op runtime van de opties leest.

Cloudflare-specifiek: Full (Strict), nooit Flexible

Zit Cloudflare voor je WordPress-site, dan kan je SSL/TLS-modus stiekem een redirect-lus creëren die op een WordPress-probleem lijkt maar dat niet is. Cloudflare's eigen documentatie zegt dat "Flexible" mode "creates HTTPS connections between your visitor and Cloudflare, but all connections between Cloudflare and your origin are made through HTTP". Het mechanisme dat WordPress sloopt is direct: Cloudflare praat over HTTP met de origin, de .htaccess-redirect (Methode 2) of nginx server block (Methode 3) van de origin stuurt een 301 terug naar HTTPS, Cloudflare ontvangt die redirect en stuurt de bezoeker terug naar HTTPS, wat weer op Cloudflare uitkomt, wat weer over HTTP met de origin gaat praten. Oneindige lus. De browser toont na zo'n 20 hops ERR_TOO_MANY_REDIRECTS.

Hoe je je huidige Cloudflare SSL-modus controleert.

  1. Log in op Cloudflare en kies de site in kwestie.
  2. Open SSL/TLS > Overview.
  3. Bekijk de encryptiemodus. Je ziet een van: Off, Flexible, Full, Full (Strict).

Wat elke modus betekent.

Modus Bezoeker naar Cloudflare Cloudflare naar origin Lus-risico bij Methode 2 of 3
Off HTTP HTTP Geen (helemaal geen HTTPS)
Flexible HTTPS HTTP Ja
Full HTTPS HTTPS (cert niet gevalideerd) Geen
Full (Strict) HTTPS HTTPS (cert gevalideerd) Geen

De fix is de modus upgraden, niet je origin-redirect weghalen. Als je de origin-redirect weghaalt om de lus te "fixen", laat je een gat open: iedereen die de origin direct benadert (via IP, via een hostname, via een oude DNS-record) krijgt gewoon HTTP. Doe in plaats daarvan dit:

  1. Zorg dat de origin een geldig SSL-certificaat heeft. Let's Encrypt is gratis en wordt op elk hostingpaneel ondersteund; Cloudflare biedt ook gratis Origin CA-certificaten die door de Cloudflare edge worden vertrouwd maar niet door browsers, wat exact is wat je wil voor een origin achter Cloudflare.
  2. Zet de SSL/TLS-modus op Full (Strict). Dit valideert het origin-certificaat tegen een vertrouwde CA en weigert te praten met een origin waar het cert ontbreekt of verlopen is.
  3. Purge de Cloudflare-cache: Caching > Configuration > Purge Everything. Wacht ongeveer 30 seconden tot de wijziging is doorgekomen.
  4. Herlaad de site in een nieuw incognito-venster. De lus moet nu weg zijn.

Cloudflare zegt zelf ook expliciet Full of Full (Strict) te gebruiken voor "sites handling sensitive information (personalized data, user login)". Elke WordPress-site heeft user login op wp-admin, ook als de front end puur informatief is. Flexible mode is nooit het juiste antwoord voor WordPress.

Kun je echt geen certificaat op de origin installeren, dan is de enige workaround die geen lus creëert om de HTTP-naar-HTTPS-redirect van de origin helemaal weg te halen en in plaats daarvan Cloudflare's Always Use HTTPS page rule te gebruiken om de redirect aan de edge te doen. Dat is een workaround, geen aanbevolen houding: het laat de origin bereikbaar over plain HTTP voor iedereen die het IP weet, en het legt de hele verantwoordelijkheid voor HTTPS-handhaving bij Cloudflare. Gebruik het als noodgreep terwijl je een fatsoenlijk origin-certificaat regelt.

Wil je het probleem vanuit de symptoom-kant bekijken (en de andere vier oorzaken van ERR_TOO_MANY_REDIRECTS zien), lees dan het too many redirects artikel.

De redirect-lus debuggen

Heb je een methode hierboven toegepast en gooit de site nu ERR_TOO_MANY_REDIRECTS, dan komt het bijna altijd door één van drie dingen: de Cloudflare-lus hierboven, twee lagen die allebei HTTPS afdwingen maar het oneens zijn, of een reverse proxy waar WordPress en de proxy het oneens zijn over het huidige schema. Diagnose eerst, daarna pas verder klooien.

Stap 1: lees de redirect-keten. Open de site in een incognito-venster met DevTools op het Network-tabblad, vink Preserve log en Disable cache aan, en laad de URL. Je ziet een reeks 301/302-responses. Lees de Location-header van elke response.

  • http://yoursite.nl naar https://yoursite.nl naar http://yoursite.nl betekent dat twee lagen het oneens zijn over het canonieke schema. De ene dwingt HTTPS af, de andere dwingt HTTP af. De Cloudflare Flexible-situatie hierboven produceert exact dit patroon.
  • De keten blijft www toevoegen of verwijderen betekent dat je canonieke hostname niet consistent is. Je .htaccess of nginx-redirect wijst naar de verkeerde host, of WP_HOME en WP_SITEURL gebruiken een andere host dan de redirect.
  • De lus begint pas op /wp-admin/ betekent dat FORCE_SSL_ADMIN aan staat op een site die de admin niet daadwerkelijk over HTTPS kan serveren, meestal door een reverse proxy of Cloudflare Flexible.

Stap 2: bevestig wat de origin echt doet. Sla elke CDN of proxy over en spreek de origin direct aan. Vanaf een server met shell-toegang, of vanaf je eigen machine met het origin-IP in /etc/hosts:

curl -sI --resolve yoursite.nl:443:ORIGIN_IP https://yoursite.nl/
curl -sI --resolve yoursite.nl:80:ORIGIN_IP http://yoursite.nl/

Vervang ORIGIN_IP door je echte origin-IP (Cloudflare verbergt het; check je hostingpaneel voor het echte adres). Het eerste commando hoort een 200 OK van het HTTPS-endpoint terug te geven. Het tweede hoort één enkele 301 terug te geven die naar https://yoursite.nl/ wijst. Geeft het HTTPS-endpoint van de origin zelf weer een 301-redirect, dan zit de origin in een zelf-refererende lus en zit de fix op de origin, niet aan de edge.

Stap 3: controleer de URL-instellingen van WordPress. Ga in wp-admin naar Instellingen > Algemeen en kijk of zowel WordPress-adres (URL) als Siteadres (URL) met https:// begint. Staan ze op http://, draai dan Methode 1 of Methode 4 om dit te herstellen.

WP-CLI alternatief:

wp option get siteurl
wp option get home

Beide horen https://yoursite.nl terug te geven (of welke canonieke URL je certificaat ook dekt).

Reverse proxy en load balancer caveats: vertrouw X-Forwarded-Proto alleen als het veilig is

Draait WordPress achter een reverse proxy of load balancer die TLS termineert en daarna plain HTTP doorstuurt naar de origin, dan ziet het PHP-proces $_SERVER['HTTPS'] als leeg en denkt dat het verzoek HTTP was. Elke link die WordPress genereert gebruikt http://, elke wp_redirect()-aanroep wijst naar http:// en is_ssl() geeft false terug. Combineer dat met FORCE_SSL_ADMIN en je hebt een instant redirect-lus in wp-admin.

De fix is om WordPress het oorspronkelijke schema te laten lezen uit de X-Forwarded-Proto-header die de proxy zet. De WordPress HTTPS admin-gids documenteert dit patroon expliciet:

define( 'FORCE_SSL_ADMIN', true );
if (
    isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] )
    && false !== strpos( $_SERVER['HTTP_X_FORWARDED_PROTO'], 'https' )
) {
    $_SERVER['HTTPS'] = 'on';
}

Plaats dit in wp-config.php boven de regel /* That's all, stop editing! */. De check gebruikt strpos in plaats van een gelijkheids-check omdat de header een door komma's gescheiden lijst kan bevatten (http,https) als meerdere proxies hem hebben gestempeld.

Belangrijke security-kanttekening: doe dit alleen als de origin niet rechtstreeks bereikbaar is vanaf het publieke internet. Accepteert de origin-server HTTP-verzoeken direct (niet alleen vanaf de proxy), dan kan een kwaadwillende client X-Forwarded-Proto: https in zijn verzoek zetten, en WordPress vertrouwt het. Daarmee kan een aanvaller HTTPS-handhaving omzeilen in scenario's waar je dacht dat het aan stond, en bij cookie-gebaseerde authenticatie kan dat session hijacking mogelijk maken. De X-Forwarded-Proto-shim is alleen veilig als één van deze klopt:

  • De origin luistert op een intern IP dat het publieke internet niet kan bereiken.
  • Een firewall blokkeert al het inkomende verkeer naar de origin behalve vanaf de bekende IP-ranges van de proxy.
  • De proxy is de enige listener op de poort van de origin, en de origin heeft geen eigen publieke DNS-record.

Is je origin direct over HTTP bereikbaar, voeg de shim dan niet toe. Repareer eerst de netwerktopologie: zet de origin achter een privé-netwerk of een firewall, en voeg dan pas de shim toe. De shim toevoegen op een publiek bereikbare origin creëert een header-spoofing kwetsbaarheid die erger is dan de redirect-lus die je probeerde te fixen.

AWS-specifiek: CloudFront gebruikt een andere headernaam. AWS CloudFront geeft X-Forwarded-Proto niet op dezelfde manier door; het zet Cloudfront-Forwarded-Proto. De PHP-variabelenaam wordt dan $_SERVER['HTTP_CLOUDFRONT_FORWARDED_PROTO']. Gebruik alleen de header die je daadwerkelijke infrastructuur uitstuurt. AWS Application Load Balancer (ALB) en Elastic Load Balancer (ELB) gebruiken wél de standaard X-Forwarded-Proto-header.

Verificatie. Met de shim op zijn plek herlaad je wp-admin in een nieuw incognito-venster. Het loginscherm hoort in één enkel verzoek te verschijnen. Inspecteer de paginabron: <link rel="canonical"> moet met https:// beginnen. Controleer dan de waarde van is_ssl() vanuit de admin:

wp eval 'echo is_ssl() ? "true" : "false";'

Verwachte output.

true

Geeft het nog steeds false terug, dan wordt de shim niet uitgevoerd voordat WordPress het schema leest. Zorg dat de shim boven de regel require_once ABSPATH . 'wp-settings.php'; in wp-config.php staat, niet eronder.

Wanneer je hulp moet vragen

Heb je de juiste methode voor je stack toegepast en laadt de site nog steeds over HTTP, of blijft de lus bestaan na het Cloudflare- en reverse proxy-deel, verzamel dan dit voordat je je host of een WordPress-engineer aanspreekt:

  • Het exacte symptoom: welke URL faalt, in welke browser, met welke foutmelding.
  • De output van curl -sI http://yoursite.nl/ en curl -sI https://yoursite.nl/ vanaf een andere machine.
  • De Server:-header uit die requests, zodat je weet welke webserver er daadwerkelijk antwoord geeft.
  • De redirect-keten uit DevTools (elke Location-header op volgorde, letterlijk gekopieerd).
  • Je Cloudflare SSL/TLS-modus als Cloudflare in het pad zit.
  • De inhoud van .htaccess (Apache) of je nginx server block.
  • De definities van WP_HOME, WP_SITEURL en FORCE_SSL_ADMIN uit wp-config.php, met database-gegevens weggehaald.
  • De output van wp option get siteurl en wp option get home.
  • Of je WordPress-versie 5.7 of nieuwer is en of de Site Health één-klik HTTPS knop verscheen.

Een site die HTTPS niet kan afdwingen heeft bijna altijd een van bovenstaande patronen als wortel. De escalatielijst maakt van "het werkt niet" een diagnose-gesprek dat in minuten wordt opgelost in plaats van uren.

Hoe houd je HTTPS werkend na een migratie

Migraties zijn waar HTTPS-configuraties stuk gaan. Domeinwisselingen, hostverhuizingen en certificaatverlengingen raken telkens één van de vier lagen en vrijwel nooit alle vier in dezelfde stap. Een korte pre-migratie checklist scheelt veel debug-werk:

  • Schrijf de vier waarden op die ertoe doen voor je begint: je WP_HOME- en WP_SITEURL-instelling (constant of database), je Cloudflare SSL-modus als die van toepassing is, je .htaccess of nginx-redirect, en of FORCE_SSL_ADMIN aan staat.
  • Draai de database search-replace voor het nieuwe domein op de nieuwe host, met WP-CLI of Better Search Replace zoals beschreven in het mixed content artikel. Sla de guid-kolom over.
  • Test de redirect-keten met curl -sI voordat je DNS naar de nieuwe host wijst. De nieuwe server hoort één enkele 301 van HTTP naar HTTPS terug te geven, en daarna een 200 op HTTPS.
  • Gebruik vanaf dag één Full (Strict) op Cloudflare. Begin niet "even voor de test" in Flexible en vergeet hem dan op te waarderen.
  • Kies één plek om HTTPS af te dwingen en zet het overal anders uit. Doet je .htaccess of nginx server block de redirect, zet dan niet ook nog eens een "Force HTTPS"-toggle aan in een SEO- of SSL-plugin. Twee lagen handhaving is de meest voorkomende oorzaak van redirect-lussen na een migratie.

WordPress onderhoud zonder omkijken?

Ik regel updates, backups en beveiliging, en houd performance strak—zodat storingen en traagheid niet terugkomen.

Bekijk WordPress onderhoud

Doorzoek deze site

Begin met typen om te zoeken, of blader door de kennisbank en blog.