GERBELOTBARILLON.COM

Parce qu'il faut toujours un commencement...

Utiliser NGinx comme Reverse Proxy

Le Reverse Proxy

Tout comme son homologue Apache, Nginx est un serveur Web qui peut être utilisé comme Reverse Proxy. Un Reverse Proxy est utilisé comme intermédiaire entre les clients et un ou plusieurs serveurs pour améliorer la sécurité des services exposés sur Internet, améliorer les performances par un usage de mémoire cache et de l'équilibrage de charge.

Imaginez que vous ayez un service qui tourne sur un serveur en écoute du port 9000. Vous ne voulez pas que ce service soit directement exposé sur internet avec tous les problèmes de sécurité existants. Utiliser Nginx comme reverse proxy va lui permettre de récupérer les requêtes provenant des utilisateurs, de les transférer au service en écoute sur le port 9000 quelque part sur un serveur protégé et de renvoyer la réponse du servier web au client qui a initié la requête.

Mise en place

Si vous disposez déjà de Nginx fonctionnel vous pouvez sauter cette étape sinon plusieurs solutions sont possibles :

  • Installer nginx sur une machine dédiée
  • Installer Nginx en tant que container Docker
  • Installer Nginx comme container LXC

Nginx sur une machine dédiée

On partira du postulat que Ubuntu version Serveur a été installé sur une machine neuve. Sur cet Ubuntu, nous allons installer nginx par sudo apt install nginx. Par défaut, le firewall UFW (Uncomplicated FireWall) est installé mais inactif sur Ubuntu. Puisque nous sommes (normalement) en train d'utiliser SSH pour gérer le serveur à distance, il ne faut pas que nous fermions nos accès. Faites un sudo ufw allow 22/tcp afin d'autoriser le flux SSH à travers le firewall. Vérifiez le status pour être sûr que c'est bien le cas. Nous pouvons maintenant activer UFW avec sudo ufw enable. Le status obtenu par sudo ufw status nous indique que le firewall logiciel est maintenant activé et nous affiche également les règles en cours. Un petit tour sur le status de nginx nous affiche alors

Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere                  
80/tcp                     ALLOW       Anywhere                  
443                        ALLOW       Anywhere                  
22/tcp (v6)                ALLOW       Anywhere (v6)             
80/tcp (v6)                ALLOW       Anywhere (v6)             
443 (v6)                   ALLOW       Anywhere (v6)
Prenez votre navigateur préféré et pointez vers l'adresse http://<ip-du-serveur-nginx>. Vous devriez obtenir l'affichage de la page par défaut de Nginx.

Puisque nous parlons de serveur web, il nous faut autoriser les ports 80 et 443 à destination de notre serveur nginx par

sudo ufw allow http
sudo ufw allow https

Lorsque Nginx s'installe il créé un utilisateur www-data avec lequel seront réalisées les opérations d'authentification sur les différents services Nginx. C'est cet utilisateur qui est référencé sur la première ligne du fichier /etc/nginx/nginx.conf. Dans ce fichier, nous retrouvons également la notion de worker_processes qui indique le nombre de connexions simultanées supportées par Nginx. La valeur "auto" essaie de détecter le nombre de CPU disponibles pour paramétrer au mieux le comportement de Nginx. Globalement le nombre de connexions simultanées est worker_processes * nombre_de_cpu.

Nginx avec Docker

Pour les services courants, il est aujourd'hui intéressant de passer par les containers Docker pour une mise en place simplifiée. Si vous avez une machine Docker vous pouvez faire simplement :

docker pull nginx
Cela va tirer l'image depuis le Docker Hub et la télécharger sur la machine Docker locale.

Pour exécuter Docker, faire simplement :

docker run -d -p 8080:80 --name nginx_rp nginx
Cette commande se décompose comme suit :
  • docker run : démarrage d'un nouveau container
  • -d : détache le container du shell de lancement de docker pour faire fonctionner le container en tâche de fond
  • -p 8080:80 : mappe le port 8080 entrant depuis le host sur le port 80 sortant vers le container. Ainsi le reverse proxy sera accessible par http://@ip-docker:8080
  • --name nginx_rp : assigne le nom nginx_rp au container, utile pour les prochaines commandes Docker
  • nginx : le nom de l'image Docker qui va servir à créer le container.
Testez votre serveur Nginx en vous connectant sur http://@ip-docker:8080. Pour arrêter le container, faire simplement
docker stop nginx_rp

Pour configurer Nginx en tant que Reverse Proxy, voici un exemple de fichier de configuration :

server {
    listen 80;
    server_name localhost;

    location / {
        proxy_pass http://@ip-service-web:9000;
        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;
    }
}
Les éléments du fichier de configuration sont les suivants :
  • server { ... } marque le début du block de configuration. Il est entouré d'accolades {}
  • listen représente le port sur lequel Nginx se met en écoute localement
  • server_name représente le nom attendu et sur lequel les requêtes seront faites. C'est le nom qui va être dans la variable $host
  • location / { ... } signifie que les requêtes seront traitées si elles arrivent sur la racine du serveur (/)
  • proxy_pass http://@ip-service-web:9000 redirige les requêtes vers le serveur backend situé sur @ip-service-web, sur le port 9000
  • les lignes proxy_set_header permettent de passer des entêtes additionnels au serveur backend avec l'hôte, l'IP réelle ($remote_addr) le champ X-Forwarded-For ainsi que le protocole utilié ($scheme)

Maintenant que la configuration existe, il faut la fournir à Nginx qui, je vous le rappelle, est un container Docker donc une zone sur laquelle nous n'avons que peu de moyens d'action. Pour cela on va ajouter un champ à la ligne d'appel de lancement du container Docker :

