nginx обратный прокси - как обслуживать несколько приложений - PullRequest
2 голосов
/ 10 июля 2020

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

/etc/nginx/sites-enabled/reverse-proxy.conf

server {
        listen 80;
        listen [::]:80;
        location  / {

        resolver 127.0.0.1;
        allow "x.x.x.x";
        deny   all;
        proxy_pass http://consul:8500;
    }

}

Поэтому, когда я вызываю IP-адрес сервера x.x.x.x в моем браузере, я вижу пользовательский интерфейс Consul и отображаемый URL-адрес x.x.x.x/ui/dc1. Кроме того, я вижу, что пользовательский интерфейс успешно выполнил запросы файлов ресурсов.

Мой вопрос; Возможно ли, что на одном сервере размещены две разные службы, и они просто ссылаются на них с разных мест? Например, если я хочу включить пользовательский интерфейс Vault, я бы подумал о том, чтобы сделать что-то вроде этого:

server {
        listen 80;
        listen [::]:80;
        location  /consul {

        resolver 127.0.0.1;
        allow "x.x.x.x";
        deny   all;
        proxy_pass http://consul:8500;
    }

        location  /vault {

        resolver 127.0.0.1;
        allow "x.x.x.x";
        deny   all;
        proxy_pass http://vault:8200;
    }

}

Однако я не уверен, можно ли это сделать таким образом. Самое дальнее, что я получил, - это открыть пользовательский интерфейс Consul, когда все другие подзапросы не найдены (например, загрузка ресурсов).

ОБНОВЛЕНИЕ

Думаю, моя проблема в том, что я ошибочно использую location и proxy_pass

, наблюдая за первой конфигурацией (которая работает)

server {
        listen 80;
        listen [::]:80;
        location  / {

        resolver 127.0.0.1;
        allow "x.x.x.x";
        deny   all;
        proxy_pass http://consul:8500;
    }

}

Если я посмотрю на команду curl curl localhost -L -vvvv

