Сборка Nginx с GeoIP модулем. Ограничение доступа к сайту по странам.

nginx geoip

Здравствуйте дамы и господа. Иногда появляется необходимость запретить доступ на свой сайт из некоторых стран. Например, при DDoS атаках или поступлении на сайт нежелательного трафика с адресов определенной страны. Закрыть доступ можно с помощью специального модуля GeoIP для Nginx.

С помощью модуля можно не только запретить доступ, иногда он нужен для работы некоторых приложений. Недавно мне как раз понадобилось наличие модуля для системы сбора статистики PIWIK. Но поскольку сервер был собран без него, мне пришлось пересобирать Nginx и добавлять нужный модуль.

По умолчанию модуль не входит в состав Nginx, он добавляется при сборке с помощью следующего параметра.

Первым делом узнаем с какими параметрами был собран Nginx.

Нас интересует строка con­fig­ure argu­ments, точнее все написанное после двоеточия, это и есть конфигурация с которой был собран сервер. Перейдем в каталог с исходниками, после установки я никогда их не удаляю.

Установим пакет lib­geoip-dev, он понадобится при сборке.
Если его не установить то сборка завершится такой ошибкой.

Задаем новую конфигурацию. С помощью команды ./configure задаем предыдущую конфигурацию с добавленным параметром --with-http_­geoip_­mod­ule.

Сразу после сборки компилируем и устанавливаем.
Создадим каталог для хранения баз GeoIP и сразу перейдем в него.
С помощью wget скачиваем базы стран и городов.
Распакуем скачанные архивы.

В результате получим два файла GeoIP.dat и GeoLiteCity.dat, их нужно будет включить в конфигурацию сервера.

Открываем nginx.conf и добавляем базы в контекст http {}.

В файл fastcgi_params необходимо добавить необходимые для работы переменные.

Перезапустим сервер и php. У меня php сборный, у вас он может называться по другому.

Сделаем проверку. В корневой директории сайта создадим файл geotest.php со следующим содержанием.

Проверьте свое положение, это можно сделать через сеть Tor. Обратитесь к сайту по адресу вида http://mydomain.com/geotest.php и посмотрите что из этого выйдет. Сначала можно обратиться со своего настоящего адреса, тогда точно будете уверены что все работает. Должно быть что-то типа того.

Все проверили, все работает. Переходим собственно к запретам, будем не пущать неугодных. Опять открываем nginx.conf и добавляем в контекст http {} вот такую конструкцию.

Работает это по схеме белого списка. По умолчанию все страны плохие, они определяются переменной $bad_country, но есть "белый список" - good_countries. Список содержит двухбуквенный код страны со значением 0 разрешающим доступ. Значение 1 наоборот запрещает доступ. Выглядит это примерно так.

На примере показаны: Австралия (AU), Аруба (AW), Азербайджан (AZ), Босния и Герцеговина (BA). Из них доступ запрещен только Азербайджану, всем остальным доступ разрешен. С полным списком использующихся обозначений можно ознакомиться здесь.

Создадим файл good_countries в каталоге /etc/nginx/geoip.

Добавьте в него разрешенные страны в следующем формате.

Все остальные, кто не внесен в список, не будут иметь доступа к сайту. Можно пойти методом от противного и добавить все страны, а потом исключить ненужные.

Теперь самое главное. Нужно добавить условие при котором "плохие страны" будут исключаться из свободного доступа к вашему сайту. Откройте конфигурационный файл который отвечает за сайт и добавьте условие в вызов php. Например так.

При определении if ($bad_country) {return 403;} "плохой страны" пользователю пришедшему с адреса принадлежащего ей будет отдан 403 ответ (for­bid­den).

Перезапустим сервер.

Принцип понятен, если значение 0, то доступ есть, если 1, то доступа нет. То есть изменили значение на 1, перезагрузили сервер (достаточно reload) и после чего PROFIT!

Можно пойти дальше 403-го ответа. Это скучно и слишком банально. Давайте будем отдавать не ошибку, а страничку, на которой можно немного поглумиться над неугодными посетителями. Просто для примера.

Сохранить как html и кинуть в корень сайта. Можно написать что-нибудь свое, можно сделать страничку с изображением и т.д.

Только тогда нужно переписать условие, вместо ответа 403, будем отдавать адрес странички c 301 редиректом.
На этом все. Благодарю за внимание. О том как запретить доступ целой стране, но оставить лазейку для отдельных ip-адресов, можно прочитать в продолжении статьи. Там я рассматриваю вопрос про поисковых роботов, заданный в комментариях.