Такой инструмент как Front-end сервер уже давно зарекомендовал себя как эффективный способ решения сразу массы проблем. С помощью front-end серверов администраторы Linux скрывают реальные ip адреса приложений, балансируют нагрузку на backend, организуют почтовые releay и выполняют множество задач, которые довольно удобно решать с помощью front-end серверов с Nginx proxy на борту.
В этой статье мы расскажем и предоставим подробный листинг команд для организации идеального Nginx proxy front-end (Perfect Nginx Proxy — PNP) сервера на базе Centos 7, который помимо своей прямой роли, будет предоставлять ещё и автоматическую выдачу SSL сертификатов LetsEncrypt. Кроме этого, мы обеспечим корректную работу GeoIP2, проброс на backend корректных заголовков и реальных ip адресов пользователей, если вы используете CloudFlare.
Кстати, у нас есть отличная статья на тему генерации WildCard SSL сертификатов LetsEncrypt в связке с Cloudflare
Итак, для начала работ нам необходимо установить epel-release:
yum install epel-release -y
После установки epel-release, приступаем к установке nginx и git:
yum install git nginx -y
Далее в отдельную папку клонируем ngx_http_geoip2_module:
cd /usr/src
git clone https://github.com/leev/ngx_http_geoip2_module.git
После завершения скачиваем последнюю версию nginx использую команды:
NGINXFILE=$(wget -qO- http://nginx.org/en/download.html | tr ' ' '\n' | egrep -o 'nginx.+?tar.gz' | head -1) wget http://nginx.org/download/${NGINXFILE} tar zxvf ${NGINXFILE} cd ${NGINXFILE%..}
Теперь установим необходимые библиотеки и зависимости для последующей сборки модуля:
yum groupinstall -y "Development Tools" "Development Libraries"
yum install -y compat-libstdc++-33 libstdc++.so.6.i686 zlib libmaxminddb libmaxminddb-devel pcre-devel openssl-devel
yum install -y compat-libstdc++-33 libstdc++.so.6 zlib libmaxminddb libmaxminddb-devel pcre-devel openssl-devel
Копируем текущую конфигурацию nginx, как говорится — на всякий случай:
cp -r /etc/nginx /root/nginx_$(date +%F)
И приступаем к сборке:
./configure --add-module=/usr/src/ngx_http_geoip2_module --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --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 --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'
make
make install
В зависимости от ресурсов, процесс может занимать некоторое время. После того как всё завершится создаём необходимую директорию для размещения баз GeoIP2 и скачиваем сами базы:
mkdir -p /usr/share/nginx/GeoIP2
wget -O /usr/share/nginx/GeoIP2/GeoLite2-ASN.mmdb http://ip.linuxexpert.ru/GeoIP2/GeoLite2-ASN.mmdb
wget -O /usr/share/nginx/GeoIP2/GeoLite2-City.mmdb http://ip.linuxexpert.ru/GeoIP2/GeoLite2-City.mmdb
wget -O /usr/share/nginx/GeoIP2/GeoLite2-Country.mmdb http://ip.linuxexpert.ru/GeoIP2/GeoLite2-Country.mmdb
ln -s /usr/share/nginx/GeoIP2 /etc/nginx/GeoIP2
Далее создаём конфигурацию geoip2 скопировав и выполнив команду целиком:
cat > /etc/nginx/geoip2.conf << 'EOL' geoip2 GeoIP2/GeoLite2-City.mmdb { $geoip2_city_names_en city names en; $geoip2_continent_code continent code; $geoip2_continent_names_en continent names en; $geoip2_country_iso_code country iso_code; $geoip2_names_en names en; $geoip2_location_accuracy_radius location accuracy_radius; $geoip2_location_latitude location latitude; $geoip2_location_longitude location longitude; $geoip2_location_time_zone location time_zone; $geoip2_postal_code postal code; $geoip2_registered_country_iso_code registered_country iso_code; $geoip2_registered_country_names_en registered_coutry names en; $geoip2_subdivisions_iso_code subdivisions iso_code; $geoip2_subdivisions_names_en subdivisions names en; } geoip2 GeoIP2/GeoLite2-ASN.mmdb { $geoip2_autonomous_system_number autonomous_system_number; $geoip2_autonomous_system_organization autonomous_system_organization; } EOL
Следующим шагом создаём команду, которая подготовит нам конфигурацию fastcgi_params:
cat > /etc/nginx/fastcgi_params << 'EOFASTPARAMS' fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REQUEST_SCHEME $scheme; fastcgi_param HTTPS $https if_not_empty; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; PHP only, required if PHP was built with --enable-force-cgi-redirect fastcgi_param REDIRECT_STATUS 200; fastcgi_param GEOIP2_CITY_NAMES_EN $geoip2_city_names_en; fastcgi_param GEOIP2_CONTINENT_CODE $geoip2_continent_code; fastcgi_param GEOIP2_CONTINENT_NAMES_EN $geoip2_continent_names_en; fastcgi_param GEOIP2_COUNTRY_ISO_CODE $geoip2_country_iso_code; fastcgi_param GEOIP2_NAMES_EN $geoip2_names_en; fastcgi_param GEOIP2_LOCATION_ACCURACY_RADIUS $geoip2_location_accuracy_radius; fastcgi_param GEOIP2_LOCATION_LATITUDE $geoip2_location_latitude; fastcgi_param GEOIP2_LOCATION_LONGITUDE $geoip2_location_longitude; fastcgi_param GEOIP2_LOCATION_TIME_ZONE $geoip2_location_time_zone; fastcgi_param GEOIP2_POSTAL_CODE $geoip2_postal_code; fastcgi_param GEOIP2_REGISTERED_COUNTRY_ISO_CODE $geoip2_registered_country_iso_code; fastcgi_param GEOIP2_REGISTERED_COUNTRY_NAMES_EN $geoip2_registered_country_names_en; fastcgi_param GEOIP2_SUBDIVISIONS_ISO_CODE $geoip2_subdivisions_iso_code; fastcgi_param GEOIP2_SUBDIVISIONS_NAMES_EN $geoip2_subdivisions_names_en; fastcgi_param GEOIP2_AUTONOMOUS_SYSTEM_NUMBER $geoip2_autonomous_system_number; fastcgi_param GEOIP2_AUTONOMOUS_SYSTEM_ORGANIZATION $geoip2_autonomous_system_organization; EOFASTPARAMS
Подключаем созданные конфигурации в nginx, проверяем конфигурацию и перезапускаем nginx:
NSTRING=$(grep -n '/etc/nginx/conf.d/*.conf' /etc/nginx/nginx.conf | cut -d : -f 1) grep -q geoip2.conf /etc/nginx/nginx.conf || sed -i -e ${NSTRING}' s#^#include /etc/nginx/geoip2.conf;\n#;' /etc/nginx/nginx.conf nginx -t && service nginx restart
Теперь пришло время установить certbot, выполнив следующую команду:
yum install certbot -y
После завершения установки certbot, нам необходимо создать директорию и поместить туда скрипт, который будет работая по крону парсить лог на предмет доменов, которые выполняя запрос по https получают ошибку и попадают в лог расположенный по адресу /var/log/nginx-ssl-error.log. Команда которую необходимо выполнить выглядит так:
mkdir /root/sbin/ &>/dev/null cat > /root/sbin/lets_auto_sign << 'EOCAT' for DOMAIN in $(grep 'cannot load certificate' /var/log/nginx-ssl-error.log | cut -d '"' -f 2 | cut -d / -f 5 | sort -u) do letsencrypt certonly -a webroot -n -m admin@letsgetdomain.com --agree-tos --webroot-path=/usr/share/nginx/html -d ${DOMAIN} ; chmod -R 755 /etc/letsencrypt done truncate -s 0 /var/log/nginx-ssl-error.log EOCAT chmod 700 /root/sbin/lets_auto_sign
Данный скрипт позволит автоматически издавать сертификаты для доменов направленных на наш front-end сервер.
Стоит помнить, что сертификаты от LetsEncrypt имеют сравнительно не большой срок действия, поэтому нам необходимо позаботиться о их своевременном продлении, поэтому создадим скрипт, который будет автоматически переиздавать наши сертификаты:
cat > /root/sbin/lets_renew << 'EOCAT' check_ssl() { expr (echo|openssl s_client -connect ${DOMAIN}:443 -servername ${DOMAIN} 2>/dev/null|openssl x509 -noout -enddate|cut -d'=' -f2|xargs -I ^ date +%s -d "^"
-date +%s
) / 24 / 3600 } truncate -s 0 /tmp/ssl_domains for DOMAIN in $(ls /etc/letsencrypt/live/ | grep -v README) do echo $(check_ssl)_$DOMAIN >> /tmp/ssl_domains done cat /tmp/ssl_domains for EXDOMAIN in $(cat /tmp/ssl_domains | uniq) do EXDAYS=$(echo $EXDOMAIN | cut -d _ -f 1) DOMAIN=$(echo $EXDOMAIN | cut -d _ -f 2) if [ "$EXDAYS" -lt "30" ] then letsencrypt certonly -a webroot -n -m admin@letsgetdomain.com --agree-tos --webroot-path=/usr/share/nginx/html -d ${DOMAIN} ; chmod -R 755 /etc/letsencrypt fi done EOCAT chmod 700 /root/sbin/lets_renew
Выполнив эту команду целиком, мы создадим файл /root/sbin/lets_renew и зададим необходимые права, которые обеспечат его корректное выполнение.
Что бы выполнение скриптов исполнялось по определённому расписанию, создадим кроны:
cat > /etc/cron.d/lets_auto_gen << 'EOL' * * * * root /root/sbin/lets_auto_sign 0 14 * * 1 root /root/sbin/lets_renew EOL
Теперь мы можем создать конфигурационный файл nginx, который будет проксировать запросы с front-end сервера на backend.
mkdir -p /etc/nginx/conf.d cat > /etc/nginx/conf.d/frontend.conf << 'EOAPP' upstream appserver { server 1.2.3.4 weight=10 max_fails=60 fail_timeout=2s; } map $http_x_forwarded_proto $real_scheme { default $http_x_forwarded_proto; '' $scheme; } server { listen 80; listen *:443 ssl http2; ssl_certificate /etc/letsencrypt/live/$ssl_server_name/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/$ssl_server_name/privkey.pem; ssl_session_cache shared:SSL:50m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384'; ssl_prefer_server_ciphers on; resolver 8.8.4.4 8.8.8.8 valid=300s; resolver_timeout 10s; root /usr/share/nginx/html; access_log /var/log/nginx-main-access.log main; error_log /var/log/nginx-ssl-error.log; server_name _;location ~ "^/\.well-known/acme-challenge/(.*)$" {
default_type text/plain;
}
location / {
include /etc/nginx/deny.conf; proxy_pass http://appserver; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $real_scheme; } } EOAPP
Обратите внимание, что в upstream вместо ip адреса 1.2.3.4:
server 1.2.3.4 weight=10 max_fails=60 fail_timeout=2s;
Вам необходимо указать ip адреса вашего сервера backend (приложения).
На текущем этапе осталось заменить дефолтный nginx.conf — на новый, с оптимизированными настройками и продвинутыми пробросами заголовков:
cat > /etc/nginx/nginx.conf << 'EONGINX' worker_rlimit_nofile 30000; worker_processes auto; timer_resolution 100ms; pid /run/nginx.pid; thread_pool default threads=32 max_queue=655360; events { worker_connections 10000; multi_accept on; use epoll; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $host [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"'; log_format defaultServer '[$time_local][$server_addr] $remote_addr ($http_user_agent) -> "$http_referer" $host "$request" $status'; log_format downloadsLog '[$time_local] $remote_addr "$request"'; log_format Counter '[$time_iso8601] $remote_addr $request_uri?$query_string'; # log example # access_log unc.log Counter; access_log off; access_log /dev/null main; # access_log /var/log/nginx-main-access.log; error_log /dev/null; connection_pool_size 256; client_header_buffer_size 4k; client_max_body_size 2048m; large_client_header_buffers 8 32k; request_pool_size 4k; output_buffers 1 32k; postpone_output 1460; gzip on; gzip_min_length 1000; gzip_proxied any; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript text/x-javascript application/javascript image/svg+xml svg svgz; gzip_disable "msie6"; gzip_comp_level 6; gzip_http_version 1.0; gzip_vary on;sendfile on;
aio threads;
directio 10m;
tcp_nopush on;
tcp_nodelay on;
server_tokens off;
keepalive_timeout 75 20;
server_names_hash_bucket_size 128;
server_names_hash_max_size 8192;
ignore_invalid_headers on;
server_name_in_redirect off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.4.4 8.8.8.8 valid=300s;
resolver_timeout 10s;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'AES128+EECDH:AES128+EDH';
ssl_session_cache shared:SSL:50m;
ssl_prefer_server_ciphers on;
#ssl_dhparam /etc/ssl/certs/dhparam.pem;
#ssl_trusted_certificate /etc/ssl/certs/ca-certs.pem;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
proxy_buffer_size 8k;
proxy_buffers 8 64k;
proxy_connect_timeout 300m;
proxy_read_timeout 300m;
proxy_send_timeout 300m;
proxy_store off;
proxy_ignore_client_abort on;
fastcgi_read_timeout 300m;
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
proxy_cache_path /var/cache/nginx/page levels=2 keys_zone=pagecache:100m inactive=1h max_size=10g;
fastcgi_cache_path /var/cache/nginx/fpm levels=2 keys_zone=FPMCACHE:100m inactive=1h max_size=10g;
fastcgi_cache_key "$scheme$request_method$host";
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
upstream memcached_backend { server 127.0.0.1:11211; }
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
set_real_ip_from 51.255.66.206/32; set_real_ip_from 103.21.244.0/22; set_real_ip_from 103.22.200.0/22; set_real_ip_from 103.31.4.0/22; set_real_ip_from 104.16.0.0/12; set_real_ip_from 108.162.192.0/18; set_real_ip_from 131.0.72.0/22; set_real_ip_from 141.101.64.0/18; set_real_ip_from 162.158.0.0/15; set_real_ip_from 172.64.0.0/13; set_real_ip_from 173.245.48.0/20; set_real_ip_from 188.114.96.0/20; set_real_ip_from 190.93.240.0/20; set_real_ip_from 197.234.240.0/22; set_real_ip_from 198.41.128.0/17; set_real_ip_from 199.27.128.0/21; set_real_ip_from 2400:cb00::/32; set_real_ip_from 2606:4700::/32; set_real_ip_from 2803:f800::/32; set_real_ip_from 2405:b500::/32; set_real_ip_from 2405:8100::/32; set_real_ip_from 2c0f:f248::/32; set_real_ip_from 2a06:98c0::/29; set_real_ip_from 0.0.0.0/0; real_ip_header X-Forwarded-For; allow all; include /etc/nginx/geoip2.conf; include /etc/nginx/conf.d/.conf; include /etc/nginx/sites-enabled/.vhost; } EONGINX
Конфиг создан, осталось создать файл где мы можем самостоятельно формировать blacklist, со списком ip адресов, которые не будут иметь доступ к нашему серверу, а так же папку для кеша и уже финально перезагрузить nginx.
touch /etc/nginx/deny.conf mkdir -p /var/cache/nginx/page nginx -t && service nginx restart
Вот и всё, наш Perfect Nginx Proxy (PNP) готов.
Подводя итоги, стоит дополнительно обозначить тот факт, что эта сборка была установлена и работает на текущий момент более чем на 50 front-end серверах, отлично справляется с поставленными перед нею целями, и конечно же постоянно совершенствуется. Поэтому эта статья будет периодически обновляться.
0 Comments