docker run -d -p 8080:80 --name nginx_rp -v /path/to/local/nginx.conf:/etc/nginx/nginx.conf:ro nginx
Remplacez le chemin /path/to/local/nginx.conf par le chemin dans lequel vous avez mis en place le fichier de configuration localement. Il sera mappé sur le fichier situé après les ':' à savoir /etc/nginx/nginx.conf.

Pour connaître le chemin, interroge celui qui en vient.

Proverbe Chinois

Nginx Proxy Manager


Un des avantages certains des containers sur les VMs est que le container va démarrer beaucoup plus vite qu'une VM. Par exemple, pour installer docker simplement il suffirait (exemple tiré de Nginx Proxy Manager):

  1. de créer un conteneur type Ubuntu ou Debian
  2. sur le shell de ce nouveau conteneur, taper curl -sSL https://get.docker.com/ | sh pour récupérer le script d'installation de docker et de procéder à son installation automatiquement
  3. de créer une stack pour nginx proxy manager par exemple (pour rappel, créer un dossier pour la stack par mkdir -p ~/docker/npm) puis faire un cd ~/docker/npm. Créer ensuite un fichier docker-compose.yml
  4. version: '3.8'
    services:
      app:
        image: 'jc21/nginx-proxy-manager:latest'
        restart: unless-stopped
        ports:
          # These ports are in format <host-port>:<container-port>
          - '80:80' # Public HTTP Port
          - '443:443' # Public HTTPS Port
          - '81:81' # Admin Web Port
          # Add any other Stream port you want to expose
          # - '21:21' # FTP
    
        # Uncomment the next line if you uncomment anything in the section
        # environment:
          # Uncomment this if you want to change the location of
          # the SQLite DB file within the container
          # DB_SQLITE_FILE: "/data/database.sqlite"
    
          # Uncomment this if IPv6 is not enabled on your host
          # DISABLE_IPV6: 'true'
    
        volumes:
          - ./data:/data
          - ./letsencrypt:/etc/letsencrypt
  5. Exécuter ensuite la commande docker compose up -d qui va lire le fichier docker-compose.yml précédemment créé.

Maintenant il reste à routeur sur le firewall les ports 80 et 443 pour permettre l'accès depuis l'extérieur et permettre la mise en place de certificats Let's encrypt.. Sur pfSense, le port forwarding consiste en les règles suivantes :

Interface Protocol Source Address Source Ports Dest. Address Dest. Ports NAT IP NAT Ports Description
WANTCP**WAN address80 (HTTP) 192.168.x.y80nginx proxy manager WANTCP**WAN address443 (HTTPS) 192.168.x.y80nginx proxy manager

Se connecter à nginx sur le port 81 et saisir le mot de passe par défaut changeme. Changez-le à la première connexion pour quelque chose de plus solide.

Pour exposer des services le plus simple est de créer une nouvelle entrée dans le DNS du domaine pour le service que vous souhaitez exposer. Un enregistrement A seul ou A + CNAME font l'affaire. Si plusieurs services sont à exposer, utiliser la même IP publique (A) pour toutes les déclarations de services.

Aller sur l'interface principale de nginx proxy manager et cliquer sur Proxy Hosts pour ajouter un nouveau service.

  • Domain Names : spécifier le FQDN du domaine précédemment créé (e.g. proxy.domaine.tld)
  • Scheme : Mettre HTTPS si le service local répond sur https par défaut (comme pfsense, sonicwall ou autre). Pour CEGID ce serait par défaut en http car le SSL n'est pas la norme.
  • Forward Hostname / IP : Adresse IP du service Web dans le LAN
  • Forward Port : Port de communication avec ce service sur le LAN

Sur l'onglet SSL, sélectionner Force SSL et I agree... et faire Save. Le certificat sera automatiquement généré tous les 90 jours depuis le site de Let's Encrypt et affecté au service exposé. Ainsi nous pouvons avoir un certificat légitime pour notre interface Proxmox sans trop de difficultés si nous définissons l'accès à la WebGUI de Proxmox depuis NGinx Proxy Manager...

NGinx Proxy Manager pour gérer les certificats pfSense

Par défaut pfSense est capable de gérer des certificats mais si l'on souhaite utiliser nginx pour accéder à la webgui, il suffit :

  1. de créer un champ DNS pour le serveur pfSense dans domaine DNS voulu
  2. de créer un proxy host dans nginx proxy manager en spécifiant un dialogue https et l'IP LAN du pfSense comme point de redirection
  3. d'ajouter un certificat SSL à cette redirection
  4. de télécharger le certificat depuis l'interface des proxy hosts de nginx
  5. d'ajouter ce certificat dans l'interface globale de pfSense System > Certificates

Nginx Proxy Manager et les streams

Dans le langage Nginx, un stream peut être considéré comme une redirection de ports. Par exemple, si NPM est derrière un firewall et que tous les ports sont redirigés vers NPM, alors le reverse proxy peut se charger de rediriger n'importe lequel des ports vers le serveur mentionné. A la fois TCP et UDP sont pris en charge et ce type de fonctionnement peut permettre de sécuriser des accès comme les FTP par exemple.

Default site

Par défaut lorsqu'une connexion est établie avec la page d'accueil du proxy (son ip), celle-ci consiste en une page de félicitations. Il est important de remplacer cette page par autre chose. C'est le rôle de la page par défaut disponible dans Settings > Default Site. En faisant Edit nous allons pouvoir définir une page 404 ou une page sans réponse, voire une page custom (intéressant pour faire la pub de nos services par exemple).