GeoIP позволяет nginx принимать решение по стране посетителя — показать локализованную версию сайта, закрыть доступ для регионов, где легитимных клиентов нет, или просто собрать статистику по географии трафика. Модуль не заменяет файрвол и не защищает от распределённой атаки: он работает на уровне HTTP уже после того, как соединение дошло до nginx, и подходит для точечных правил, а не для защиты от наплыва запросов.
Два модуля GeoIP и почему geoip2 предпочтительнее
В nginx есть два модуля для определения страны по IP: устаревший ngx_http_geoip_module, работающий с бинарными базами легаси-формата GeoIP, и ngx_http_geoip2_module, который читает современные базы формата .mmdb — GeoLite2 или платный GeoIP2 от MaxMind. Легаси-базы GeoIP компания MaxMind давно не обновляет, поэтому для новых серверов смысла в старом модуле нет.
Модуль geoip2 не входит в базовую сборку nginx — это динамический модуль, который устанавливается отдельным пакетом из официального репозитория nginx или собирается из исходников с опцией --add-dynamic-module. Базовую настройку самого nginx, в который добавляется этот модуль, описывает статья про настройку Nginx для сайта на VDS.
Установка модуля и базы GeoLite2
После установки пакета модуль подключается директивой load_module в начале основного файла конфигурации, до блока events. База GeoLite2-Country или GeoLite2-City скачивается с сайта MaxMind — для бесплатных баз нужна регистрация и ключ лицензии, а их обновление обычно автоматизируют отдельным заданием cron с утилитой geoipupdate.
Директива geoip2 объявляется в блоке http один раз и связывает путь к файлу базы с переменными, которые можно использовать дальше в конфигурации, — кодом страны, континентом или названием города, если используется база City.
load_module modules/ngx_http_geoip2_module.so;
http {
geoip2 /etc/nginx/geoip/GeoLite2-Country.mmdb {
auto_reload 60m;
$geoip2_data_country_code country iso_code;
}
map $geoip2_data_country_code $country_blocked {
default 0;
RU 1;
BY 1;
}
}
Блокировка стран через map и return 403
Переменная $geoip2_data_country_code подставляется в map, который превращает код страны в простой флаг 0 или 1. Внутри server или location остаётся проверить этот флаг директивой if и вернуть 403 без обращения к бэкенду — запрос из заблокированной страны даже не доходит до PHP-FPM или прокси-приложения.
| Способ | Уровень | Когда уместен |
|---|---|---|
| geoip2 в nginx | HTTP, на самом сервере | точечные правила для отдельных location или доменов |
| Firewall-правила Cloudflare | перед сервером, на CDN | массовая блокировка стран ещё до того, как запрос дошёл до VDS |
| limit_req / limit_conn | HTTP, на самом сервере | защита от наплыва запросов независимо от географии |
Эти три способа не исключают друг друга: geoip2 решает, откуда запрос, Cloudflare фильтрует трафик ещё на границе сети, а limit_req и limit_conn ограничивают скорость запросов независимо от страны.
Где это уместно, а где лучше блокировать на Cloudflare
Правило на уровне nginx всё равно принимает TCP-соединение и тратит ресурсы процесса на обработку заголовков запроса, прежде чем вернуть 403. Для одиночного VDS без CDN это не критично, но при серьёзном объёме трафика из заблокированных стран разумнее не пускать его на сервер вовсе.
Если перед сайтом уже стоит Cloudflare, то блокировку по стране логичнее настроить там — она описана в статье про Firewall-правила Cloudflare. Для сайтов без CDN geoip2 в nginx остаётся рабочим вариантом без дополнительных сервисов.
Чек-лист перед включением
Перед тем как включать блокировку по странам в продакшене, стоит пройти по следующим пунктам — ошибка в правиле отрезает не абьюз, а часть реальных посетителей.
- Проверено, что IP реальных пользователей сайта, включая клиентов в командировках и на VPN, не попадают в список заблокированных стран по ошибке.
- База GeoLite2 обновляется регулярно — устаревшая база неверно определяет страну для новых подсетей.
- Правило протестировано через curl с заголовком, имитирующим IP из нужной страны, перед включением на реальном трафике.
- Для API и вебхуков от платёжных систем сделано исключение, если их серверы физически находятся в заблокированном регионе.
- Логи nginx фиксируют код страны в отдельной переменной, чтобы потом проверить, сколько запросов реально отрезано правилом.
Частые вопросы
Можно ли заблокировать не всю страну, а отдельный регион или город?
Да, если используется база GeoLite2-City вместо GeoLite2-Country — она даёт переменные с названием города и региона, но точность определения города заметно ниже точности определения страны, особенно для мобильных и корпоративных подсетей.
Что делать, если легитимный клиент пишет о блокировке 403?
Проверить его реальный IP и код страны по базе GeoLite2 вручную — иногда провайдер маршрутизирует трафик через узел в другой стране, и блокировка срабатывает ошибочно. В такой ситуации проще добавить его IP в отдельный allowlist, чем снимать правило целиком.
Нужно ли перезапускать nginx после обновления базы GeoLite2?
Нет, если в блоке geoip2 указан auto_reload с интервалом — nginx сам подхватывает новый файл базы по расписанию. Без этой директивы изменения применяются только после reload конфигурации.