Геоинформация по IP помогает решать две практические задачи в Nginx: геотаргетинг (выбор языка/каталога/бэкенда по стране) и ограничения (доступ по списку стран, выполнение требований законодательства и договоров с правообладателями). В проде это должно работать предсказуемо, быстро и обновляться без ручных танцев. В статье — как раз о корректной установке, настройке и проверках модуля geoip2
для Nginx.
Что такое geoip2 и чем он отличается от устаревшего geoip
Модуль ngx_http_geoip2_module
работает с базами в формате MMDB (MaxMind DB). Не путайте его со старым ngx_http_geoip_module
, который читал legacy-базы в формате .dat
— они сняты с поддержки, и точность хуже. Переход на geoip2
обязателен, если вам важны актуальные данные, IPv6 и расширенные поля (город, регион, ASN).
Ключевые преимущества geoip2: поддержка MMDB, регулярные обновления MaxMind, IPv6, доступ к детальным полям (страна, регион, город, ASN), возможность подгружать несколько баз одновременно.
Способы установки: готовые пакеты или динамический модуль
В большинстве дистрибутивов geoip2 поставляется как динамический модуль. Вам понадобится библиотека libmaxminddb
и утилиты для работы с базами. Примеры для Debian/Ubuntu и RHEL-совместимых систем:
apt update
apt install nginx libmaxminddb0 libmaxminddb-dev mmdb-bin geoipupdate
dnf install nginx libmaxminddb libmaxminddb-devel geoipupdate
Проверьте, есть ли модуль в поставке Nginx. В ряде репозиториев он уже встроен и доступен через load_module
:
nginx -V
Если видите среди параметров сборки --with-compat
и модуль ngx_http_geoip2_module
предоставлен пакетом, подключите его в nginx.conf
до блока http
:
load_module modules/ngx_http_geoip2_module.so;
Если динамического модуля нет, можно собрать его отдельно из исходников модуля под вашу версию Nginx с флагом совместимости. В проде предпочтительнее репозиторные пакеты, чтобы не усложнять обновления. На общем хостинге модуль может быть недоступен — для гибкой конфигурации удобнее отдельный VDS. Если вы выбираете управляющую панель, будет полезен обзор «панели для VDS: сравнение».
Базы MaxMind: где хранить и как обновлять
Для страны достаточно базы GeoLite2-Country.mmdb
, для города — GeoLite2-City.mmdb
, для автономной системы — GeoLite2-ASN.mmdb
. Обычно их складывают в каталог /usr/share/GeoIP
или /var/lib/GeoIP
.
Утилита geoipupdate
автоматизирует загрузку/обновление. Пример минимальной конфигурации:
# /etc/GeoIP.conf
AccountID 123456
LicenseKey YOUR_LICENSE_KEY
EditionIDs GeoLite2-Country GeoLite2-City
DatabaseDirectory /usr/share/GeoIP
Проверьте вручную и добавьте крон:
geoipupdate
# /etc/cron.d/geoipupdate
0 4 * * * root geoipupdate && systemctl reload nginx
Релоад после обновления нужен, если ваша версия модуля не поддерживает автообновление карт. В новых релизах geoip2
доступна опция автоматической подгрузки без рестарта, но в проде всё равно полезно запланировать регулярный reload
и мониторинг свежести файлов.
Базовая конфигурация geoip2 в Nginx
Подключаем базы в контексте http
и прокладываем переменные. Старайтесь объявлять только те поля, которые реально нужны, чтобы не тратить лишние ресурсы на парсинг:
http {
# Подключаем базы
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
$geoip2_country_code source=$remote_addr country iso_code;
$geoip2_country_name source=$remote_addr country names en;
}
geoip2 /usr/share/GeoIP/GeoLite2-City.mmdb {
$geoip2_city_name source=$remote_addr city names en;
$geoip2_region_code source=$remote_addr subdivisions 0 iso_code;
}
# Пример меток для геотаргетинга
map $geoip2_country_code $is_ru {
default 0;
RU 1;
BY 1;
KZ 1;
}
# Пример списка стран под ограничение
map $geoip2_country_code $blocked_country {
default 0;
CN 1;
KP 1;
}
# Добавим геометку в формат логов
log_format main '$remote_addr $request $status $body_bytes_sent $geoip2_country_code';
access_log /var/log/nginx/access.log main;
server {
listen 80;
server_name example.test;
# Возврат 451, если страна заблокирована политикой
if ($blocked_country) {
return 451;
}
location / {
try_files $uri $uri/ =404;
}
}
}
Поле subdivisions 0
— это первый уровень административного деления (обычно регион/штат). Индексация с нуля. Если нет данных, переменная вернёт пустую строку.
Геотаргетинг: варианты маршрутизации
Самые частые паттерны: включение нужного каталога, выбор апстрима, автоматический редирект на языковую версию. Рекомендуется реализовывать поведение через map
и затем использовать переменные, избегая тяжёлых if
в локациях.
Выбор корня сайта по стране
http {
map $is_ru $doc_root {
1 /var/www/project/ru;
0 /var/www/project/en;
}
server {
listen 80;
root $doc_root;
location / { try_files $uri $uri/ /index.html; }
}
}
Выбор апстрима
http {
upstream app_ru { server 10.10.0.10:8080; }
upstream app_en { server 10.10.0.11:8080; }
map $is_ru $backend {
1 app_ru;
0 app_en;
}
server {
location / { proxy_pass http://$backend; }
}
}
Мягкий редирект на раздел
Для редиректов используйте 302/307, подкрепляя их клиентоориентной логикой на стороне приложения (кука/локаль), чтобы избежать зацикливания и проблем индексации.
server {
location = / {
if ($is_ru) { return 302 /ru/; }
return 302 /en/;
}
}
Если редирект постоянный и осознанный, выбирайте 301, учитывая кэш браузера и поисковиков. Подробности про 301, HSTS и SSL разобраны в материале «перенос домена: 301, HSTS и SSL».
Ограничения по странам: корректно и прозрачно
Если по договору с правообладателем либо по внутренней политике вы обязаны ограничить доступ, возвращайте понятные коды и страницы. Код 451 «Unavailable For Legal Reasons» подходит для юридических ограничений. Для технических ограничений допустим 403.
map $geoip2_country_code $blocked_country {
default 0;
CN 1;
KP 1;
}
server {
if ($blocked_country) {
return 451;
}
error_page 451 /451.html;
location = /451.html { internal; }
}
Не забывайте релевантно отражать ограничения в политике обработки данных и пользовательском соглашении.
Правильный клиентский IP: reverse proxy, CDN и IPv6
Точность geoip напрямую зависит от того, какой IP-адрес видит Nginx. Если перед ним стоит балансировщик или CDN, настройте real_ip_module
и доверяйте только известным подсетям прокси. Никогда не доверяйте всем источникам заголовка X-Forwarded-For
.
http {
real_ip_recursive on;
set_real_ip_from 127.0.0.1;
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 192.168.0.0/16;
set_real_ip_from 2001:db8::/32;
real_ip_header X-Forwarded-For;
# Теперь geoip2 будет получать реальный клиентский адрес
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
$geoip2_country_code source=$remote_addr country iso_code;
}
}
Если вы решите указывать source=$http_x_forwarded_for
прямо в блоке geoip2
, учитывайте: заголовок может содержать список адресов, и парсинг первого IP ляжет на вас. Поэтому надёжнее использовать real_ip_module
, чтобы нормализовать $remote_addr
и затем передавать его в geoip2.
Тестирование конфигурации
Локально удобно эмулировать IP через X-Forwarded-For
, предварительно разрешив доверие к локалу:
# В http добавьте
set_real_ip_from 127.0.0.1;
real_ip_header X-Forwarded-For;
# Проверка ответа и заголовков
curl -H 'X-Forwarded-For: 8.8.8.8' -sS http://127.0.0.1/ -D - | sed -n '1,10p'
Также полезны проверки через mmdblookup
для точечной диагностики базы:
mmdblookup --file /usr/share/GeoIP/GeoLite2-Country.mmdb --ip 8.8.8.8 country iso_code
Логирование и метрики
Добавив переменные geoip2 в log_format
, вы сможете строить отчёты по странам в привычных тулзах веб-аналитики или через парсинг логов. Минимально достаточно $geoip2_country_code
, а при необходимости — город/ASN:
log_format geo '$time_local $remote_addr $status $request $geoip2_country_code $geoip2_city_name';
access_log /var/log/nginx/access.log geo;
Для безопасности избегайте логирования лишних персональных данных и используйте маскирование IP при хранении длительное время.
Производительность и надёжность
- По опыту, один lookup MMDB на запрос занимает микро-миллисекунды; узким местом станет не
geoip2
, а лишняя логика вокруг (многоmap
, регулярки, сложная маршрутизация). - Объявляйте минимум необходимых переменных внутри блоков
geoip2
. - Размещайте
geoip2
вhttp
, а не вserver
/location
— так данные кэшируются на уровне конфигурации и не дублируются. - Обновляйте базы регулярно. Ставьте мониторинг даты модификации MMDB и оповещения.
- Тестируйте и на IPv6: точность может отличаться от IPv4, но современные базы GeoLite2 покрывают v6 хорошо.
Переезжаете на отдельный сервер ради гибких правил? Сохранить аптайм поможет руководство «перенос сайта без простоя».

