Nginx – Redirection http vers https derrière un LB ou Reverse Proxy

Sur le serveur web Nginx, pour faire une redirection de HTTP vers HTTPS, il n’y a rien de bien compliquer : une simple règle de redirection et le tour est joué. Cela donne quelque chose comme :

 

server {
    listen 80;
    server_name xxx;
    return 301 https://$server_name$request_uri;
}
server {
    listen 443;
    ...

Maintenant les choses peuvent se compliquer si votre Nginx est utilisé comme serveur web en écoute uniquement sur le port 80 (HTTP) et que le HTTPS est géré en amont par un Load Balancer ou un Reverse Proxy.

Dans ce cas-là, on est tenté de faire une redirection simple HTTP vers HTTPS

server{
    listen *:80;
    server_name mydomain.com www.mydomain.com; 
    rewrite ^ https://mydomain.com$request_uri? permanent

Problème : Cela va créer une boucle de redirection infinie entre le Load Balancer ou Reverse Proxy et votre serveur Nginx :

(Le LB va renvoyer les connections en HTTP à votre Nginx, qui les renverra en HTTPS au LB, qui les renverra en HTTP à Nginx, …)

 

Pour éviter ce problème, lors de la redirection le LB ou Reverse Proxy va modifier l’entête pour définir X-Forwaded-Proto sur HTTPS.

proxy_set_header X-Forwarded-Proto $scheme;

Cela permettra à Nginx de savoir si la requête provient du protocole HTTPS sur le LB/Reverse Proxy ou non.

 

Il faut donc définir une redirection dans la conf de votre vhost du serveur web Nginx en tenant compte de cette entête :

if ($http_x_forwarded_proto = "http") { 
    rewrite ^/(.*)$ https://mydomain.com/$1 permanent; 
}

Ce qui se traduit simplement par :

Si la requête est arrivée en HTTP sur le LB alors il faut la rediriger en HTTPS (si elle est arrivée en HTTPS alors pas besoin de redirection, on laisse la page demandée s’afficher normalement).

ou si vous préférez faire la vérification dans l’autre sens :

if ($http_x_forwarded_proto != 'https') {
 rewrite ^ https://$host$request_uri? permanent;
 }

 

Et voilà, votre serveur web continue de ne traiter que le port 80 et le protocole HTTPS est forcé sur votre Load Balancer ou Reverse Proxy.

A noté que cette technique fonctionne aussi avec l’ALB d’AWS : testé et approuvé 🙂