Прокси для клиентского приложения
Для корректной работы пользовательского приложения при установке приложения в docker контейнере и без него нужен прокси, на котором будут выполняться роли:
- Хостинг приложения по пути
/ - Проксирование запросов к бэкенду по путям
/api/socket.io/metrics
- Подготовка и отправка статики по пути
/static - Опционально: предоставление доступа к ендпоинту
/metricsдля мониторинга приложения с использованием Prometheus - Опционально: предоставление ендпоинта для проксирования запросов и организации кэширования ответов тайлового сервера Martin.
Таким образом прокси будет выполнять роль диспетчера всех запросов приложения и является критически важным элементом при развертывании приложения. В качестве прокси используется Nginx 1.25.4.
Базовая конфигурация
nginx.conf
# Определяем пользователя
user nginx;
# Определяем количество рабочих процессов автоматически
# Параметр auto поддерживается только начиная с версий 1.3.8 и 1.2.5.
worker_processes auto;
# Данная директива указывает сколько файловых дескрипторов будет использовать Nginx. На каждое соединение надо
# выделять по два дескриптора, даже для статических файлов (картинки/JS/CSS): один для соединения с клиентом,
# а второй — для открытия статического файла. Таким образом, значение worker_rlimit_nofile должно быть не меньше
# удвоенного значению Max Clients.
# В системе это значение можно установить из командной строки ulimit -n 200000 или используя
# /etc/security/limits.conf.
# Проверить установленное значение в системе
# hard limit `ulimit -Hn` и soft limit `ulimit -Sn`
worker_rlimit_nofile 20000;
# !! для установки без контейнера надо вывод ошибок перенаправить в файлы, а не STDOUT !!
# pid /var/log/nginx/nginx.pid;
# задаем общие параметры логирования
# error_log /var/log/nginx/error.log warn;
error_log /dev/stdout info;
# логируем только критические ошибки
# error_log /var/log/nginx/error.log crit
# Если нужно полностью отключить ошибки (использовать с пониманием зачем это нужно)
# error_log /dev/null crit;
events {
# увеличение по сравнению со стандартным 1024, для продуктивного контура, можно увеличивать больше в зависимости от нагрузки и ресурсов
# worker_processes * worker_connections = max_clients (кол-во одновременных соединений)
worker_connections 2048;
# предпочтительнее для Linux
use epoll;
# Для того, чтобы Nginx пытался принять максимальное количество подключений, необходимо включить
# директиву multi_accept. Однако при слишком маленьком значении worker_connections, их лимит может быть
# быстро исчерпан.
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# Куда писать лог доступа и уровень логирования
# добавляем buffer=16k для оптимизации логирования
# access_log /var/log/nginx/access.log main buffer=16k;
access_log /dev/stdout main;
# либо отключаем лог - так будет работать намного быстрее
# access_log off;
# Для нормального ответа 304 Not Modified;
if_modified_since before;
# Включаем поддержку WebP
map $http_accept $webp_ext {
default "";
"~*webp" ".webp";
}
##
# Basic Settings
##
# Используется, если количество имен серверов большое
#server_names_hash_max_size 1200;
#server_names_hash_bucket_size 64;
### Обработка запросов ###
# Метод отправки данных sendfile более эффективен, чем стандартный метод read+write
sendfile on;
# Будет отправлять заголовки и и начало файла в одном пакете
tcp_nopush on;
tcp_nodelay on;
### Адрес резолвера DNS ###
# resolver 10.0.0.1 valid=30s;
### Информация о файлах ###
# Максимальное количество файлов, информация о которых будет содержаться в кеше
open_file_cache max=200000 inactive=20s;
# Через какое время информация будет удалена из кеша
open_file_cache_valid 30s;
# Кеширование информации о тех файлах, которые были использованы хотя бы 2 раза
open_file_cache_min_uses 2;
# Кеширование информации об отсутствующих файлах
open_file_cache_errors on;
# Удаляем информацию об nginx в headers
server_tokens off;
# Будет ждать 30 секунд перед закрытием keepalive соединения
keepalive_timeout 30s;
## Максимальное количество keepalive запросов от одного клиента
keepalive_requests 100;
# Разрешает или запрещает сброс соединений по таймауту
reset_timedout_connection on;
# Будет ждать 30 секунд тело запроса от клиента, после чего сбросит соединение
client_body_timeout 30s;
# В этом случае сервер не будет принимать запросы размером более 200Мб
client_max_body_size 200m;
# Если клиент прекратит чтение ответа, Nginx подождет 30 секунд и сбросит соединение
send_timeout 30s;
# Proxy #
# Задаёт таймаут для установления соединения с проксированным сервером.
# Необходимо иметь в виду, что этот таймаут обычно не может превышать 75 секунд.
proxy_connect_timeout 30s;
# Задаёт таймаут при передаче запроса проксированному серверу.
# Таймаут устанавливается не на всю передачу запроса, а только между двумя операциями записи.
# Если по истечении этого времени проксируемый сервер не примет новых данных, соединение закрывается.
proxy_send_timeout 30s;
# Задаёт таймаут при чтении ответа проксированного сервера.
# Таймаут устанавливается не на всю передачу ответа, а только между двумя операциями чтения.
# Если по истечении этого времени проксируемый сервер ничего не передаст, соединение закрывается.
proxy_read_timeout 30s;
# Размер буфера используемого для проксированых запросов
# proxy_buffers 32 4k;
##
# Кэш для геосервера
##
# proxy_cache_path /var/cache/nginx/
# levels=1:2
# max_size=10g
# inactive=60m
# use_temp_path=off
# keys_zone=tiles_cache:10m;
##
# Gzip Settings
##
# Включаем сжатие gzip
gzip on;
# Для IE6 отключить
gzip_disable "msie6";
# Добавляет Vary: Accept-Encoding в Headers
gzip_vary on;
# Cжатие для всех проксированных запросов (для работы NGINX+Apache)
gzip_proxied any;
# Устанавливает степень сжатия ответа методом gzip. Допустимые значения находятся в диапазоне от 1 до 9
gzip_comp_level 6;
# Задаёт число и размер буферов, в которые будет сжиматься ответ
gzip_buffers 16 8k;
# Устанавливает минимальную HTTP-версию запроса, необходимую для сжатия ответа. Значение по умолчанию
gzip_http_version 1.1;
# MIME-типы файлов в дополнение к text/html, которые нужно сжимать
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript image/svg+xml;
# Минимальная длина файла, которую нужно сжимать
gzip_min_length 10;
# Подключаем конфиги конкретных сайтов
include /etc/nginx/conf.d/*.conf;
}
Для самого приложения в контейнере или в самом nginx настраивается конфигурация default.conf, которая располагается
по пути /etc/nginx/conf.d/ Если установка администратором проведена в другое место (при установке не в контейнере) -
необходимо не забыть заменить в файле nginx.conf путь до конфигураций сайтов.
default.conf
upstream app_server {
# указываем правильный адрес
server vismind-backend:35115 max_fails=5 fail_timeout=5s;
# ребуется для оптимизации keep alive соединений
keepalive 50;
}
server { # подключение к бэкенду 80 и 443 порты
listen 80;
# listen 443 http2 ssl;
# ssl_certificate /etc/ssl/certs/ssl.crt;
# ssl_certificate_key /etc/ssl/private/ssl.key;
# устанавливать если меняется на доменное имя
# server_name my_server_name;
# Основное приложений
location / {
root /usr/share/nginx/html;
try_files $uri$args $uri$args/ $uri/ /index.html;
}
# Папка статики
location /static/ {
root /usr/share/nginx/media;
add_header Access-Control-Allow-Origin *;
# expires 1d; # VISMIND-6615
}
# Обратный прокси для бэкенда
location /api/ {
proxy_http_version 1.1;
proxy_set_header "Connection" "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
proxy_buffers 32 4k;
proxy_redirect $scheme://$host/api/v1/ $scheme://$http_host/api/;
# с бэкендом работа идет по http
proxy_pass http://app_server/api/v1/;
}
# Проброс сокетов
location /socket.io {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://app_server;
tcp_nodelay on;
keepalive_timeout 600;
}
# Ендпоинт для получения метрик приложения
location /metrics {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://app_server/metrics;
}
# Геосервер с кэшированием запросов
location ~ /tilecache/(?<fwd_path>.*) {
proxy_pass http://dev.int.bittechno.ru:3000/static/$fwd_path$is_args$args;
}
# Геосервер без кэширования, по сути прокси
location ~ /tileserver/(?<fwd_path>.*) {
proxy_pass http://dev.int.bittechno.ru:3000/dynamic/$fwd_path$is_args$args;
}
# 404 ошбка
#error_page 404 /404.html;
# перенаправление при ошибках 50х на /50x.html2
#error_page 500 502 503 504 /50x.html;
#location = /50x.html {
# root /usr/share/nginx/html;
#}
}
Прокси для относительных адресов геосервера
Дополнительная роль, которую может выполнять nginx - перенаправление запросов на геосервер в случае использования относительных адресов. Это необходимо для того, чтобы не переписывать адреса при переносе задач между разными окружениями.
Для этого в конфигурации задается location для кэшируемых и динамических тайлов. Тайловый сервер должен иметь свой
прокси с настроенным кэшированием по путям /static и /dynamic.
Пример location для reverse proxy
При использовании проброса запросов на геосервер они уходят на прокси геосервера, которая отвечает за кэширование и их перенаправления на сам геосервер.
Важно
При использовании этого варианта проксирования запросов нельзя изменять заголовки запросов, т.к. ответ геосервера содержит адрес по которому надо получать тайлы, а этот адрес формируется из заголовков запросов пришедших на геосервер.
Подробнее про прокси геосервера см. раздел Геосервер Martin
