Nginx перезаписывает на докер-машине, когда порт хоста != порт контейнера

Я пытаюсь запустить несколько контейнеров docker, все из которых работают под управлением nginx, прослушивающего порт 80, но с разными портами хоста, сопоставленными с портом 80 контейнеров.

По большей части это работает, за исключением случаев, когда nginx выполняет перенаправление из-за отсутствия завершающей косой черты.

server {    listen 80;    root /var/www;    index index.html;    location /docs {}}

Учитывая приведенную выше конфигурацию nginx и контейнер docker, запускающий его с портом хоста 8080, сопоставленным с портом контейнера 80, я могу получить localhost: 8080 / docs / через curl ok:

> GET /docs/ HTTP/1.1> User-Agent: curl/7.35.0> Host: localhost:8080> Accept: */*>< HTTP/1.1 200 OK* Server nginx/1.9.5 is not blacklisted< Server: nginx/1.9.5< Date: Sat, 28 Nov 2015 17:27:05 GMT< Content-Type: text/html< Content-Length: 6431< Last-Modified: Sat, 28 Nov 2015 17:17:06 GMT< Connection: keep-alive< ETag: "5659e192-191f"< Accept-Ranges: bytes<... html page ...

но если я запрашиваю localhost:8080/docs, я получаю перенаправление на localhost/docs/

> GET /docs HTTP/1.1> User-Agent: curl/7.35.0> Host: localhost:8080> Accept: */*>< HTTP/1.1 301 Moved Permanently* Server nginx/1.9.5 is not blacklisted< Server: nginx/1.9.5< Date: Sat, 28 Nov 2015 17:29:40 GMT< Content-Type: text/html< Content-Length: 184< Location: http://localhost/docs/< Connection: keep-alive<... html redirect page ...

Как я могу заставить nginx сохранить исходный порт при выполнении перенаправления? Я пробовал просматривать port_in_redirect и server_name_in_redirect, но они не помогли.


РЕДАКТИРОВАТЬ

Основанный на https://forum.nginx.org/read.php?2 ,261216,261216#msg-261216 прямо сейчас это кажется невозможным.

HTTP-клиенты поместят порт в заголовок хоста. Если вы используете исходное значение заголовка узла при выполнении перенаправления, оно должно работать так, как ожидалось. Я протестировал следующий код и, похоже, делаю именно то, что вы просили:

location ~ ^.*[^/]$ {    try_files $uri @rewrite;}location @rewrite {    return 302 $scheme://$http_host$uri/;}

> GET /bla HTTP/1.1> User-Agent: curl/7.29.0> Host: localhost:8080> Accept: */*>< HTTP/1.1 302 Moved Temporarily< Server: nginx/1.9.7< Date: Sun, 29 Nov 2015 06:23:35 GMT< Content-Type: text/html< Content-Length: 160< Connection: keep-alive< Location: http://localhost:8080/bla/

Самым простым решением является удаление index директива и не полагаться на явные или неявные $uri/ перенаправляет. Например:

server {  listen 80;  root /var/www;  location /docs {    try_files $uri $uri/index.html =404;  }}

Это не идентичное поведение, поскольку оно полностью позволяет избежать перенаправления. Если вы хотели перенаправить конечную косую черту, как это дает модуль index, то требуется более сложное решение. Например:

server {  listen 80;  root /var/www;  location /docs {    try_files $uri @redirect;  }  location @redirect {    if ($uri ~* ^(.+)/$) { rewrite ^ $uri/index.html last; }    if (-d $document_root$uri) { return $scheme://$host:8080$uri/; }    return 404;  }}

Просто следуйте этому простому исправлению

location /app {    alias /usr/share/nginx/html/folder;    if (-d $request_filename) {        rewrite [^/]$ $scheme://$http_host$uri/ permanent;    }}

Интересный... Я столкнулся именно с этой проблемой и смог исправить ее так же, как Ответ Ричарда Смита предполагает:

root /var/www;location = /docs {    try_files $uri $uri/ =404;}

Единственная разница в том, что я не указываю index.html?

Укажите код ошибки, чтобы избежать цикла перенаправления.

Все еще жду обратной связи от службы поддержки nginx.

Я думаю, это происходит потому, что ваш Docker является своего рода NAT / прокси-сервером для вашего контейнера nginx. Для маршрутизации между различными портами требуется дополнительная информация.

Для меня это было решено, добавив следующее в nginx.conf

http {    ...    proxy_set_header Host $http_host; # required for docker client's sake    proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;    proxy_set_header X-Forwarded-Proto $scheme;    ...}

Акк, только что тоже столкнулся с этой проблемой. Я думаю, мне придется перейти на ванильный nginx или перенести материал с 8080 на что-то другое.

Загляните в nginx-proxy контейнер, так что вам не нужно делать ничего из этого безумного мусора для перезаписи портов.

Я действительно не хочу, чтобы что-то балансировало перед этими контейнерами. У меня есть файл docker-compose, который устанавливает внешний порт на основе env var, и большую часть времени я просто “docker-compose up -d” этот файл один раз. Однако по соображениям тестирования и для того, чтобы я мог работать над другими вещами, я хочу иметь возможность выполнять “PORT = 8080 docker-compose -p test up -d”, чтобы развернуть совершенно новый набор контейнеров (из-за нового названия проекта), которые сопоставлены с другим портом хоста.