Blog d'Olivier Raulin

Un peu de technique ...

Mise en place d'un reverse proxy Nginx

Quand on est geek, il arrive qu’on héberge plusieurs services sur plusieurs ports chez soi … et, malheureusement, on se retrouve confronté à la limite d’une seule adresse IP (hors IPv6, mais c’est un autre sujet :) ), qui est celle que notre fournisseur d’accès nous offre.

C’était clairement un problème jusqu’à ce soir. J’avais mis en place une solution de contournement utilisant un web-proxy … qui était malheureusement assez peu pratique.
En visitant le blog de Victor Héry, je suis tombé sur cet article qui indiquait comment monter un reverse proxy avec Apache. D’ailleurs, son explication de l’utilité du bazar est assez claire, n’hésitez pas à aller le lire.

Du coup, j’ai entrepris de faire la même chose avec Nginx sur mon Raspberry Pi (parce que Apache, c’est trop facile :–) )

Edit 10 mars 2014 : Coquille trouvée par un lecteur concernant l’emplacement du fichier contenant la configuration : il n’était pas situé dans /etc/nginx mais dans /etc/nginx/sites-available/
Il faut également vérifier que le fichier nginx.conf va bien chercher les fichiers dans sites-enabled et faire le lien symbolique qui va bien :)

Nginx ? Proxy ? Reverse ?

Pour expliquer rapidement, Nginx (A prononcer Engine X, j’ai appris ça récemment) est un serveur web, qui a des fonctionnalités de proxy, de reverse proxy, et load balancer, etc.
Il a un gros intérêt, c’est sa très faible consommation en ressources.

Un proxy, globalement, c’est une machine qui va servir d’intermédiaire entre le client (votre ordinateur, par exemple) et un serveur (par exemple, un serveur web)
Généralement, un proxy est utilisé en entreprise en guise de “porte de sortie” vers le web. Quand on ne renseigne pas l’adresse du proxy dans le navigateur, il n’est pas possible d’accéder à Internet.

Le reverse proxy, il fait l’inverse : depuis Internet, accéder à plusieurs (machines|services|sites|…) qui sont dans un réseau local, sans passer par de la translation d’adresse / de ports, qui, bien que pratique, est rapidement limitée quand on a qu’une adresse IP, par exemple.

Pour schématiser rapidement, pour accéder aux différents services que j’ai chez moi, je veux une adresse en trucbidule.mondomaine.fr ou machinchose.mondomaine.fr et pas mondomaine.fr:1337 ou mondomaine.fr:42

La mise en place à proprement parler

La création des sous-domaines

J’ai un domaine qui pointe vers l’adresse IP de chez moi, qui sera, à des fins de confidentialité, modifié dans ce billet. Je prendrai http://chezmoi.exemple.fr comme … exemple.

Je déclare donc dans mes DNS de nouveaux enregistrements : + service1.chezmoi.exemple.fr + service2.chezmoi.exemple.fr

Je les fais pointer en CNAME vers chezmoi.

Jusque là, rien de très compliqué.

L’installation de nginx

Là encore, rien de très compliqué sous Debian …

apt-get install nginx

La configuration de nginx

Le SSL

Devant de plus en plus parano, je désirais forcer l’utilisation de SSL à ce niveau-là, afin d’éviter toute interception éventuelle de mes mots de passe sur des réseaux non sécurisés …
J’ai du suivre ce tutoriel très bien fait, et donc en gros, avec 3 commandes j’étais prêt à activer le SSL sur mes domaines

openssl genrsa -out nginx.key 2048
openssl req -new -key nginx.key -out nginx.csr
openssl x509 -req -days 3650 -in nginx.csr -signkey nginx.key -out nginx.crt

Et voilà, un certificat SSL signé par moi-même, accompagné de sa clé.

Les hôtes virtuels

Ici, les concepts qui entrent en jeu sont un peu plus coriaces …
Pour faire simple, on fait correspondre une configuration à un nom de domaine (service1.chezmoi.exemple.fr par exemple)
On dit à notre nginx que quand le client appelle service1.chezmoi.exemple.fr, il agit de telle manière.

Note : La directive Host est implémentée dans la version 1.1 du protocole HTTP, un client en version 1.0 ne pourra pas accéder à vos hôtes … mais globalement, vous ne devriez pas avoir à vous en soucier, HTTP1.0 n’est plus utilisé depuis un bout de temps.

Je créée donc un fichier /etc/nginx/sites-available/reverse, où je place toutes mes configurations. Les voici, en brut, commentés avec les # :

# On commence par dire où se situent nos certificats SSL
# On aurait pu les mettre séparément dans chaque "server" en ayant besoin.
ssl_certificate /etc/nginx/nginx.crt;
ssl_certificate_key /etc/nginx/nginx.key;

server {
        # Redirection vers HTTPS
        # Ici, je spécifie que toute requête vers le port 80 (HTTP) sera renvoyée vers le même hôte, en HTTPS.
        listen 80;
        return 301 https://$host$request_uri;
}

server {
        # Service 1
        listen 443;
        # J'active SSL
        ssl on;

        server_name service1.chezmoi.exemple.fr; # Ici, c'est le nom de domaine qui sera appelé dans le navigateur
        location / { # pour le dossier racine (/), on active le mode proxy vers l'adresse spécifiée, sur le port spécifié
                proxy_pass http://premieremachine:1081/;
        }
}

server {
        # Service 2
        listen 443;
        ssl on;

        # On peut spécifier 2 noms de domaine différents qui auront le même comportement
        server_name service2.chezmoi.exemple.fr;
        server_name chezmoi.exemple.fr;
        location / {
                proxy_pass https://secondemachine:443/;
        }
}

On relance le service … et ça roule ! On teste dans son navigateur en HTTP, on est bien redirigé vers la même adresse en HTTPS …
On a un avertissement qui dit que le certificat est signé par une autorité non-reconnue (moi :) ), c’est normal, on “accepte les risques” et c’est parti.

Notre serveur nginx fait donc bien son travail de proxy … nous ne savons pas, en tant que client, quelle machine travaille derrière : on sait juste que sur l’URL appelée, le service nous est retourné.

HTTPS de bout en bout ?

Je n’ai eu aucun souci pour proxyfier du HTTPS, pour répondre à Victor :–)
Pour schématiser rapidement : |client|<==SSL==>|proxy|<==SSL==>|serveur|