Юридические и приватностные аспекты
Геоданные по IP относятся к технической информации. Соблюдайте требования локального законодательства о персональных данных и конфиденциальности. Если реализуете ограничения, возвращайте корректные коды, информируйте пользователя понятной страницей, храните только необходимые логи и устанавливайте разумные сроки хранения.
Типичные ошибки и их диагностика
- Неверный путь к базе. Ошибка в логе: не удаётся открыть файл MMDB. Проверьте права доступа Nginx-пользователя и путь.
- Старый модуль geoip. В конфиге используются
geoip_country
/geoip_city
, а MMDB не подключены. Перейдите наgeoip2
. - Неправильный клиентский IP. Без настройки
real_ip_module
Nginx видит адрес балансировщика. Исправьтеset_real_ip_from
,real_ip_header
, включитеreal_ip_recursive
. - Пустые переменные. Для части адресов база может не содержать данных. Обрабатывайте дефолты в
map
и логике приложения. - Нет обновлений. Точность падает со временем. Настройте
geoipupdate
и крон. - Слишком агрессивные
if
. Избегайте сложных условий вlocation
; переносите решения вmap
и используйте переменные.
Чек‑лист корректной конфигурации
- Установлен и подключён
ngx_http_geoip2_module
черезload_module
. - Скачаны и доступны для чтения
GeoLite2-Country.mmdb
/GeoLite2-City.mmdb
. - В
http
объявлены только нужные переменные geoip2. - Настроен
real_ip_module
и доверенные сети прокси/CDN. - Геологика оформлена через
map
и переменные, без избыточныхif
. - Логи содержат геометки; проверена анонимизация/ретеншн.
- Автообновление баз через
geoipupdate
и плановыйreload
. - Покрыты IPv6 кейсы; тесты c эмуляцией адресов.
- Ограничения возвращают корректные коды (403/451) и понятные страницы.
FAQ
Можно ли одновременно использовать Country и City? Да, подключите оба файла и объявите отдельные переменные. Это не конфликтует.
Нужно ли перезапускать Nginx при обновлении баз? Для большинства версий достаточно reload
. Некоторые релизы модуля поддерживают автообновление; уточняйте по вашей сборке.
Почему страна определяется не всегда? В базе может не быть записи, особенно для новых/редких подсетей. Обрабатывайте дефолты, логируйте пустые кейсы и обновляйте базы.
Как протестировать без внешнего трафика? Разрешите доверие к 127.0.0.1
, подставляйте X-Forwarded-For
в curl
, либо используйте mmdblookup
по адресу.
Где хранить MMDB? Стандартно в /usr/share/GeoIP
или /var/lib/GeoIP
с правами чтения для пользователя Nginx.
Правильно внедрённый geoip2
в Nginx даёт предсказуемый геотаргетинг, аккуратные ограничения и удобную аналитическую разметку логов — без ощутимой нагрузки на сервер.