HAProxy avec Nginx et OpenVPN sur le même port (443)

Introduction

L’objectif de ce tutoriel est de montrer comment configurer un HAProxy pour faire fonctionner Openvpn (un logiciel open-source pour faire un VPN) et Nginx (un load balancer pour les applications web).

Pourquoi avoir besoin de HAProxy ?

le traffic des deux services arrivent sur le même port et j’ai seulement une seule adresse IP public. Il m’est impossible d’avoir une deuxième adresse IP.

donc tout le traffic HTTPS (443) qui va entrer sur mon router va être redirigé vers la VM qui elle va pointer sur HAProxy et qui à son tour va rediriger les paquets au bon service.

example avec un service et plusieurs HTTP avec un endpoint HTTPS

1. Les besoins

  1. Un routeur avec un accès administrateur
    1. vous devez être capable de configurer un Port forwarding
  2. Une machine dans la ‘DMZ’ (c’est plus simple) avec Centos 7
  3. un DNS (un nom de domaine que vous pouvez configurer)
  4. Docker d’installé sur votre Machine DMZ
  5. Une adresse IP statique pour votre machine haproxy.
  6. Une IP statique publique ou un DDNS

2. Installation de HAProxy

Plutôt simple,

sudo yum install haproxy -y

Il se peut que vous ayez besoin de epel-release

yum install epel-release -y

2.1 Configuration de HAProxy

Maintenant la partie intéressante,

2.1.1 Installer certbot et générer un certificat SSL

Il faut en premier lieu installer certbot

yum install certbot -y

Ensuite, il faut s’assurer de plusieurs choses,

  1. Votre DNS pointe sur votre IP externe et tout ca fonctionne
    1. nslookup example.com retourne votre IP publique
    2. Comment connaitre son IP externe : https://www.whatsmyip.org
  2. vous n’avez aucun service qui utilise le port 80 actuellement
    1. netstat -ltn | grep 80
    2. la commande doit rien retourner

Si les deux étapes sont OK !

Vous êtes prêt a faire la demande pour un certificat SSL.

certbot certonly --standalone --preferred-challenges http --http-01-port 80 -d <votre-nom-de-domaine>

Tout devrait bien se dérouler, il se peut que vous ayez des erreurs, habituellement celle-ci pointe bien au problème.

Les fichiers générés devraient se retrouver :

/etc/letsencrypt/live/<votre-nom-de-domaine>/fullchain.pem
/etc/letsencrypt/live/<votre-nom-de-domaine>/privkey.pem

Maintenant il faut mettre ces deux fichiers en un seul

mkdir /opt/<votre-nom-de-domaine>

cat /etc/letsencrypt/live/<votre-nom-de-domaine>/fullchain.pem \
/etc/letsencrypt/live/<votre-nom-de-domaine>/privkey.pem \
| tee /opt/<votre-nom-de-domaine>/certificate.pem

2.1.2 Configuration de HAProxy

voici ma configuration,

nano /etc/haproxy/haproxy.cfg
global
	tune.ssl.default-dh-param 2048
	log /dev/log  local0
  	log /dev/log  local1 notice

defaults
    	log     global
    	mode    http
    	option  httplog
    	option  dontlognull
	timeout connect 5000
	timeout check 5000
	timeout client 30000
	timeout server 30000	

frontend ssl
	mode tcp
	option tcplog
	bind 0.0.0.0:443
	tcp-request inspect-delay 5s
	tcp-request content accept if HTTP
	use_backend main-ssl if { req.ssl_hello_type 1 } 
	default_backend openvpn

frontend main
    bind 0.0.0.0:80
    bind 127.0.0.1:444 ssl crt /opt/<votre-nom-de-domaine>/certificate.pem accept-proxy
    mode http
    option forwardfor
    use_backend webserver_<votre-nom-de-domaine> if { req.hdr(host) -I <votre-nom-de-domaine> }
 
backend main-ssl
	mode tcp
	server main-ssl 127.0.0.1:444 send-proxy

backend webserver_<votre-nom-de-domaine>
    server webserver-localhost 127.0.0.1:8080

backend openvpn  
	mode tcp
	server openvpn-server 192.168.1.2:443

La première partie frontend (ssl) contient la définition du https, donc si la requête est de type HTTP le serveur web prend la requête.
Sinon c’est le serveur openvpn qui va recevoir la requête.

le deuxième frontend (main), contient la définition pour deux choses il écoute sur le port 80 et le port 444.

Le port 80 est simple, le traffic HTTP va directement sur le serveur web (NGINX)

Le port 444, est différent.

Par exemple,

  1. le traffic arrive sur le frontend (ssl) et la requête est de type HTTP
  2. la requête est alors redirigé vers le backend (main-ssl)
  3. notre backend (le serveur NGINX) n’est pas en HTTPS. Il est seulement en HTTP et il écoute sur le port 8080
  4. donc on redirige le traffic de main-ssl vers le frontend (main) sur le port 444, le traffic est donc HTTPS avec SSL
  5. on redirige vers le NGINX qui écoute sur le port 8080

Donc de l’Externe le traffic est en HTTPS et à l’interne il est en HTTP.

le backend (openvpn), celui-ci est différent, le service vpn est installé sur la machine 192.168.1.2 et il écoute sur le port 443, donc on redirige simplement le traffic.

Après avoir mis la configuration,

sudo service haproxy start
sudo service haproxy reload
sudo service haproxy status
sudo systemctl enable haproxy

Vous devriez voir aucune erreur.

J’ai eu des problèmes avec selinux.

3. Installation & configuration de Nginx

J’ai utilisé docker,

docker run -d --name frontend -p 8080:80 -v /var/www/:/usr/share/nginx/html:ro nginx

copiez vos fichiers HTML et autres dans le dossier /var/www

4. Test

À partir de l’extérieur de votre réseau, essayez de vous connecter à votre domaine dans votre navigateur favori.

Puis tentez de vous connecter à votre serveur OpenVPN.

Les deux devraient fonctionner, dans mon cas, je ne peux pas utiliser le DNS pour usage local, je dois utiliser directement les adresses IP.

5. Sources

6. Problèmes rencontrés

SELINUX

Le module de SElinux bloque le démarrage de HAProxy, je vais investiguer ce problème et ajouter plus de détails sous peu, présentement, le workaround est

setenforce 0
service haproxy stop
service haproxy start

DHCP vs STATIC

Vous devez utiliser une adresse IP Statique, sinon votre port forwarding risque de ne pas fonctionner, après une panne électrique, mon adresse IP a changé, …

Laisser un commentaire