Как настроить NGINX для маршрутизации внешних запросов к моим докер-хостам stage и production

Как настроить NGINX для маршрутизации внешних запросов на мои докер-хосты stage и production

У меня есть 2 FQDN stage.external.example.net и external.example.net, которые разрешаются в один и тот же внешний публичный IP-адрес, например, 140.240.40. 111 (настроен на внешнем DNS)

HTTPS запросы к этому IP (например, GET https://stage.external.example.net) затем направляются на мой NGINX сервер, который имеет одну ногу в DMZ, например, 172.20.180.111 и другую во внутреннюю сеть, например, 10.222.20. 1/16, на котором у меня есть 2 докер-хоста, которые разрешаются внутри следующим образом:

  • stage.internal.example.net => 10.222.20.14
  • internal.example.net => 10.222.20.15

Я пытаюсь настроить мой NGINX на маршрутизацию:

  • внешний запрос stage.external.example. net:443 на внутренний stage.internal.example.net:443
  • внешний запрос external.example.net:443 на внутренний internal.example.net:443
stage.external.example.net:443 -> 140.240.40.111:443 -> 172.20.180.111:443 (NGINX) -> 10.222.20.14:443 (stage.internal.example.net)

external.example.net:443 -> 140.240.40.111:443 -> 172.20.180.111:443 (NGINX) -> 10.222.20.15:443 (internal.example.net)

Я вижу, что запросы попадают на мой NGINX в access.log, но затем запрос, похоже, не направляется на мои докер-хосты.

Ниже приведена конфигурация, которую я пробовал, любые указания приветствуются:

nginx. conf

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

include /usr/share/nginx/modules/*.conf;

events {
  worker_connections 1024;
}

http {
  log_format main '$remote_addr - $remote_user [$time_local] '
                  '"$request" $status $body_bytes_sent '
                  '"$http_referer" "$http_user_agent"';

  access_log /var/log/nginx/access.log main;
  error_log /var/log/nginx/error.log warn; 

  sendfile            on;
  tcp_nopush          on;
  tcp_nodelay         on;
  keepalive_timeout   65;
  types_hash_max_size 2048;

  include             /etc/nginx/mime.types;
  default_type        application/octet-stream;

  include /etc/nginx/conf.d/*.conf;

  upstream internal_stage {
    server 10.222.20.14:443; # docker host stage.internal.example.net
  }

  upstream internal_production {
    server 10.222.20.15:443; # docker host internal.example.net 
  }

  # Forward all requests to stage.external.example.net:443
  server {
    listen 443;
    server_name stage.external.example.net;
    location / {
      proxy_pass http://internal_stage;
    }
  }

 
  # Forward all requests to external.example.net:443
  server {
    listen 443;
    server_name external.example.net;
    location / {
      proxy_pass http://internal_production;
    }
  }
}

UPDATE: Change error_log to info

Теперь я могу наблюдать, что получаю 400 Bad Request Client sent invalid request while reading client request line

-1
задан 7 May 2021 в 09:58
3 ответа

РЕШЕНО с помощью stream блока и ssl_preread

nginx.conf

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

include /usr/share/nginx/modules/*.conf;

events {
  worker_connections 1024;
}

http {
  log_format main '$remote_addr - $remote_user [$time_local] '
                  '"$request" $status $body_bytes_sent '
                  '"$http_referer" "$http_user_agent"';

  access_log /var/log/nginx/access.service-api.log main;
  error_log /var/log/nginx/error.service-api.log info;

  sendfile            on;
  tcp_nopush          on;
  tcp_nodelay         on;
  keepalive_timeout   65;
  types_hash_max_size 2048;

  include             /etc/nginx/mime.types;
  default_type        application/octet-stream;

  include /etc/nginx/conf.d/*.conf;
}

include /etc/nginx/passthrough.conf;

passthrough.conf

stream {
  log_format basic '$remote_addr [$time_local] '
                 '$protocol $status $bytes_sent $bytes_received '
                 '$session_time "$upstream_addr" '
                 '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';

  access_log /var/log/nginx/access.log basic;
  error_log  /var/log/nginx/error.log;

  upstream internal_stage {
    server 10.222.20.14:443 max_fails=5 fail_timeout=300; # docker host stage.internal.domain.net
  }

  upstream internal_production {
    server 10.222.20.15:443 max_fails=5 fail_timeout=300; # docker host stage.internal.domain.net 
  }

  map $ssl_preread_server_name $upstream {
    stage.external.polylabs.net internal_stage;
    external.polylabs.net internal_production;
  }

  server {
    listen 443;
    proxy_pass $upstream;
    ssl_preread on;
    proxy_next_upstream on;        
  }
}
0
ответ дан 7 May 2021 в 21:06

Похоже, в вашем вопросе вы объединяете порт 443 с HTTPS. Если вы имеете в виду HTTP с шифрованием на порту 443, то это просто https, но имя хоста: 443 ничего не говорит нам ни о протоколе, ни о том, есть ли шифрование. Возможная причина для отклонения вопроса.

Когда вы используете «proxy_pass», nginx перенаправляет HTTP-запрос на указанный адрес, но HTTP явно поддерживает мультиплексирование разных (виртуальных) имен хостов на одном IP-адресе.Стоит упомянуть, что существует другой дополнительный метод, реализованный в TLS для мультиплексирования имени хоста (SNI), и здесь предоставленная вами конфигурация конфликтует с тем, что я считаю вашей целью; подключение к https на сервере. Ваша конфигурация подключается к http. Еще одна причина, по которой кто-то отклонил ваш вопрос. Однако директива proxy_pass Nginx будет обрабатывать перезапись подтверждения SNI автоматически, так что это не причина ваших текущих проблем.

При этом, если вы явно не укажете Nginx не делать этого, он проверит сертификат, предоставленный внутренним сервером. Использует ли он сертификат, который должен быть проверен nginx? Вы можете проверить это на хосте nginx с помощью openssl s_client.

похоже, что запрос не перенаправляется на мои докеры.

Как вы пришли к такому выводу? (отсутствие обоснования этого может быть еще одной причиной отклонения вашего вопроса).

Это может быть так, но даже если запросы перенаправляются на предполагаемый IP-адрес / порт, они приведут к ошибке, если этот бэкэнд не считает себя исходным сервером для "stage.external.domain.net ".

Безусловно, самое простое решение - сообщить внутреннему веб-серверу, что это действительно "stage.external.domain.net". Но можно и запрос переписать ....

    server_name external.polylabs.net;
    location / {
      proxy_set_header Host "internal.polylabs.net";
      proxy_ssl_verify off;
      proxy_pass https://internal.polylabs.net;
    }
-1
ответ дан 7 May 2021 в 21:06

кажется, что серверная часть - это https, поэтому proxy_pass должен быть https, как показано ниже: location / upstream { proxy_pass https://backend.example.com; } Пожалуйста, проверьте ссылку ниже: { {1}} https://docs.nginx.com/nginx/admin-guide/security-controls/securing-http-traffic-upstream/

1
ответ дан 7 May 2021 в 21:06

Теги

Похожие вопросы