Configuration du réseau sur une seule IP publique

Remarque préalable : ce qui est décrit ici fonctionne sur de l’auto-hébergement. Il peut y avoir des paramétrages spécifiques pour faire cette opération chez un hébergeur type OVH ou online.

Nous avons une seule IP publique et pourtant, il nous faut servir différentes applications dans différents containers. Comment faire ? Et bien une fois n’est pas coutume, on va suivre la doc.

Le principe de base est qu’on va déclarer sur la carte réseau physique un pont, noté vmbr , d’adresse 192.168.100.254, qui va agir comme un switch. Tous les containers seront sur un même réseau local 192.168.100.X relié par ce switch. Ensuite on va utiliser le principe du NAT pour servir les différents containers en fonction du port demandé.

Tout se passe en terme de configuration dans le fichier du serveur proxmox /etc/network/interfaces. Voici ma configuration avec la description par bloc :

# cette partie est ecrit à l'installation de proxmox
auto lo
iface lo inet loopback
# a partir de là, on commence les modifcations. Le mot clé 'manual' remplace 'auto'
iface eth0 inet manual

# on définit la première inteface réseau qui est celle utilisé par l'OS de proxmox
auto vmbr0
iface vmbr0 inet static
	address  192.168.37.201
	netmask  255.255.255.0
	gateway  192.168.37.1
	bridge_ports eth0
	bridge_stp off
	bridge_fd 0

# on va ensuite définir notre fameux pont=switch qui route tous les flux en maquerading
auto vmbr1
iface vmbr1 inet static
	address  192.168.100.254
	netmask  255.255.255.0
	bridge_ports none
	bridge_stp off
	bridge_fd 0
	post-up echo 1 > /proc/sys/net/ipv4/ip_forward
	post-up iptables -t nat -A POSTROUTING -s '192.168.100.0/24' -o vmbr0 -j MASQUERADE
	post-down iptables -t nat -D POSTROUTING -s '192.168.100.0/24' -o vmbr0 -j MASQUERADE

# Maintenant, on va écrire nos règles de NAT pour diriger nos applications, ici une pour postgresql et l'autre pour un accès SSH sur le meme container
	# CT postgresql
	post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 5432 -j DNAT --to 192.168.100.1:5432
	post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 5432 -j DNAT --to 192.168.100.1:5432
	post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 221 -j DNAT --to 192.168.100.1:22
	post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 221 -j DNAT --to 192.168.100.1:22

# La on va servir l'application redmine d'un autre container, gérant https/http/ssh
	# CT redmine
	post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 4432 -j DNAT --to 192.168.100.2:443
	post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 4432 -j DNAT --to 192.168.100.2:443
	post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 802 -j DNAT --to 192.168.100.2:80
	post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 802 -j DNAT --to 192.168.100.2:80
	post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 222 -j DNAT --to 192.168.100.2:22
	post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 222 -j DNAT --to 192.168.100.2:22

# Le site internet du Cen sur ce container, NAT pour https/http/ssh/mysql adminer
        post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 4437 -j DNAT --to 192.168.100.7:443 
        post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 4437 -j DNAT --to 192.168.100.7:443 
        post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 807 -j DNAT --to 192.168.100.7:80 
        post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 807 -j DNAT --to 192.168.100.7:80 
        post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 227 -j DNAT --to 192.168.100.7:22 
        post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 227 -j DNAT --to 192.168.100.7:22 
        post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 12327 -j DNAT --to 192.168.100.7:12322 
        post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 12327 -j DNAT --to 192.168.100.7:12322 

# Le site du projet ligero sur ce container, NAT pour https/http/ssh/msql adminer
        post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 4439 -j DNAT --to 192.168.100.9:443 
        post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 4439 -j DNAT --to 192.168.100.9:443 
        post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 809 -j DNAT --to 192.168.100.9:80 
        post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 809 -j DNAT --to 192.168.100.9:80 
        post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 229 -j DNAT --to 192.168.100.9:22 
        post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 229 -j DNAT --to 192.168.100.9:22 
        post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 12329 -j DNAT --to 192.168.100.9:12322 
        post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 12329 -j DNAT --to 192.168.100.9:12322 

