Я запускаю несколько док-контейнеров с именами хостов:
web1.local web2.local web3.local
Маршрутизация к ним выполняется на основе имени хоста nginx. У меня есть прокси-сервер перед этой настройкой (на другом компьютере, подключенном к Интернету), где я определяю восходящий поток как:
upstream main {
server web1.local:80;
server web2.local:80;
server web3.local:80;
}
И собственно описание виртуального хоста:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://main;
}
}
Теперь, поскольку контейнеры получают имя хоста «main» вместо «web1.local», они не отвечают на запрос должным образом.
Вопрос: как я могу указать nginx передать имя вышестоящего сервера вместо имени вышестоящей группы серверов в заголовке Host: при проксировании запроса?
На самом деле вы можете сделать это через proxy_set_header.
Подробнее смотрите здесь: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header или посмотрите пример использования здесь: https://stackoverflow.com/questions/12847771/configure-nginx-with-proxy-pass
Я включил динамический подход в вашу конфигурацию, опубликованную выше:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://main;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
Вот пример со статическим именем хоста:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://main;
proxy_set_header Host www.example.com;
proxy_set_header X-Forwarded-For $remote_addr;
}
}
У меня была та же проблема, и я наконец решил ее, используя два уровня прокси. Вот как вы могли бы поступить в своей ситуации (я думаю):
server {
listen 8001 default_server;
server_name web1.example.com;
location / {
proxy_pass http://web1.local:80;
proxy_set_header Host web1.local:80;
}
}
server {
listen 8002 default_server;
server_name web2.example.com;
location / {
proxy_pass http://web2.local:80;
proxy_set_header Host web2.local:80;
}
}
server {
listen 8003 default_server;
server_name web3.example.com;
location / {
proxy_pass http://web3.local:80;
proxy_set_header Host web3.local:80;
}
}
upstream main {
server 127.0.0.1:8001;
server 127.0.0.1:8002;
server 127.0.0.1:8003;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://main;
}
}
Как видите, фокус состоит в том, чтобы создать локальный сервер, отвечающий на определенный порт, который будет прокси-сервером, переписав правильный хост для каждого сервера. Затем вы можете использовать эти локальные серверы в своем восходящем потоке и, наконец, использовать его в реальном прокси.
Итак, прочитав всю документацию для nginx (я не мог действительно разобрать код для восходящего модуля = (), я придумал это ублюдочное решение. К сожалению, это решение не отслеживает отказавшие хосты, а просто выбирает случайный и перенаправляет запрос на него. Поэтому мне нужно настроить какой-то мониторинг, чтобы убедиться, что все серверы работают.
server {
listen 80;
server_name example.com;
resolver 127.0.0.1;
location / {
set $upstream "";
rewrite_by_lua '
local upstreams = {
"http://web1.dokku.localdomain",
"http://web2.dokku.localdomain",
"http://web3.dokku.localdomain",
"http://web4.dokku.localdomain"
}
ngx.var.upstream = upstreams[ math.random( #upstreams ) ]
';
proxy_pass $upstream;
}
}
Мы передаем восходящий адрес в виде отдельного заголовка, как этот
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://main;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
add_header X-Upstream $upstream_addr;
}
}
Что, если бы вы попробовали?
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://main;
proxy_set_header Host $upstream_addr;
proxy_set_header X-Forwarded-For $remote_addr;
add_header X-Host $host;
}
}
Хотя цель кажется логичной, nginx не собирается изменять заголовок Host: для соответствия восходящему потоку. Вместо этого лечит upstream
доменные имена, такие как CNAME
в DNS - как способ добраться до IP-адреса.
Заголовки (и тело) запроса фиксируются до выбора восходящего потока. Восходящий поток может изменить средний запрос, если он не отвечает, но запрос не меняется.
Хм. У меня аналогичная установка, в которой я просто сделал
location / {
...
proxy_set_header X-Forwarded-Host $http_host;
proxy_pass ...;
}
Использование $http_host
(заголовок HTTP Host из входящего запроса) здесь, а не $host
(конфигурация имени хоста сервера) в моем тестировании заставляет тот же заголовок Host, переданный клиентом, передается восходящему потоку.
Смотрите также https://stackoverflow.com/questions/14352690/change-host-header-in-nginx-reverse-proxy.
Поскольку другие люди уже писали с использованием переменной скрипта (например, $ upstream), вы можете установить ее так, как вам нравится, и это решит проблему без дополнительного взлома заголовка.
Переменные сценария угроз обработчика Proxy Pass по-другому: если значение не является условным (в имени нет $), оно передается в вышестоящий поток на этапе настройки и используется позже.
Простой способ опустить эту проблему и получить большинство преимуществ (бесплатной версии) апстрима - это использовать что-то вроде Split_Clients
:
split_clients $request_uri $my_upstream {
33% server1.domainX.com;
33% server2.domainX.com;
# Always use DOT at end entry if you wonder why, read the SC code.
* server3.domainX.com;
}
location / {
...
proxy_pass http://$my_upstream;
}
Приведенный выше пример выглядит почти так же, как и восходящий поток. Существуют другие модули, выполняющие отображение, т.е. chash_map_module, но поскольку они не входят в дерево, вам нужно будет построить их самостоятельно, что невозможно для некоторых случаев использования /