*   Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 301 Moved Permanently
< Server: nginx/1.18.0 (Ubuntu)
< Date: Fri, 10 Jul 2020 16:24:38 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 39
< Connection: keep-alive
< Location: /ui/
< 
* Ignoring the response-body
* Connection #0 to host localhost left intact
* Issue another request to this URL: 'http://localhost/ui/'
* Found bundle for host localhost: 0x557b754549e0 [serially]
* Can not multiplex, even if we wanted to!
* Re-using existing connection! (#0) with host localhost
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /ui/ HTTP/1.1
> Host: localhost
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.18.0 (Ubuntu)
< Date: Fri, 10 Jul 2020 16:24:38 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 7806
< Connection: keep-alive
< Accept-Ranges: bytes
< Last-Modified: Fri, 10 Jul 2020 07:37:44 GMT
< 
<!DOCTYPE html>
<html lang="en" class="ember-loading">
...

, я уже вижу html. Однако, если я изменил файл conf на это:

server {
        listen 80;
        listen [::]:80;
        location  /consul/ {

        resolver 127.0.0.1;
        allow "x.x.x.x";
        deny   all;
        proxy_pass http://consul:8500;
    }

}

, а затем попробую назвать его как curl localhost/consul -L -vvvv, я получу следующее:

*   Trying 127.0.0.1:80...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /consul HTTP/1.1
> Host: localhost
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 301 Moved Permanently
< Server: nginx/1.18.0 (Ubuntu)
< Date: Fri, 10 Jul 2020 16:32:35 GMT
< Content-Type: text/html
< Content-Length: 178
< Location: http://localhost/consul/
< Connection: keep-alive
< 
* Ignoring the response-body
* Connection #0 to host localhost left intact
* Issue another request to this URL: 'http://localhost/consul/'
* Found bundle for host localhost: 0x55ba7959f9e0 [serially]
* Can not multiplex, even if we wanted to!
* Re-using existing connection! (#0) with host localhost
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET /consul/ HTTP/1.1
> Host: localhost
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Server: nginx/1.18.0 (Ubuntu)
< Date: Fri, 10 Jul 2020 16:32:35 GMT
< Content-Length: 0
< Connection: keep-alive

Буду признателен за любые идеи по этому вопросу

1 Ответ

1 голос
/ 10 июля 2020

Вы правы, вы неправильно используете location и proxy_pass. Когда вы используете конструкцию

location /vault {
    proxy_pass http://vault:8200;
}

, вы передаете свой URI восходящему потоку как есть, хотя, скорее всего, вы хотите удалить из него префикс /vault. Для этого вы должны использовать этот:

location /vault/ {
    proxy_pass http://vault:8200/;
}

Подробнее о различиях первого и второго можно прочитать здесь . Однако это по-прежнему может помешать правильной загрузке ресурсов.

Этот вопрос - как проксировать некоторые веб-приложения под некоторым префиксом URI - снова и снова задают в stackoverflow. Единственный правильный способ сделать это - заставить ваше проксируемое приложение запрашивать свои ресурсы только через относительные URL-адреса (рассмотрите assets/script.js вместо /assets/script.js) или используя правильный префикс (/vault/assets/script.js). Некоторые хорошо написанные приложения могут определять, используются ли они с таким префиксом URI, и использовать его, когда создается ссылка на ресурс, некоторые приложения позволяют указывать его с помощью некоторых настроек, но некоторые вообще не подходят для такого использования . Причина, по которой веб-приложение не будет работать без выполнения этих требований, совершенно очевидна - любой URL-адрес, не начинающийся с /vault, не будет соответствовать вашему блоку location /vault/ { ... } и будет обслуживаться через основной блок location. Поэтому лучший способ сделать это - исправить ваше веб-приложение, однако, если вы действительно не можете этого сделать, можно использовать несколько обходных путей.

  • Некоторые веб-фреймворки уже создают свои веб-приложения с относительными URL-адресами, но используют <base href="/"> в головной части index.html. Например, React или Angular используют этот подход. Если в вашем веб-приложении есть такая строка root index.html, просто измените ее на <base href="/vault/">.

  • Использование условной маршрутизации на основе значения заголовка HTTP Referer. Этот подход работает довольно хорошо для одностраничных приложений для загрузки ресурсов, но если веб-приложение содержит несколько страниц, этот подход не сработает, лог c для правильного восходящего обнаружения сломается после первого перехода с одной страницы на другую. Вот пример:

    map $http_referer $prefix {
        ~https?://[^/]+/vault/     vault;
        # other webapps prefixes could be defined here
        # ...
        default                    base;
    }
    
    server {
    
        # listen port, server name and other global definitions here
        # ...
    
        location / {
            # "unconditional" jump-to-location idea taken from this answer:
            # https://serverfault.com/questions/908086/nginx-directly-send-from-location-to-another-named-location/965779#965779
            try_files /dev/null @$prefix;
        }
        location /vault/ {
            # proxy request to the vault upstream, remove "/vault" part from the URI
            proxy_pass http://vault:8200/;
        }
        location @vault {
            # proxy request to the vault upstream, do not change the URI
            proxy_pass http://vault:8200;
        }
        location @base {
            # default "root" location
            proxy_pass http://consul:8500;
        }
    
    }
    
  • Перезапись ссылок внутри тела ответа с помощью директивы sub_filter из ngx_http_sub_module. Это самый уродливый вариант, но его все же можно использовать как последний доступный вариант. Такой подход оказывает очевидное влияние на производительность. Шаблоны перезаписи следует определять на основании вашего основного ответа. Обычно такая конфигурация выглядела как

    location /vault/ {
        proxy_pass http://vault:8200/;
        sub_filter_types text/css application/javascript;
        sub_filter_once off;
        sub_filter 'href="/' 'href="/vault/';
        sub_filter "href='/" "href='/vault/";
        sub_filter 'src="/'  'src="/vault/';
        sub_filter "src='/"  "src='/vault/";
        sub_filter 'url("/'  'url("/vault/';
        sub_filter "url('/"  "url('/vault/";
        sub_filter "url(/"   "url(/vault/";
    }
    
...