Pour que ces réglages fonctionnent, il faut bien entendu configurer les containers de façon adéquate :

  • définir le pont réseau à vmbr1,
  • indiquer adresse IPv4 à statique,
  • définir l’adresse IP sous la forme 192.168.100.X/24 (attention, bien ajouter le ’/24’ ),
  • définir la passerelle à 192.168.100.254
    Dans la capture suivante, voici la config du container servant le projet Ligero :
    Conf LAN container
    Ludovic Lestrat

Important : la prise en compte de la configuration de /etc/network/interfaces devrait se faire en relançant simplement le service network (/etc/init.de/network restart). Chez moi, çà ne suffit pas et il faut rebooter le serveur proxmox pour prise en compte des modifications

Autre source d’information sur le sujet :

Néanmoins cette configuration pose un soucis si l’on héberge sur le même port d’écoute la même application sur plusieurs containers . On va être obligé de multiplier les ports de NAT pour une même application, ce qui n’est pas forcément élégant et pratique en fonction du type d’application.
Heureusement, pour servir plusieurs sites web, il y a une solution plus élégante, c’est la gestion multi-site.

Gestion multi-sites web

Le principe utilisé ici est le suivant :

  • on envoie toutes les requêtes sur le port 80 sur un seul container,
  • ce container fait tourner le serveur web Nginx qui va travailler en mode reverse-proxy,
  • le serveur nginx va directement fournir les données immuables (ex : images) pour lesquelles il va faire du cache et transmettre aux serveurs web apache des différents containers cibles ce qui bouge (ex : code php).
  • pour que tout ceci fonctionne de l’extérieur, on paramètre le parefeu devant le serveur proxmox en DNAT du port 80 vers l’IP du serveur proxmox (192.168.37.201 dans notre exemple).

