[英]docker-compose nginx proxy_pass to upstream containers not behaving as expected
我正在嘗試使用一個基本的反向代理來處理基於 [本教程][1] 的多個網站,但將其調整為使用單個 docker-compose 文件和 proxy_pass 到上游容器。 這似乎是最簡潔的方法,因為它適用於我的學習/測試服務器,我將經常啟動和停止容器。 我想在開始添加更復雜的應用程序容器之前鎖定它。 我不確定我應該轉發端口的配置的哪一部分,因為大多數在線問題和教程都沒有使用上游容器。
編輯 - 默認服務器未在 443 上偵聽,修復此問題消除了一個混亂。 現在我只能從xxxx/
和來自xxxx/site1
或xxxx/site2
(或其他任何東西)的反向代理自定義 404 頁面獲取預期的 index.html
從我讀過,端口內部由碼頭工人,只要處理的容器鏈接(同泊塢窗網絡上),並且不需要甚至暴露聲明docker-compose.yml
,只要容器開始docker-compose up
我已經嘗試將自定義端口轉發到 docker-compose.yml 中的容器
ports:
- 8081:443
這在 nginx default.conf
upstream docker-site1 {
server website1-container:8081;
}
但這給了我502 Bad Gateway
我使用命名容器和外部網絡來保持名稱靜態,以保持容器間網絡與主機分離,並在這方面利用 Docker 功能。
我現在已經花了兩天時間,我真的需要一些指導來避免繞圈子!
編輯 - 仍在兜兜轉轉。 感謝 lmsec 更新了 default.conf,並將 /site1 添加到 docker-compose.yml 中的卷路徑
我的 docker-compose.yml(在頂級目錄中)已編輯 - 我最好的工作配置
version: '3.6'
services:
proxy:
build: ./proxy/
container_name: reverse-proxy
hostname: reverse-proxy
networks:
- public
- website1
- website2
ports:
- 80:80
- 443:443
site1_app:
build:
./site1/
volumes:
- ./site1/html:/usr/share/nginx/html/site1
container_name: website1-container
hostname: website1-container
networks:
- website1
site2_app:
build:
./site2/
volumes:
- ./site2/html:/usr/share/nginx/html/site2
container_name: website2-container
hostname: website2-container
networks:
- website2
networks:
public:
external: true
website1:
external: true
website2:
external: true
./proxy/ 中的 Dockerfile
FROM nginx:1.20-alpine
COPY ./default.conf /etc/nginx/conf.d/default.conf
COPY ./backend-not-found.html /var/www/html/backend-not-found.html
COPY ./index.html /var/www/html/index.html
# Proxy and SSL configurations
COPY ./includes/ /etc/nginx/includes/
# Proxy SSL certificates
COPY ./ssl/ /etc/ssl/certs/nginx/
網站 Dockerfiles 只包含FROM nginx:1.20-alpine
./proxy/編輯中的default.conf - 我最常用的配置,不鏈接 JS、CSS、圖像
# Default
server {
# listen on port 80 (http)
listen 80 default_server;
server_name _;
location / {
# redirect any requests to the same URL but on https
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2 default_server;
server_name _;
root /var/www/html;
charset UTF-8;
# Path for SSL config/key/certificate
ssl_certificate /etc/ssl/certs/nginx/proxy.crt;
ssl_certificate_key /etc/ssl/certs/nginx/proxy.key;
include /etc/nginx/includes/ssl.conf;
error_page 404 /backend-not-found.html;
location = /backend-not-found.html {
allow all;
}
location / {
index index.html;
}
location /site1 {
include /etc/nginx/includes/proxy.conf;
proxy_pass http://website1-container;
}
location /site2 {
include /etc/nginx/includes/proxy.conf;
proxy_pass http://website2-container;
}
access_log off;
log_not_found off;
error_log /var/log/nginx/error.log error;
}
./proxy/includes/ 中的 proxy.conf
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_intercept_errors on;
每個網站容器都有自己的網絡,它與代理容器共享。
{
"Name": "website1",
"Id": "9477470a8689d08776b38c4315882caff75573b7244f77091aa5e5438804ce36",
"Created": "2021-06-21T02:52:25.402118801Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.160.0/20",
"Gateway": "192.168.160.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"7c1a8b62864642afd5366ef88d762e4c5450eee02acb8c3f1890444b59379340": {
"Name": "website1-container",
"EndpointID": "f04d96343737574ca869270954461774f731851b781120119c21e02c0aa9968e",
"MacAddress": "02:42:c0:a8:a0:02",
"IPv4Address": "192.168.160.2/20",
"IPv6Address": ""
},
"a88326952fb5f25f9084eb038f22f56b7331032a5ba71848ea6ada677a2ed998": {
"Name": "reverse-proxy",
"EndpointID": "b0c97c7f8dfe0febddbd6668481a009cce0c4f20dae3c3d3280dad0069c90394",
"MacAddress": "02:42:c0:a8:a0:03",
"IPv4Address": "192.168.160.3/20",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
我可以通過這個網絡訪問網站容器,甚至可以使用 curl 獲取 index.html: sudo docker exec reverse-proxy curl 192.168.160.2/site1/index.html
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0<!DOCTYPE html>
<html>
<head>
<title>Site 1</title>
</head>
<body>
<h1>This is a sample "site1" response</h1>
</body>
</html>
100 142 100 142 0 0 20285 0 --:--:-- --:--:-- --:--:-- 23666
我將這個問題標記為關閉。 我得出的結論是,當使用 proxy_pass 到 docker 容器時,最新版本的 docker 不需要任何特殊的端口轉發,盡管如果需要,可以在 docker-compose 和 nginx default.conf 中完成 - 正如 lmsec 答案所解釋的那樣。
[..] 在配置的哪一部分中,我應該使用上游容器轉發端口[..]。
您可以在上游定義中執行此操作(摘自下面的nginx 文檔):
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com:8080;
# [..]
}
[..] 當我請求服務器的根 xxxx 時,我得到 website1,當我請求 xxxx/site1 時,我得到 404 錯誤。
您沒有為 https (443) 定義default_server
,因此第一個服務器用作443 的默認值。(不確定為什么會得到 404。)
從未得到網站的回應2
您需要請求site2
以從中獲得響應(因為server_name site2;
)。 出於測試目的,您可以將它放在您的主機文件中。
site1 127.0.0.1
site2 127.0.0.1
以下是使用 nginx-as-a-proxy 更快開始的其他一些關鍵:
server_name
就像一個請求過濾器;proxy_pass http://docker-site1/;
(帶有尾隨/
)以便/example
轉到http://docker-site1/example
,而不是http://docker-site1
;/site2
和/site3
)代理到不同的主機或上游。server {
# Filter requests having 'Host: site1' (ignore the others)
server_name site1;
location / {
# Send everything beginning with '/' to docker-site1
proxy_pass http://docker-site1/;
}
location /site2/ {
# Send everything beginning with '/site2/' to docker-site2
# removing the leading `/site2`
proxy_pass http://docker-site2/;
}
location /site3/ {
# Send everything beginning with '/site3/' to docker-site3
# keeping the leading `/site2`
proxy_pass http://docker-site3/site3/;
}
}
server {
# do something else if the requested Host is site2
server_name site2;
}
(當然?)這也可以在沒有upstream
情況下工作,在proxy_pass
使用服務器的地址而不是upstream
標識符。
編輯 -獎勵:Docker(-compose) 端口和網絡
site1_app:
ports:
- 8081:443
localhost:8081
(或xxxx:8081
)訪問site1_app
的 443 端口site1_app:443
* (或https://site1_app
)訪問site1_app
的 443 端口 (讓我們假設site1_app
也監聽端口 80):
site1_app
的 80 端口:它沒有被轉發(這里,只有 443 是)site1_app:80
* (或http://site1_app
)訪問site1_app
的 80 端口 *不確定這適用於docker-compose
的version: '2'
,但它適用於version: '3.9'
。
您編寫的以下幾行允許您調用website1_container
而不是site1_app
:
container_name: website1-container
hostname: website1-container
所以如果你這樣做:
# 3
upstream docker-site1 {
server website1-container:8081;
}
server {
# 1
listen 80;
listen 443 ssl http2;
server_name site1;
# [..] SSL config/key/certificate
location / {
# 2
proxy_pass http://docker-site1/;
}
假設您將請求標頭設置為Host: site1
(感謝您的hosts
文件或自己偽造請求標頭):
site1
塊http://docker-site1/
( http )docker-site1
被解析為只包含一台服務器的服務器組: website1-container:8081
site1_app
在其8081
端口(不是443
)上接收請求。site1_app
可能想HTTPS上的443
端口。所以你應該:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.