帶有 poste.io 郵件伺服器的 docker nginx 代理
我想知道是否有可能,如果可以,我將如何在一台專用伺服器上同時執行 nginx-proxy 和 poste.io 郵件伺服器?
我可以分別執行兩者,但是當我嘗試同時執行它們時,它說我不能執行後一個容器,因為埠 443 已經被另一個容器使用。
現在,當我只使用我的 nginx 反向代理時,我會在我的伺服器上執行多個網站,所有這些網站都公開埠 80 和 443 以及代理本身,這讓我有點困惑,為什麼我不能執行另一個容器做同樣的事情(是的,我知道通常 2 個程序不應該在沒有一些擺弄的情況下使用同一個埠)。
我使用以下代理:https ://github.com/jwilder/nginx-proxy
我使用https://poste.io作為我的郵件伺服器
這是我在伺服器上執行的一個網站 docker-compose 的範例。
application: build: code volumes: - /websites/domain:/var/www/laravel - /docker/webs/domain/logs:/var/www/laravel/storage/logs tty: true redis: image: redis:alpine db: image: mariadb:10.2 environment: MYSQL_ROOT_PASSWORD: toor MYSQL_DATABASE: laravel TEST_DB_NAME: laravel_test MYSQL_USER: laravel MYSQL_PASSWORD: laravel php: build: php7-fpm volumes_from: - application links: - db - redis nginx: build: nginx links: - php volumes_from: - application - nginx-proxy volumes: - ./logs/nginx/:/var/log/nginx environment: - VIRTUAL_HOST=www.domain.com
在我的 nginx 的 Dockerfile 中,我公開了埠 80 和 443
FROM debian:jessie MAINTAINER Purinda Gunasekara <purinda@gmail.com> RUN apt-get update && apt-get install -y \ nginx ADD nginx.conf /etc/nginx/ ADD *.conf /etc/nginx/sites-enabled/ RUN rm /etc/nginx/sites-enabled/default RUN rm /etc/nginx/sites-enabled/nginx.conf # remove the https for local development #RUN rm /etc/nginx/sites-enabled/*.ssl.conf RUN echo "upstream php-upstream { server php:9000; }" > /etc/nginx/conf.d/upstream.conf RUN usermod -u 1000 www-data CMD ["nginx"] EXPOSE 80 EXPOSE 443
所以這就是讓我感到困惑的原因。為什麼 docker 允許我的網站執行(即使 nginx 代理已經在埠 80 和 443 上執行)沒有問題。但是當我嘗試執行我的郵件伺服器時,它是否正在考慮埠 443 已經在使用中?
這是docker發布的實際錯誤
docker: Error response from daemon: driver failed programming external connectivity on endpoint nginx_proxy <containerID>: Bind for 0.0.0.0:443 failed: port is already allocated.
理想情況下,我將能夠在一台伺服器上同時執行此郵件伺服器和我的網站,這是因為只有一小部分網站將被託管,並且預計不會在短時間內增長太多。
更新
這些網站使用來自 nginx-proxy 的捲,因此為什麼它們可以在自己暴露埠 80 和 443 的同時執行在它旁邊,但是當我嘗試將相同卷的 nginx-proxy 與郵件伺服器連結時,我一直收到相同的錯誤正在使用的埠。
如果一個 docker 容器已經綁定到您的一個介面 IP 上的埠 443(或 0.0.0.0 表示所有介面),則其他 docker 容器不能綁定到同一個 IP。使用 netstat 檢查,當一個 1 容器啟動時:
sudo netstat -nalp64 | grep 443 tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 26547/docker-proxy
由於 0.0.0.0 上的 443 埠已被 docker 容器使用,因此新容器無法綁定到該 IP+埠。
視覺化
0.0.0.0:443 (Error: Port 443 already in use) | \ +--------------+ +--------------+ | CONTAINER | | CONTAINER | | 172.0.0.2 | | 172.0.0.3 | +--------------+ +--------------+
您不需要將多個容器綁定到同一個埠,而是需要將一些軟體綁定到埠,將連接重定向到適當的容器。
這很容易通過執行專用的反向代理來完成,這是唯一綁定到埠 (443) 的程序。反向代理的目的是根據請求的 HTTP 主機轉發傳入連接。
反向代理可以在執行 docker 的物理主機上執行,也可以在 docker 容器內執行。
反向代理也可以終止 SSL 連接,這意味著這個 nginx 實例處理所有與客戶端的加密/解密,而與後端(容器)的連接是未加密的。
我認為這不是絕對必要的,現代瀏覽器支持 SNI,因此 nginx 仍然可以將請求轉發到適當的後端,而無需解密所有流量。但是使用中央 SSL 終止,您只需要在一個地方提供證書,並且對於大多數案例,SSL 只需全域配置一次。
為了設置這樣一個帶有 SSL 終止的反向代理
- 在 docker 主機上安裝 nginx(反向代理)
- 為容器定義靜態 IP 或主機名
- 將容器的 SSL 證書 + 私鑰文件提供給 nginx 反向代理
- 在反向代理配置中為 Docker 容器定義 nginx 上游
- 定義 nginx 伺服器(“vhosts”)來服務定義的域名
server_name
- 將請求轉發到
location
使用定義的上游proxy_pass
例子:
我的
/etc/nginx/sites-enabled/dockerproxy
樣子是這樣的:# gitlab upstream gitlab { server 172.20.0.2; } # docker registry upstream registry { server 172.20.0.3:5050; } # dev.mycompany.org server { listen 10.10.10.40:80 default; listen 10.10.10.40:443 ssl default; server_name dev.mycompany.org; ssl_certificate /data/run/certbot/data/live/dev.mycompany.org/fullchain.pem; ssl_certificate_key /data/run/certbot/data/live/dev.mycompany.org/privkey.pem; location / { proxy_pass http://gitlab/; 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; } } # registry.mycompany.org server { listen 10.10.10.40:443 ssl; server_name registry.mycompany.org; ssl_certificate /data/run/certbot/data/live/registry.mycompany.org/fullchain.pem; ssl_certificate_key /data/run/certbot/data/live/registry.mycompany.org/privkey.pem; ssl_session_cache builtin:1000 shared:SSL:60m; ssl_session_timeout 60m; client_max_body_size 0; chunked_transfer_encoding on; location / { proxy_pass http://registry/; 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_set_header
指令嚴格來說不是必需的,它們取決於各個後端應用程序的期望。如您所見,此配置告訴 nginx:
- 綁定到 10.10.10.40:443
- dev.mycompany.org 到 172.20.0.2 的代理請求$$ :80 $$(gitlab容器的IP)
- 對 registry.mycompany.org 的代理請求到 172.20.0.3:5050(註冊容器的 IP)
- 使用給定的證書文件終止 SSL(在我的例子中,來自 certbot 容器)
視覺化
0.0.0.0:443 | +-----------------------+ | nginx | +-----------------------+ | | +--------------+ +--------------+ | VHOST | | VHOST | | web.app1.com | | web.app2.com | +--------------+ +--------------+ | | +--------------+ +--------------+ | CONTAINER | | CONTAINER | | 172.0.0.2 | | 172.0.0.3 | +--------------+ +--------------+
通過使用不同的指令定義其他
upstream
和server
對象server_name
,您可以使用相同的介面 IP + 埠使其他 HTTP(S) 服務可用。請注意,該
listen 10.10.10.40:443
指令在 nginx 配置中多次使用。這是可能的,因為 nginx 只綁定到該 IP 一次,然後解析Host
客戶端請求中的標頭以確定哪個server
(vhost)將為該請求提供服務。我的配置在定義中使用靜態 IP
upstream
,但您也可以使用容器的主機名,只需確保事先知道它們(在 docker-compose 中定義,請參閱https://docs.docker.com/compose/compose-file/# domainname-hostname-ipc-mac_address-privileged-read_only-shm_size-stdin_open-tty-user-working_dir)並且可由 nginx 解析。最後,不要將容器/服務的埠映射到主機埠!它們不需要對外部世界可用,只有 nginx 需要訪問它們。