Ajouter la GeoIP à Nginx Proxy Manager

Ajouter la GeoIP à Nginx Proxy Manager

Historique des versions

Version Date Commentaires
1 Octobre 2023 Version initiale
2 Août 2025 Révision pour suivi de la compatibilité suite à la mise à jour de NPM.

En complément de la mise en place de Nginx Proxy Manager pour gérer vos redirections de sous-domaines vers les services que vous hébergez, nous allons voir comment ajouter les informations GeoIP à NPM, nous permettant de bloquer les visiteurs venant de certains pays et/ou de loguer la provenance de ces visiteurs.

Ouvrir vos services vers Internet avec Nginx Proxy Manager ou Synology DSM
On vous montre sur ce blog tout un tas de services à héberger chez vous ou sur un serveur dans le cloud, et vous pouvez y accéder quand vous êtes sur votre réseau local. Mais comment faire pour les rendre disponibles quand vous êtes en déplacement ou n’y êtes simplement

La GeoIP est une technique permettant de localiser un utilisateur en se basant sur son adresse IP. Pour cela, nous nous appuierons sur des bases de données que Maxmind met à disposition gratuitement : GeoLite2. Ces bases gratuites sont moins précises que leurs versions payantes, mais seront largement suffisantes pour notre utilisation.

NPM à l'origine n'intégrait pas les modules nécessaires dans l'image officielle, il fallait donc mettre les mains dans le cambouis pour compiler et intégrer ces modules. Ce qui avait donné lieu à un tuto en 2 parties sur le blog :

Ajouter la GeoIP à Nginx Proxy Manager 1/2
En complément de la mise en place de Nginx Proxy Manager pour gérer vos redirections de sous-domaines vers les services que vous hébergez, nous allons voir comment ajouter les informations GeoIP à NPM, nous permettant de bloquer les visiteurs venant de certains pays et/ou de loguer la provenance de

Mais depuis quelques versions, ces modules sont intégrés à l'image, ce qui simplifie énormément la configuration et l'utilisation de la GeoIP avec NPM. Voici donc le tutoriel remanié et fonctionnant avec la dernière version de NPM (2.12 à l'écriture de l'article).


Prérequis

Pour cet article, nous allons partir d'un fichier docker-compose.yml standard pour NPM :

version: '3.9'
services:
  nginx-proxym:
    container_name: nginx-proxym
    image: jc21/nginx-proxy-manager:latest
    restart: always
    volumes:
      - /dockers/nginx-proxym/data:/data
      - /dockers/nginx-proxym/letsencrypt:/etc/letsencrypt
    ports:
      - 80:80
      - 443:443
      - 81:81
    environment:
      TZ: "Europe/PARIS"
      DB_SQLITE_FILE: "/data/database.sqlite"

Pour les volumes, j'ai opté pour un chemin absolu afin d'être plus clair dans les chemins utilisés, à vous d'adapter en fonction de votre configuration et de vos habitudes.

Vous noterez que le fichier utilise une base SQLite au lieu de MariaDB, c'est juste pour simplifier, tout ce que nous allons faire est indépendant de la base de donnée utilisée et ne remet pas en cause votre installation.

Chargement des modules

Pour charger les modules GeoIP dans NPM, il suffit de créer un fichier root_top.conf dans le dossier prévu par NPM pour les configurations avancées, à savoir /dockers/nginx-proxym/data/nginx/custom.

load_module /usr/lib/nginx/modules/ngx_http_geoip2_module.so;
load_module /usr/lib/nginx/modules/ngx_stream_geoip2_module.so;

root_top.conf

Puis on recharge la configuration de nginx : docker exec -it nginx-proxym nginx -s reload


Téléchargement et mise à jour des bases GeoLite

Pour obtenir les bases Geoip2 gratuites de Maxmind, il faut d'abord s'inscrire sur leur site. Ça se passe là : https://www.maxmind.com/en/geolite2/signup.
Créez votre compte et une fois celui-ci validé, vous pouvez vous connecter afin de générer une clé de licence qui servira par la suite : https://www.maxmind.com/en/accounts/current/license-key.

Attention ! Notez bien l'Account ID et la Licence Key (celle-ci ne sera plus visible par la suite).

Afin de mettre à jour régulièrement les bases geoip, Maxmind propose une image docker très simple à utiliser. Il suffit de lui monter comme volume le dossier où l'on veut nos bases et de renseigner avec des variables d'environnement les informations de notre clé de licence.