Pour cela :

  • créer un container avec le template de nginx,
  • on va déclarer ce container sur l’IP 192.168.100.6
  • configuration du fichier nginx.conf comme suit
    user www-data;
    worker_processes 4;
    pid /run/nginx.pid;
    error_log /var/log/nginx/error.log;
    events {
            worker_connections 1024;
            use epoll;
            # multi_accept on; }
    http {
            # Basic Settings
            sendfile on;
            tcp_nopush on;
            tcp_nodelay on;
            keepalive_timeout 65;
            types_hash_max_size 2048;
            server_tokens off;
            server_names_hash_bucket_size 64;
            # server_name_in_redirect off;
            include /etc/nginx/mime.types;
            default_type application/octet-stream;
            # SSL Settings
            ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
            ssl_prefer_server_ciphers on;
            # Logging Settings
            access_log /var/log/nginx/access.log;
            #error_log /var/log/nginx/error.log;
            # Gzip Settings
            gzip on;
            #gzip_disable "msie6";
            gzip_disable "MSIE [1-6]\.(?!.*SV1)";
            gzip_vary on;
            gzip_proxied any;
            gzip_comp_level 6;
            gzip_min_length 1400;
            # gzip_buffers 16 8k;
            gzip_http_version 1.1;
            gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
            # Definir une zone de cache appeller "STATIC de 1Go Max"
            proxy_cache_path /var/cache/nginx levels=2:2:2 keys_zone=STATIC:1000m inactive=24h max_size=1g;
            proxy_temp_path /var/lib/nginx/proxy;
            # Virtual Host Configs
            include /etc/nginx/conf.d/*.conf;
            include /etc/nginx/sites-enabled/*;
    }
  • Fichier pour le proxy simple : /etc/nginx/proxy.conf
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_hide_header X-Powered-By;
    proxy_set_header Server "";
  • Fichier pour le proxy avec cache : /etc/nginx/proxy-cache.conf
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_hide_header X-Powered-By;
     # Clear a few headers we might not want to pass on
    proxy_set_header Accept "";
    proxy_set_header Connection "";
    proxy_set_header Server "";
     # Enable caching for the proxied requests using the STATIC storage
    # Cache 200 (OK), as well as 301 and 302 (redirect) responses for 30m
    proxy_cache STATIC;
    proxy_cache_valid 200 301 302 30m;
     proxy_connect_timeout 90;
    proxy_send_timeout 90;
    proxy_read_timeout 90;
    # Allow using stale data (cached data that has expired) in the following cases:
    # - an error has occurred while connecting to the server, sending a request to it, or reading its response
    # - timeout occurred during the connection with the server, transfer the request or while reading response from the server
    # - server returned a empty or incorrect answer
    # - server returned an error status (500, 502-504)
    proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 htt
  • on va maintenant déclarer nos sites dans /etc/nginx/sites-available. On va commencer par le site internet du cen dans un fichier /etc/nginx/sites-available/internet :
    server {
        listen 0.0.0.0:80;
        server_name internet.local www.mondomaine.org;
        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;
    	location / {
    	include proxy.conf;
    	proxy_pass http://192.168.100.7/;}
    }

    On utilise le nom du domaine pour déterminer la cible, qui est l’ip locale du container hébergeant le site internet (cf première partie de l’article). On peut mettre plusieurs domaines, comme c’est le cas ici ou on en profite pour gérer un accès local à ce serveur (internet.local)
    On va activer cette configuration :

  • création d’un lien dans site_enabled
    ln -s /etc/nginx/sites-available/internet /etc/nginx/sites-enabled/internet
  • recharge de la configuration de nginx :
    /etc/init.d/nginx reload
  • sur le container ’inernet’ d’IP 192.168.100.7 ou tourne le serveur apache, on trouve la configuration de site par défaut suivante, dans le fichier /etc/apache2/sites-available/000-default.conf :
    ServerName localhost
    <VirtualHost *:80>
            ServerAdmin webmaster@localhost
            DocumentRoot /var/www/html_public
            Options Indexes FollowSymLinks MultiViews
    </VirtualHost>
    <VirtualHost *:443>
            SSLEngine on
            ServerAdmin webmaster@localhost
            DocumentRoot /var/www/html_public
    </VirtualHost>
    ScriptAlias /cgi-bin/ /var/www/cgi-bin/
    <Directory /var/www/html_public>
            Options Indexes FollowSymLinks MultiViews
            Require all granted
            AllowOverride all
    </Directory>

    A noter qu’on pourrait très bien gérer ici des virtualhost par domaine name, si ces derniers sont déclarés au préalable dans le fichier /etc/nginx/sites-enabled/internet

Autre exemple de configuration avec l’application redmine, on crée le fichier /etc/nginx/sites-enabled/redmine suivant :

server {
    listen 0.0.0.0:80;
    server_name redmine.local redmine.mondomaine.org;
    access_log /var/log/nginx/redmine_access.log;
    error_log /var/log/nginx/redmine_error.log;
	location / {
	include proxy.conf;
	proxy_pass http://192.168.100.2/;}
}
  • ne pas oublier la déclaration du container nginx dans le fichier de configuration du reseau de proxmox /etc/networw/interfaces, ajouter donc :
            # CT nginx
            post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 443 -j DNAT --to 192.168.100.6:443
            post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 443 -j DNAT --to 192.168.100.6:443
            post-up iptables -t nat -A PREROUTING -i vmbr0 -p tcp --dport 80 -j DNAT --to 192.168.100.6:80
            post-down iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 80 -j DNAT --to 192.168.100.6:80

    On indique ici que tout ce qui arrive sur les ports 80(http) et 443(https) est envoyé vers le container nginx.

Sur le sujet :