kil*_*eet 1 email-server reverse-proxy docker
我想知道这是否可能,如果可以,我如何在一台专用服务器上同时运行 nginx-proxy 和 poste.io 邮件服务器?
我可以单独运行这两个容器,但是当我尝试同时运行这两个容器时,它说我无法运行后一个容器,因为端口 443 已被另一个容器使用。
现在,当我只使用 nginx 反向代理时,我会在服务器上运行多个网站,所有这些网站都会公开端口 80 和 443 以及代理本身,这让我很困惑为什么我不能运行另一个容器做同样的事情(是的,我知道通常两个进程不应该能够使用同一个端口而不需要一些摆弄)。
我使用以下代理: 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
Run Code Online (Sandbox Code Playgroud)
在我的 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
Run Code Online (Sandbox Code Playgroud)
所以这就是让我困惑的地方。为什么 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.
Run Code Online (Sandbox Code Playgroud)
理想情况下,我能够在一台服务器上运行该邮件服务器和我的网站,这是因为只有一小部分网站要托管,并且预计这些网站都不会在短时间内增长太多。
更新
这些网站使用来自 nginx-proxy 的卷,因此它们可以在其旁边运行,同时暴露端口 80 和 443 本身,但是当我尝试将 nginx-proxy 的相同卷与邮件服务器链接时,我不断收到相同的错误正在使用的端口。
如果一个 docker 容器已绑定到接口之一 IP 上的端口 443(或 0.0.0.0 表示所有接口),则其他 docker 容器无法绑定到同一 IP。当一个 1 容器启动时,使用 netstat 检查:
sudo netstat -nalp64 | grep 443
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 26547/docker-proxy
Run Code Online (Sandbox Code Playgroud)
由于 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 |
+--------------+ +--------------+
Run Code Online (Sandbox Code Playgroud)
您不需要将多个容器绑定到同一个端口,而是需要一些绑定到端口的软件,将连接重定向到适当的容器。
通过运行专用反向代理最容易完成此操作,这是绑定到端口 (443) 的唯一程序。反向代理的目的是根据请求的 HTTP 主机转发传入连接。
反向代理可以在运行 docker 的物理主机上运行,也可以在 docker 容器内运行。
反向代理还可以终止 SSL 连接,这意味着该 nginx 实例处理与客户端之间的所有加密/解密,而与后端(容器)的连接未加密。
我认为这并不是严格需要的,现代浏览器支持 SNI,因此 nginx 仍然可以将请求转发到适当的后端,而无需解密所有流量。但是使用中央 SSL 终止,您只需要在一处提供证书,并且对于大多数用例,只需全局配置 SSL 一次。
为了设置这样一个带有 SSL 终止的反向代理
server_namelocation将请求转发到使用定义的上游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;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,严格来说这些proxy_set_header指令不是必需的,它们取决于各个后端应用程序的期望。
如您所见,此配置告诉 nginx:
可视化
0.0.0.0:443
|
+-----------------------+
| nginx |
+-----------------------+
| |
+--------------+ +--------------+
| VHOST | | VHOST |
| web.app1.com | | web.app2.com |
+--------------+ +--------------+
| |
+--------------+ +--------------+
| CONTAINER | | CONTAINER |
| 172.0.0.2 | | 172.0.0.3 |
+--------------+ +--------------+
Run Code Online (Sandbox Code Playgroud)
通过使用不同指令定义其他upstream对象,您可以使用相同的接口 IP + 端口来提供其他 HTTP(S) 服务。serverserver_name
请注意,该listen 10.10.10.40:443指令在 nginx 配置中多次使用。这是可能的,因为 nginx 仅绑定到该 IP 一次,然后解析Host客户端请求中的标头以确定哪个server(虚拟主机)将服务该请求。
我的配置在upstream定义中使用静态 IP,但您也可以使用容器的主机名,只需确保它们事先已知(在 docker-compose 中定义,请参阅https://docs.docker.com/compose/compose-file/#域名-主机名-ipc-mac_address-privileged-read_only-shm_size-stdin_open-tty-user-working_dir)并可由 nginx 解析。
最后,不要将容器/服务的端口映射到主机端口!它们不需要对外界可用,只有 nginx 需要访问它们。
| 归档时间: |
|
| 查看次数: |
3931 次 |
| 最近记录: |