Вопрос или проблема
Итак, мне поручено “модернизировать” приложение плейстоценовой эпохи, и я не могу заставить его работать. Позвольте объяснить:
У меня есть серия серверов Tomcat, каждый со следующей структурой:
(partner1 - tomcatServer1)
http://myServerIp1:8080/ -> индекс Tomcat
http://myServerIp1:8080/webapp1 -> webapp1 (основное)
http://myServerIp1:8080/webapp2 -> webapp2
(partner2 - tomcatServer2)
http://myServerIp2:8080/ -> индекс Tomcat
http://myServerIp2:8080/webapp1 -> webapp1 (основное)
http://myServerIp2:8080/webapp2 -> webapp2
http://myServerIp2:8080/webapp3 -> webapp3
Как вы видите, изначально я нахожу несколько очень заметных проблем.
- Во-первых, они используют публичный IP, что усложняет задачу
найти SSL-сертификат (но это будет решено позже). - Каждый сервер содержит несколько приложений.
Моя первоначальная идея для “модернизации” приложения заключалась в использовании домена и через выделенный сервер nginx реализовать реверс-прокси, который бы использовал следующую структуру:
(partner1 - tomcatServer1)
http://partner1.myDomain.com/ -> webapp1 (основное)
http://partner1.myDomain.com/webapp2 -> webapp2
(partner2 - tomcatServer2)
http://partner2.myDomain.com/ -> webapp1 (основное)
http://partner2.myDomain.com/webapp2 -> webapp2
http://partner2.myDomain.com/webapp3 -> webapp3
И как только это будет достигнуто, я начну разбираться с использованием SSL. Я говорю это и делаю на это особый акцент, потому что не хочу начинать с SSL, не проверив сначала, что это работает без него, потому что я не могу даже сделать хороший proxy_pass на индекс Tomcat, так как он загружает только текст без изображений. Если бы я сделал редирект, проблем бы не было, но идея состоит в том, чтобы клиент перестал использовать IP и наконец имел серьезный домен.
Конечно, я не только попробовал с индексом Tomcat, до этого я пробовал начать напрямую с webapp1 и обнаружил, что ошибки не было… но он ничего не показывал. Увидев это, я пошел посмотреть на индекс и понял, что он тоже не загружался должным образом.
Сначала я думал, что проблему можно решить, создав виртуальный хост в Tomcat для каждого webapp, потому что я считал, что проблема была грубой и сделал прямой proxy_pass на http://myServerIp1:8080/webapp1/, но после настройки виртуального хоста Tomcat результат был тот же – полностью белая страница.
Мне нужна помощь, и я думаю, что лучший способ начать – это начать с самого начала. Давайте посмотрим, сможете ли вы помочь мне правильно загрузить индекс Tomcat.
Для этого я оставляю конфигурацию Tomcat на данный момент без виртуальных хостов, и это будет конфигурация nginx для индекса Tomcat на http://partner1.myDomain.com/ (позже, если это будет загружено хорошо, я начну тестировать с приложениями)
server {
listen 80 default_server;
listen [::]:80 default_server;
index index.html index.htm index.nginx-debian.html;
server_name partner1.myDomain.com;
location / {
proxy_pass http://myServerIp1:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
try_files $uri $uri/ =404;
}
}
Как вы видите, это небольшая модификация файла по умолчанию nginx в Debian.
Если я проверю инструменты разработки браузера, я могу увидеть, что у него есть проблемы с загрузкой элементов, таких как “tomcat.css, favicon.ico…”.
У вас ситуация, аналогичная этому вопросу. Tomcat не знает, что он используется через прокси, и сгенерированные абсолютные URL начинаются с http://myServerIp:8080
.
Вам нужно добавить RemoteIpValve в <Host>
:
<Valve className="org.apache.catalina.valves.RemoteIpValve"
protocolHeader="X-Forwarded-Proto" />
и установите requestAttributesEnabled=true
в вашем AccessLogValve
(чтобы логи содержали реальные IP-адреса).
NGINX нужно будет отправлять на Tomcat заголовки Host
, X-Forwarded-For
и X-Forwarded-Proto
:
proxy_set_header Host $server_name;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
(заголовок X-Real-IP
уже содержится в X-Forwarded-For
).
После изменения конфигурации приложения, работающие на Tomcat, будут вести себя так, как если бы Tomcat работал на partner1.example.com:80
. Более того, когда вы переключитесь на HTTPS
, Tomcat поймет, что запрос поступил с защищенного канала, и будет генерировать ссылки вида https://
.
Редактировать: В вашей обновленной конфигурации вы изменяете абсолютный путь проксированных страниц с /myWebapp/
на /
. Я советую этого не делать: Tomcat устанавливает путь cookie для JSESSIONID
в путь контекста /myWebapp/
, поэтому веб-браузер никогда не отправляет cookie обратно. Используйте вместо этого такую конфигурацию:
location = / {
return 301 http://partner1.example.com/myWebapp/;
}
location / {
proxy_pass http://myServerIp:8080;
include nginxconfig.io/proxy.conf;
}
которая перенаправляет клиентов с /
на /myWebapp/
, но в остальном сохраняет пути нетронутыми.
Примечание: myDomain.com
– это действительный домен, принадлежащий кому-то, поэтому лучше использовать домены, зарезервированные для документации в вопросах и ответах.
Мне наконец удалось достичь этого, не касаясь Tomcat, фактически я смог увидеть приложение таким образом:
http://myServerIp.8080/myWebapp/ –>
http://partner1.myDomain.com/
Но затем я столкнулся с другой проблемой.
Сразу после запуска приложения jsessionid не сохраняется и обновляется при каждом запросе. Я пробовал решения, такие как:
Добавить samesite в cookies, используя nginx в качестве реверс-прокси
Использование nginx в качестве реверс-прокси для tomcat приводит к новым jsessionid для каждого запроса SSL
https://stackoverflow.com/questions/53542525/nginx-how-to-take-value-from-header-and-set-it-into-cookie
и теперь я попробовал модифицировать Tomcat, как вы рекомендуете. Однако Jsessionid продолжает изменяться, мне удается войти в приложение, но когда я делаю этот запрос, он снова изменяется, и когда я вхожу в приложение, все рушится и меня отображает как неавторизованного.
Это будет моя конфигурация
---------------
-----nginx.conf
---------------
user www-data;
pid /run/nginx.pid;
worker_processes auto;
worker_rlimit_nofile 65535;
events {
multi_accept on;
worker_connections 65535;
}
http {
charset utf-8;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
server_tokens off;
log_not_found off;
types_hash_max_size 2048;
client_max_body_size 16M;
# MIME
include mime.types;
default_type application/octet-stream;
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log warn;
# Load configs
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
---------------
-----General
---------------
# favicon.ico
location = /favicon.ico {
log_not_found off;
access_log off;
}
# robots.txt
location = /robots.txt {
log_not_found off;
access_log off;
}
# gzip
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;
---------------
-----Proxy
---------------
proxy_http_version 1.1;
proxy_cache_bypass $http_upgrade;
# Proxy headers
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_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
# Proxy timeouts
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
---------------
-----webapp
---------------
server {
listen 80;
listen [::]:80;
server_name partner1.myDomain.com;
# logging
access_log /var/log/nginx/partner1.myDomain.com.access.log;
error_log /var/log/nginx/partner1.myDomain.com.error.log warn;
# reverse proxy
location / {
proxy_pass http://myServerIp.8080/myWebapp/;
include nginxconfig.io/proxy.conf;
}
# additional config
include nginxconfig.io/general.conf;
}
Ответ или решение
Конфигурация nginx в качестве обратного прокси для серверов Tomcat – это задача, которая требует стратегического подхода из-за особенностей работы обоих серверов. Рассмотрим, как можно выполнить эту задачу, учитывая описанную структуру серверов и приложений.
Теория
-
Обратный прокси: nginx выступает в роли посредника между пользователями и Tomcat-серверами, перенаправляя запросы к соответствующим приложениям на Tomcat. Такая архитектура обеспечивает дополнительную безопасность и позволяет использовать дружественные для пользователя доменные имена вместо IP-адресов.
-
Проблемы с абсолютными URL и кэшированием: Когда Tomcat работает за обратным прокси, он может не осознавать, что конечный пользователь использует другой домен или протокол, например, HTTPS. Это может вызвать проблемы с формированием URL, приводя к неправильной загрузке ресурсов. Для решения этой проблемы важно правильно передавать заголовки, такие как
Host
,X-Forwarded-For
иX-Forwarded-Proto
. -
Управление сессиями: Неправильная настройка прокси может привести к тому, что каждый запрос будет создаваться с новой сессией, как указано в случае с
JSESSIONID
. Это вызвано тем, что Tomcat может не сохранять куки сессий, если путь или домен установлен неправильно.
Пример
Давайте рассмотрим, как можно настроить nginx с учетом этих моментов.
-
Настройка nginx:
server { listen 80; server_name partner1.myDomain.com; location / { proxy_pass http://myServerIp1:8080/webapp1/; 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_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; # Proxy timeouts proxy_connect_timeout 60s; proxy_send_timeout 60s; proxy_read_timeout 60s; } }
-
Конфигурация Tomcat:
В файле
server.xml
добавьтеRemoteIpValve
для корректной обработки заголовков:<Valve className="org.apache.catalina.valves.RemoteIpValve" protocolHeader="X-Forwarded-Proto" remoteIpHeader="X-Forwarded-For" internalProxies="192\.168\.\d{1,3}\.\d{1,3}" />
Это обеспечивает корректное восприятие протоколов или доменов, указанных пользователем.
Применение
-
Настройте заголовки: Убедитесь, что nginx правильно пересылает необходимые заголовки. Это позволяет Tomcat корректно обрабатывать запросы как будто они идут непосредственно к нему.
-
Проверка конфигурации: Убедитесь, что абсолютные URL, генерируемые вашим приложением, корректны и ведут к страницам без указания порта Tomcat. Это можно проверить в браузере, используя инструменты разработчика.
-
Устойчивость и безопасность: После проверки работоспособности перейдите к конфигурированию SSL, что повысит безопасность соединений. Используйте сертификаты, чтобы настроить HTTPS для доменов, что укрепит доверие пользователей и повысит защиту данных.
Следуя вышеописанным шагам, вы сможете успешно настроить nginx как обратный прокси для ваших серверов Tomcat, обеспечив стабильную и безопасную работу приложений. Если после выполнения настроек остаются проблемы с сессиями, убедитесь, что пути и домены установлены правильно, и изучите возможность добавления заголовков для управления "cookie".