Top.Mail.Ru
OSEN-НИЙ SAAALEСкидка 50% на виртуальный хостинг и VDS
до 30.11.2025 Подробнее
Выберите продукт

geoip2 в Nginx: геотаргетинг, ограничения и корректная конфигурация

Разбираем, как правильно включить geoip2 в Nginx: где взять базы MaxMind, как подключить модуль, настроить геотаргетинг и ограничения по странам, учесть обратные прокси и IPv6, добавить метки в логи и автоматизировать обновления баз. Плюс частые ошибки и чек‑лист в конце.
geoip2 в Nginx: геотаргетинг, ограничения и корректная конфигурация

Геоинформация по 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 и мониторинг свежести файлов.

Расположение баз MaxMind и подключение к Nginx

Базовая конфигурация 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 через curl и mmdblookup в терминале

Логирование и метрики

Добавив переменные 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 хорошо.

Переезжаете на отдельный сервер ради гибких правил? Сохранить аптайм поможет руководство «перенос сайта без простоя».

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Юридические и приватностные аспекты

Геоданные по 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 и используйте переменные.

Чек‑лист корректной конфигурации

  1. Установлен и подключён ngx_http_geoip2_module через load_module.
  2. Скачаны и доступны для чтения GeoLite2-Country.mmdb/GeoLite2-City.mmdb.
  3. В http объявлены только нужные переменные geoip2.
  4. Настроен real_ip_module и доверенные сети прокси/CDN.
  5. Геологика оформлена через map и переменные, без избыточных if.
  6. Логи содержат геометки; проверена анонимизация/ретеншн.
  7. Автообновление баз через geoipupdate и плановый reload.
  8. Покрыты IPv6 кейсы; тесты c эмуляцией адресов.
  9. Ограничения возвращают корректные коды (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 даёт предсказуемый геотаргетинг, аккуратные ограничения и удобную аналитическую разметку логов — без ощутимой нагрузки на сервер.

Поделиться статьей

Вам будет интересно

rsync для деплоев и бэкапов: быстрые ключи, инкрементальность и контроль прав OpenAI Статья написана AI Fastfox

rsync для деплоев и бэкапов: быстрые ключи, инкрементальность и контроль прав

rsync остаётся базовым инструментом для деплоя и резервного копирования. В статье — проверенные пресеты, инкрементальные бэкапы че ...
php-fpm status и ping: включаем, мониторим и ищем узкие места OpenAI Статья написана AI Fastfox

php-fpm status и ping: включаем, мониторим и ищем узкие места

Разделы status и ping в php-fpm — быстрый способ понять здоровье пула и найти узкие места под нагрузкой. Покажу, как включить и за ...
UFW на практике: быстрые правила для веб‑сервера, SSH и rate‑limit OpenAI Статья написана AI Fastfox

UFW на практике: быстрые правила для веб‑сервера, SSH и rate‑limit

UFW позволяет быстро закрыть лишние порты, оставить доступ к SSH и сайту и включить защиту от перебора. В статье — безопасный запу ...