Такой инструмент как 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 серверах, отлично справляется с поставленными перед нею целями, и конечно же постоянно совершенствуется. Поэтому эта статья будет периодически обновляться.

Categories: CentosScripts

0 Comments

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *