nginx如何配置将不同的位置转发到不同的本地端口?

How can nginx be configured to forward different locations to different local ports?

我是 运行 docker 上的 nginx,它目前正在为一个网页提供 SSL 假设 https://example.com 我现在创建了另一组提供自己的 Web 服务器的容器,它在本地端口 8080 上可用,我希望能够在 https://example.com/new_service

中访问它

我尝试在 /new_service/ 位置添加一个简单的 proxy_pass 但我收到 502 Bad Gateway 错误并且 nginx 日志显示以下内容:

2022/04/12 22:27:12 [error] 32#32: *19 connect() failed (111: Connection refused) while connecting to upstream, client:8.8.8.8, server: example.com, request: "GET /new_service HTTP/1.1", upstream: "http://127.0.0.1:8080/", host: "example.com"
2022/04/12 22:27:12 [warn] 32#32: *19 upstream server temporarily disabled while connecting to upstream, client: 8.8.8.8, server: example.com, request: "GET /new_service/ HTTP/1.1", upstream: "http://127.0.0.1:8080/", host: "example.com"
2022/04/12 22:27:12 [error] 32#32: *19 connect() failed (111: Connection refused) while connecting to upstream, client: 8.8.8.8, server: example.com, request: "GET /new_service/ HTTP/1.1", upstream: "http://127.0.0.1:8080/", host: "example.com"
2022/04/12 22:27:12 [warn] 32#32: *19 upstream server temporarily disabled while connecting to upstream, client: 8.8.8.8, server: example.com, request: "GET /new_service/ HTTP/1.1", upstream: "http://127.0.0.1:8080/", host: "example.com"
8.8.8.8 - - [12/Apr/2022:22:27:12 +0000] "GET /new_service/ HTTP/1.1" 502 157 "-" "My Browser" "-"

我当前的配置是:

server {
listen 443;
server_name example.com;
ssl_certificate /etc/nginx/certs/example.com/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/example.com/privkey.pem;
root /var/www/html/;
client_max_body_size 1000M; # set max upload size
fastcgi_buffers 64 4K;
index index.php;
error_page 403 /core/templates/403.php;
error_page 404 /core/templates/404.php;
add_header Strict-Transport-Security "max-age=15552000; includeSubdomains; ";

location = /robots.txt {
  allow all;
  log_not_found off;
  access_log off;
}

location ~ ^/(data|config|\.ht|db_structure\.xml|README) {
  deny all;
}

location ~ /(conf|bin|inc)/ {
    deny all;
}

location ~ /data/ {
    internal;
}

location /new_service/ {
  rewrite ^/new_service/?(.*) / break;
  proxy_pass http://localhost:8080/;
}

location / {
  rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
  rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json last;
  rewrite ^(/core/doc/[^\/]+/)$ /index.html;
  try_files $uri $uri/ index.php;
}

location ~ ^(.+?\.php)(/.*)?$ {
  try_files  = 404;
  include fastcgi_params;
  fastcgi_param SCRIPT_FILENAME $document_root;
  fastcgi_param PATH_INFO ;
  fastcgi_param HTTPS on;
  #fastcgi_pass 127.0.0.1:9000;
  fastcgi_pass php:9000;
  # Or use unix-socket with 'fastcgi_pass unix:/var/run/php5-fpm.sock;'
  #fastcgi_pass unix:/run/php/php7.3-fpm.sock;
}

location ~* ^.+\.(jpg|jpeg|gif|bmp|ico|png|css|js|swf)$ {
  expires 30d;
  # Optional: Don't log access to assets
  access_log off;
  }
}

我想使用 nginx 将多个位置定向到不同的本地容器一定是常见的做法,但我一直无法找到这方面的良好指导。非常感谢任何见解。

在我看来,新的 docker 容器不允许您通过它的防火墙,或者您没有将端口传递给主机

请提供 docker 配置以获得量身定制的答案。 猜测:如果你的容器不使用主机网络而是桥接网络(默认),localhost 指向 nginx 容器的本地主机而不是你的主机系统。

# Using bridge network, if omitted will be same behavior
services:
  service_name:
    ports:
      - "8080:8080" # Portmapping, maps from Container to HOST
    networks:
      network_name:
networks:
  network_name:

通过在主机上设置 nginx 运行 或使用 network_mode: "host" 可以访问您的服务 @ localhost:8080。但是,如果 nginx 在如上所述的容器中 运行,则 nginx 无法像那样访问此服务。 Inter-container-communication 正在使用自己的(虚拟)网络,每个容器都作为该网络中的“网络适配器”。因此有了自己的IP-Address。为了便于处理,还有一个 DNS-Server 运行,将网络别名解析为 IP。

因此使用proxy_pass http:\DNS-NAME:8080\proxy_pass http:\DOCKER-CONTAINER-IP:8080\到达docker网络内的容器。使用 docker inspect CONTAINER 确定:

...
 "NetworkSettings": {
"Networks": {
                "NAME": {
                   "Aliases": [
                        "c4675dda79be" # <-- this
                    ],
                    
                    "IPAddress": "172.18.0.2", # <-- or that
                 
                }

别名是DNS-Names,默认使用UID,进一步可以通过

设置
docker run --net-alias
docker network connect --alias
# docker-compose:
services:
  service_name: # <- this is used as an alias (=DNS-Name)
    networks:
      network_name:
        aliases:
          - alias1 # <- additional alias

由于奇怪的副作用和安全原因等原因,只要您的容器可以使用此网络隔离(默认情况下)而不是“host-mode”。因此,对于隐藏在 nginx 后面的服务,您根本不需要 port-mapping。因为它不需要在主机上发布(除了调试和开发),所以我们的服务更安全,因为 nginx 只是将东西转发到您允许的服务,而不是在给定端口上访问您的主机的所有内容。