On créé un nouveau répertoire geoip2 pour stocker nos bases dans le dossier data de NPM : /dockers/nginx-proxym/data/geoip2.
Et voici la partie service que l'on peut rajouter au fichier docker-compose de NPM :

  geoip-upd:
    container_name: geoip-upd
    image: maxmindinc/geoipupdate:latest
    restart: unless-stopped
    volumes:
      - /dockers/nginx-proxym/data/geoip2:/usr/share/GeoIP
    environment:
      TZ: "Europe/PARIS"
      GEOIPUPDATE_ACCOUNT_ID: XXXXXX
      GEOIPUPDATE_LICENSE_KEY: "XXXXXXXXXXXXXXXXX"
      GEOIPUPDATE_EDITION_IDS: "GeoLite2-City GeoLite2-Country GeoLite2-ASN"    # Bases à télécharger
      GEOIPUPDATE_FREQUENCY: 12                # Màj toutes les 12h
      GEOIPUPDATE_PRESERVE_FILE_TIMES: 1       # Conserver la date originale de création des fichiers.

docker-compose.yml

Il est possible de ne télécharger qu'une base suivant ce que l'on compte en faire :

  • GeoLite2-ASN : Informations sur l'ISP à qui appartient l'IP.
  • GeoLite2-Country : Geolocalisation de l'IP au niveau pays.
  • GeoLite2-City : Geolocalisation de l'IP au niveau ville. (Inclue le niveau pays)

Une fois le conteneur lancé, on retrouve nos fichiers de base de données dans le répertoire /dockers/nginx-proxym/data/geoip2.

/dockers/nginx-proxym/data/geoip2#  ls -l
total 86220
-rw-r--r-- 1 root root  7541424 déc.  10 00:57 GeoLite2-ASN.mmdb
-rw-r--r-- 1 root root 74871506 déc.  10 00:57 GeoLite2-City.mmdb
-rw-r--r-- 1 root root  5862627 déc.  10 00:57 GeoLite2-Country.mmdb

Voici notre fichier docker-compose.yml final pour la stack NPM + GeoIP :

version: '3.9'
services:
  nginx-proxym:
    container_name: nginx-proxym
    image: jc21/nginx-proxy-manager:latest
    restart: always
    volumes:
      - /dockers/nginx-proxym/data:/data
      - /dockers/nginx-proxym/letsencrypt:/etc/letsencrypt
    ports:
      - 80:80
      - 443:443
      - 81:81
    environment:
      TZ: "Europe/PARIS"
      DB_SQLITE_FILE: "/data/database.sqlite"
              
  geoip-upd:
    container_name: geoip-upd
    image: maxmindinc/geoipupdate:latest
    restart: unless-stopped
    volumes:
      - /dockers/nginx-proxym/data/geoip2:/usr/share/GeoIP
    environment:
      TZ: "Europe/PARIS"
      GEOIPUPDATE_ACCOUNT_ID: XXXXXX
      GEOIPUPDATE_LICENSE_KEY: "XXXXXXXXXXXXXXXXX"
      GEOIPUPDATE_EDITION_IDS: "GeoLite2-City GeoLite2-Country GeoLite2-ASN"
      GEOIPUPDATE_FREQUENCY: 12
      GEOIPUPDATE_PRESERVE_FILE_TIMES: 1

Nous pouvons maintenant configurer NPM pour utiliser tout ça, afin de bloquer et/ou loguer en se servant des informations GeoIP. Pour cela, nous allons ajouter des fichiers de configuration "custom".


Utilisation de la base de données

Pour charger la base de donnée voulue et définir des variables contenant les informations qui nous intéressent, nous allons créer un fichier http_top.conf dans le dossier /dockers/nginx-proxym/data/nginx/custom.

charset utf-8;
geoip2 /data/geoip2/GeoLite2-City.mmdb {
	auto_reload 3h;
	$geoip2_metadata_country_build metadata build_epoch;
	$geoip2_data_country_code default=XX source=$remote_addr country iso_code;
	$geoip2_data_country_name default=- country names fr;
	$geoip2_data_city_name default=- city names fr;
	$geoip2_data_region_name default=- subdivisions 0 names fr;
}

http_top.conf

Cette configuration va permettre de charger le fichier GeoLite2-City.mmdb précédemment téléchargé et d'extraire dans des variables le code pays, le nom du pays, le nom de la ville et le nom de la région en français.
Pour ne pas avoir de problèmes avec les noms accentués, on définit le charset en UTF8.


Définition des IPs à bloquer suivant la provenance

Pour bloquer les IPs en provenance de certains pays, vous pouvez opter pour deux approches :

  • Bloquer tous les pays et n'en autoriser que certains, en ajoutant les lignes suivantes au fichier http_top.conf :
geo $allowed_ip {
	default no;             # On interdit par défaut
	192.168.1.0/24 yes;     # On autorise le réseau local
}

map $geoip2_data_country_code $allowed_country {
	default $allowed_ip;
	FR yes;                 # On autorise les IP Française
	BE yes;                 # On autorise les IP Belges
}
  • Autoriser tous les pays et ne bloquer que certains, en ajoutant les lignes suivantes au fichier http_top.conf :
geo $allowed_ip {
		default yes;             # On autorise par défaut
		192.168.1.0/24 yes;      # On autorise le réseau local
}

