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

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

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

--with-http_geoip_module

Перейдем в каталог с исходниками Nginx.

cd /usr/local/src/nginx-1.11.9

Установим пакет libgeoip-dev, он понадобится при сборке.

apt-get install libgeoip-dev -y

Если его не установить то сборка завершится ошибкой.

./configure: error: the GeoIP module requires the GeoIP library.
You can either do not enable the module or install the library.

Задаем конфигурацию с параметром --with-http_geoip_module.

./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --user=nginx --group=nginx --without-http_autoindex_module --without-http_ssi_module --without-http_scgi_module --without-http_uwsgi_module --without-http_split_clients_module --without-http_memcached_module --without-http_empty_gif_module --without-http_browser_module --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_mp4_module --with-http_auth_request_module --with-http_stub_status_module --with-http_random_index_module --with-http_gunzip_module --with-threads --with-openssl=/usr/local/src/openssl-1.1.0f --with-http_geoip_module

Компилируем и устанавливаем.

make && make install

Создадим каталог для хранения баз GeoIP и сразу перейдем в него.

mkdir /etc/nginx/geoip
cd /etc/nginx/geoip

С помощью wget скачиваем базы стран и городов.

wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz

Распакуем скачанные архивы.

gunzip GeoIP.dat.gz
gunzip GeoLiteCity.dat.gz

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

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

geoip_country /etc/nginx/geoip/GeoIP.dat;
geoip_city /etc/nginx/geoip/GeoLiteCity.dat;

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

nano /etc/nginx/fastcgi_params

# GeoIP
fastcgi_param  GEOIP_COUNTRY_CODE        $geoip_country_code;
fastcgi_param  GEOIP_COUNTRY_CODE3       $geoip_country_code3;
fastcgi_param  GEOIP_COUNTRY_NAME        $geoip_country_name;
fastcgi_param  GEOIP_CITY_COUNTRY_CODE   $geoip_city_country_code;
fastcgi_param  GEOIP_CITY_COUNTRY_CODE3  $geoip_city_country_code3;
fastcgi_param  GEOIP_CITY_COUNTRY_NAME   $geoip_city_country_name;
fastcgi_param  GEOIP_REGION              $geoip_region;
fastcgi_param  GEOIP_CITY                $geoip_city;
fastcgi_param  GEOIP_POSTAL_CODE         $geoip_postal_code;
fastcgi_param  GEOIP_CITY_CONTINENT_CODE $geoip_city_continent_code;
fastcgi_param  GEOIP_LATITUDE            $geoip_latitude;
fastcgi_param  GEOIP_LONGITUDE           $geoip_longitude;

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

systemctl restart nginx
systemctl restart php7

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

map $geoip_country_code $bad_country {
    default 1;
    include /etc/nginx/geoip/good_countries;
}

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

AU 0;
AW 0;
AZ 1;
BA 0;

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

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

nano /etc/nginx/geoip/good_countries

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

CZ 0;
DE 0;
DJ 0;
DK 0;
DM 0;
DO 0;
DZ 0;

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

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

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

location ~ \.php$ {

    try_files $uri =404;

    include       fastcgi_params;
    fastcgi_index index.php;
    fastcgi_pass  unix:/var/www/techlist/socket/techlist.sock;
    fastcgi_param SCRIPT_FILENAME
                  $document_root$fastcgi_script_name;
	
	if ($bad_country) {return 403;}
	
}

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

systemctl restart nginx

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

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

<h1>Your fucking country has no access to my website</h1>

Только тогда нужно переписать условие, вместо ответа 403, будем отдавать адрес странички c 301 редиректом.

if ($bad_country) {return 301 https://mydomain.com/fuck-error.html;}

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

Ответить:

Please enter your comment!
Please enter your name here