Настройки безопасности
Чтобы не светить версии nginx и php делаем следующее: в файле /etc/nginx/nginx.conf
в секции http
дописываем:
1 | server_tokens off; |
а в файле /etc/php.ini
дописываем:
1 | expose_php = Off |
Рестартуем сервисы:
1 2 | sudo systemctl restart php-fpm.service sudo systemctl restart nginx.service |
Проверяем командой:
1 2 3 4 5 6 7 8 9 10 | $ curl -I http://idoka.ru HTTP/1.1 200 OK Server: nginx Content-Type: text/html; charset=UTF-8 Connection: keep-alive Keep-Alive: timeout=60 Vary: Accept-Encoding, Cookie Cache-Control: max-age=3, must-revalidate Cache-Control: public |
Прикрутка GeoIP
Если по nginx -V
не находим опцию --with-http_geoip_module
, но у нас CentOS 7, то, начиная с версии nginx-1.10.0, выход есть:
1 | sudo yum install -y nginx-module-geoip |
Либа будет установлена в /usr/lib64/nginx/modules
:
1 2 3 4 5 | ls -l /usr/lib64/nginx/modules/ ngx_http_geoip_module-debug.so* ngx_http_geoip_module.so* ngx_http_js_module-debug.so* ngx_http_js_module.so* |
Скачиваем и разворачиваем:
1 2 3 4 5 6 | wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz wget http://download.maxmind.com/download/geoip/database/asnum/GeoIPASNum.dat.gz gunzip GeoIP.dat.gz gunzip GeoLiteCity.dat.gz gunzip GeoIPASNum.dat.gz |
Далее в секции http
конфига nginx прописываем пути к скаченным БД (страны, города, провайдеры):
1 2 3 | geoip_country /path/../GeoIP.dat; geoip_city /path/../GeoLiteCity.dat; geoip_org /path/../GeoIPASNum.dat; |
А вне любых секций конфига nginx добавить:
1 | load_module "modules/ngx_http_geoip_module.so"; |
Теперь перегружаем nginx:
1 | sudo systemctl restart nginx.service |
Вообще говоря, в директиве geoip_org
можно указать БД провайдеров или организаций, но в nginx нельзя иметь одновременно подключенные обе БД — надо определиться с тем что подключать.
Теперь можно, там где надо, передавать необходимые fastcgi параметры (имеет смысл добавить эти параметры в конец файла /etc/nginx/fastcgi_params):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # для стран: fastcgi_param GEOIP_ADDR $remote_addr; fastcgi_param GEOIP_COUNTRY_CODE $geoip_country_code; fastcgi_param GEOIP_COUNTRY_NAME $geoip_country_name; # для городов: fastcgi_param GEOIP_REGION $geoip_region; fastcgi_param GEOIP_REGION_NAME $geoip_region_name; fastcgi_param GEOIP_CITY $geoip_city; fastcgi_param GEOIP_AREA_CODE $geoip_area_code; fastcgi_param GEOIP_LATITUDE $geoip_latitude; fastcgi_param GEOIP_LONGITUDE $geoip_longitude; fastcgi_param GEOIP_POSTAL_CODE $geoip_postal_code; # для провайдеров/организаций: fastcgi_param GEOIP_ORGANIZATION $geoip_org; |
Тестируем работоспособность, включив в секцию server следующий код (понадобится установленный и подключенный в конфиге модуль echo-nginx-module):
1 2 3 4 5 6 7 8 9 10 | # Testing GeoIP location ^~ /geoip/ { add_header Content-Type application/json; if ($geoip_country_code ~ "RU") { echo '{"key":"russia","country":"$geoip_country_code"}'; } if ($geoip_country_code !~ "RU") { echo '{"key":"global","country":"$geoip_country_code"}'; } } |
либо кодом php:
1 2 3 | <?php echo "Your country is {$_SERVER['GEOIP_COUNTRY_NAME']} and your city is {$_SERVER['GEOIP_CITY']}."; ?> |
Запрет посещения средствами nginx для определенных стран
В ситуации, когда необходимо заблокировать доступ к хосту пользователям из определенных стран, используются также базы GeoIP для определения принадлежности к стране. Одной из разновидностей задачи является показ сайта на языке, нативном для страны нахождения постетителя.
Впишем следующий маппинг в секцию http
конфига nginx:
1 2 3 4 | map $geoip_country_code $allowed_country { default yes; CN no; } |
Для того чтобы наоборот указать кому открыть доступ, перепишем:
1 2 3 4 5 6 7 | map $geoip_country_code $allowed_country { default no; RU yes; UA yes; BY yes; KZ yes; } |
server
):1 2 3 | if ($allowed_country = no) { return 404; } |
UPD: вариант с автообновлением GEOIP
Ставим:
1 | sudo yum install -y GeoIP GeoIP-data GeoIP-update |
GeoIP-update — для автообновления через крон. БД будут располагаться в /usr/share/GeoIP
. Теперь осталось прописать в конфиге:
1 2 3 | geoip_country /usr/share/GeoIP/GeoIP.dat; geoip_city /usr/share/GeoIP/GeoIPCity.dat; geoip_org /usr/share/GeoIP/GeoIPASNum.dat; |
Настройка Let’s Encrypt сертификатов в LEMP на CentOS 7
Если вкратце — не нужно поднимать сервер на 9999 порту, юзаем самый простой способ webroot, это значит что letsencrypt’у достаточно указать в какой папке будет лежать файл для обмена с сервером (подтверждение прав на домен).
Забираем с гитхаба:
1 2 3 | git clone --depth=1 https://github.com/letsencrypt/letsencrypt cd letsencrypt ./letsencrypt-auto |
Просит рута, ну ок:
1 2 3 4 5 6 7 8 9 10 11 12 | Package gcc-4.8.5-11.el7.x86_64 already installed and latest version Package augeas-libs-1.4.0-2.el7.x86_64 already installed and latest version Package 1:openssl-1.0.1e-60.el7.x86_64 already installed and latest version Package 1:openssl-devel-1.0.1e-60.el7.x86_64 already installed and latest version Package libffi-devel-3.0.13-18.el7.x86_64 already installed and latest version Package redhat-rpm-config-9.1.0-72.el7.centos.noarch already installed and latest version Package ca-certificates-2015.2.6-73.el7.noarch already installed and latest version Package python-2.7.5-48.el7.x86_64 already installed and latest version Package python-devel-2.7.5-48.el7.x86_64 already installed and latest version Package python-virtualenv-1.10.1-3.el7.noarch already installed and latest version Package python-tools-2.7.5-48.el7.x86_64 already installed and latest version Package python2-pip-8.1.2-5.el7.noarch already installed and latest version |
Питоническая шелуха имелась в системе, а теперь самое интересное: letsencrypt-auto настолько тупой, что не видит, что репозиторий EPEL уже установлен и докучи ставит зачем-то httpd, httpd-tools и mod_ssl (это жесть, господа!). Даже при вызове с опцией —dry-run!! Крайне рукожопный скрипт!
Теперь при попытке удаления httpd он заодно сносит и php, а при установке php после таки-сноса httpd, тянет в качестве зависимости опять же httpd — чтоооооооооооо??????
Ладно, сертификаты важнее, идём дальше. Я не стал конфигурировать (и перезапускать) nginx, как того рекомендуют для указания размещения папки .well-known, если будет необходимость задать расположение .well-known вне папки сайта, синтаксис такой:
1 2 3 | location /.well-known { root /var/site/idoka.ru; } |
далее пробуем запустить letsencrypt-auto для нашего домена:
1 2 3 4 5 6 7 8 9 10 11 12 | $ ./letsencrypt-auto certonly --agree-tos --register-unsafely-without-email --noninteractive --webroot --webroot-path /var/site/idoka.ru -d idoka.ru Saving debug log to /var/log/letsencrypt/letsencrypt.log Registering without email! Obtaining a new certificate Performing the following challenges: http-01 challenge for idoka.ru Using the webroot path /var/site/idoka.ru for all unmatched domains. Waiting for verification... Cleaning up challenges Generating key (2048 bits): /etc/letsencrypt/keys/0001_key-certbot.pem Creating CSR: /etc/letsencrypt/csr/0001_csr-certbot.pem |
Успех!
Для получения доп.сертификатов для поддоменов можно указывать несколько опций -d с именами поддоменов.
Настройка SSL в nginx сводится к добавлению:
1 2 3 4 5 6 | ######### SSL ######### ssl on; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'HIGH:!aNULL:!MD5:!kEDH'; ssl_certificate /etc/letsencrypt/live/idoka.ru/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/idoka.ru/privkey.pem; |
Или вот настройки, которые предлагает сам letsencrypt в файле certbot-nginx/certbot_nginx/options-ssl-nginx.conf
:
1 2 3 4 5 6 7 | ssl_session_cache shared:le_nginx_SSL:1m; ssl_session_timeout 1440m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256 ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES128-SHA ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES128-SHA256 ECDHE-ECDSA-AES256-SHA384 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-AES128-SHA ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES256-SHA384 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES256-SHA256 EDH-RSA-DES-CBC3-SHA"; |
Для OCSP stapling делаем следующее:
1 | wget -O /etc/nginx/ssl/chain.pem "https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem" |
А в конфиг добавляем следующее:
1 2 3 | ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate /etc/nginx/ssl/chain.pem; |
После чего перегружаем конфиг nginx:
1 | sudo systemctl reload nginx.service |
Последний штрих: автообновление сертификатов. Добавляем в /etc/crontab
:
1 | 0 2 1 * * letsencrypt-auto renew >> /dev/null 2>&1 |
Желательно также тамже рестартануть nginx:
1 | 5 2 1 * * systemctl reload nginx.service >> /dev/null 2>&1 |
— первого числа каждого месяца в 2:00 будет осуществлен перевыпуск сертификатов, а в 2:05 перезачитывание конфигов nginx.
Актуальная версия справки: https://letsencrypt.readthedocs.io/en/latest/using.html#webroot