map $geoip2_data_country_code $allowed_country {
		default $allowed_ip;
		CN no;                 # On interdit les IP Chinoises
		RU no;                 # On interdit les IP Russes
}
Info ! Pour trouver le code pays sur deux lettres (ISO-3166-1), vous pouvez utiliser cette liste : https://en.wikipedia.org/wiki/ISO_3166-1#Officially_assigned_code_elements

Mise en place du blocage

Une fois que nous avons défini ce qu'on veut bloquer/autoriser, il ne reste plus qu'à le rendre effectif.
Il faut pour cela ajouter ces lignes dans un fichier de configuration :

if ($allowed_country = no) {
	return 444;
}

Le fichier dans lequel ajouter ces lignes dépend du niveau où l'on veut effectuer le blocage :

  • Blocage Général : Il faut créer un fichier server_proxy.conf avec ce contenu dans le dossier /dockers/nginx-proxym/data/nginx/custom
  • Blocage au niveau de chaque Proxy Host : Il faut ajouter ce contenu dans la configuration avancée (Custom Nginx Configuration) de chaque hôte (Interface web de NPM).
Info ! En définissant plusieurs listes $allowed_ip et $allowed_country, il est possible d'avoir des blocages différents suivant les Proxy Hosts.

Création de logs avec les infos GeoIP

Pour l'instant, il n'est pas possible dans NPM de modifier le format de log par défaut, nous allons donc devoir créer un autre fichier de log contenant les infos GeoIP en plus.
Pour cela, ajoutons un nouveau format de log dans le fichier http_top.conf :

log_format proxy_geo escape=json '[$time_local] [Client $remote_addr] [$allowed_country $geoip2_data_country_code $geoip2_data_country_name $geoip2_data_region_name $geoip2_data_city_name] "$http_user_agent" '
                                 '$upstream_cache_status $upstream_status $status - $request_method $scheme $host "$request_uri" [Length $body_bytes_sent] [Gzip $gzip_ratio] [Sent-to $server] "$http_referer"';

Les informations loguées par NPM sont les même que celles par défaut, on y a juste ajouté les infos GeoIP : [$allowed_country $geoip2_data_country_code $geoip2_data_country_name $geoip2_data_region_name $geoip2_data_city_name], à savoir, si la requête est autorisée ou non, le code pays sur deux lettres, le nom du pays, le nom de la région et le nom de la ville.

Puis ajoutons dans la configuration avancée (Custom Nginx Configuration) de chaque hôte (Interface web de NPM), le code suivant qui génèrera le fichier de log au bon format à chaque requête sur cet hôte :

access_log /data/logs/proxy-host-%HOSTID%_access-geo.log proxy_geo;

En remplaçant %HOSTID% par l'id du proxy host que vous êtes en train de modifier.

On recharge la configuration de nginx avec la commande docker exec -it nginx-proxym nginx -s reload.

Et voilà, il n'y a plus qu'à tester la connexion aux hôtes avec un vpn, pour venir de différents pays/villes et voir si le blocage éventuel est bien effectif.

Vous pouvez voir le nouveau fichier de log en direct en utilisant la commande tail -f /dockers/nginx-proxym/data/logs/proxy-host-%HOSTID%_access-geo.log.

Exemples :

/dockers/nginx-proxym/data/logs# tail -f proxy-host-1_access-geo.log
[15/Dec/2021:14:24:58 +0000] [Client 192.168.1.51] [yes XX - - -] "Uptime-Kuma/1.11.1"  200 200 - GET https mon-hote.tld "/login" [Length 9708] [Gzip ] [Sent-to 192.168.1.69] ""
[15/Dec/2021:14:27:01 +0000] [Client 185.189.113.45] [yes FR France Île-de-France Paris] "Mozilla/5.0 (Linux; Android 10; CLT-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Mobile Safari/537.36"  302 302 - GET https mon-hote.tld "/" [Length 0] [Gzip ] [Sent-to 192.168.1.69] ""
[15/Dec/2021:14:27:47 +0000] [Client 89.40.182.9] [no IT Italie Lombardie Milan] "Mozilla/5.0 (Linux; Android 10; CLT-L29) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Mobile Safari/537.36"   444 - GET https mon-hote.tld "/login" [Length 0] [Gzip ] [Sent-to 192.168.1.69] ""

La première ligne est une connexion provenant du réseau local, la deuxième provenant d'un serveur vpn à Paris, la troisième provenant d'un serveur vpn à Milan. On voit bien que les deux premières ont été acceptées et la troisième rejetée.


Conclusion

Le log de ces informations peut servir à faire des statistiques sur la provenance de vos visiteurs. Nous verrons dans un autre article comment exploiter ces informations. Quand au blocage par pays, il peut aider à sécuriser vos services web en bloquant les connexions venant de pays reconnus comme origine d'un gros pourcentage des attaques mondiales.

J'espère que cet article vous permettra de mettre en place de manière effective la GeoIP sur votre Nginx Proxy Manager.

Si vous avez des questions ou simplement souhaitez échanger avec nous, n'hésitez pas à laisser des commentaires ou à venir sur notre groupe Telegram.