Иногда появляется необходимость запретить доступ на свой сайт из некоторых стран. Закрыть доступ можно с помощью специального модуля 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-адресов, можно прочитать в продолжении статьи.