apache - 如何正确使用 Nginx 作为具有 SSL 的多个 Apache Docker 容器的反向代理?
问题描述
给定以下 docker 容器:
nginx
运行未经修改的官方nginx:latest
图像 的服务- 容器名称:
proxy
- 容器名称:
- 基于修改后的官方
php:7.4.1-apache
镜像 在不同容器中运行的两个应用程序- 容器名称:
app1
和app2
- 容器名称:
- 所有容器
proxy
、app1
和app2
都在同一个 Docker 创建的网络中,具有自动 DNS 解析
使用以下示例域名:
local.web.test
local1.web.test
local2.web.test
我想实现以下行为:
- 作为默认服务器块
local.web.test
服务nginx
- 配置
nginx
为代理来自local1.web.test
和local2.web.test
的请求app1
和app2
分别监听端口80
- 配置为使用通配符 SSL 证书
nginx
为所有三个域名提供服务
我遇到两个问题:
nginx
我在日志 中注意到以下错误:2020/06/28 20:00:59 [crit] 27#27: *36 SSL_read() failed (SSL: error:14191044:SSL routines:tls1_enc:internal error) while waiting for request, client: 172.19.0.1, server: 0.0.0.0:443
mod_rpaf
似乎无法正常工作(即,访问日志中的ip
地址是服务器 [例如,] 而不是发出请求的客户端的 地址apache
nginx
172.19.0.2
ip
172.19.0.2 - - [28/Jun/2020:20:05:05 +0000] "GET /favicon.ico HTTP/1.0" 404 457 "http://local1.web.test/" "Mozilla/5.0 (Windows NTndows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
- Apache Environment的输出
phpinfo()
显示:HTTP_X_REAL_IP
列出客户ip
SERVER_ADDR
列出app1
容器ip
(例如,172.19.0.4
)REMOTE_ADDR
显示proxy
容器ip
(例如,172.19.0.2
)而不是客户端ip
为了使其可重现,这就是一切的设置方式。我在我的 Windows 机器上试过这个,所以有两个初步步骤。
初步步骤
一个。在我的
C:\Windows\System32\drivers\etc\hosts
文件中,我添加了以下内容:127.0.0.1 local.web.test 127.0.0.1 local1.web.test 127.0.0.1 local2.web.test
湾。我生成了一个自签名 SSL 证书,其通用名称设置为
*.local.test
viaopenssl req -x509 -sha256 -nodes -newkey rsa:2048 -days 365 -keyout localhost.key -out localhost.crt
服务
proxy
设置一个。
nginx.yml
对于docker-compose
:_version: "3.8" services: nginx: image: nginx:latest container_name: proxy ports: - "80:80" - "443:443" volumes: - ./nginx:/etc/nginx/conf.d - ./certs:/etc/ssl/nginx - ./static/local.web.test:/usr/share/nginx/html networks: - proxy networks: proxy: driver: bridge
湾。在
./nginx
其中绑定安装/etc/nginx/conf.d
有一个文件default.conf
,其中包含:server { listen 80 default_server; server_name local.web.test; location / { return 301 https://$host$request_uri; } } server { listen 443 ssl; server_name local.web.test; location / { root /usr/share/nginx/html; index index.html index.htm; } ssl_certificate /etc/ssl/nginx/localhost.crt; ssl_certificate_key /etc/ssl/nginx/localhost.key; }
C。
./certs:/etc/ssl/nginx
绑定挂载包含自签名证书和密钥的文件夹d。使包含
./static/local.web.test:/usr/share/nginx/html
的文件可用index.html
<h1>local.web.test</h1>
和
app1
服务app2
设置一个。
apache.yml
对于docker-compose
:_version: "3.8" services: app1: build: context: . dockerfile: apache.dockerfile image: app1 container_name: app1 volumes: - ./static/local1.web.test:/var/www/html networks: - exp_proxy app2: build: context: . dockerfile: apache.dockerfile image: app2 container_name: app2 volumes: - ./static/local2.web.test:/var/www/html networks: - exp_proxy networks: # Note: the network is named `exp_proxy` because the root directory is `exp`. exp_proxy: external: true
湾。
apache.dockerfile
图像如下所示:# Base image. FROM php:7.4.1-apache # Install dependencies. RUN apt-get update && apt-get install -y curl nano wget unzip build-essential apache2-dev # Clear cache. RUN apt-get clean && rm -rf /var/lib/apt/lists/* # Change working directory, WORKDIR /root # Fetch mod_rpaf. RUN wget https://github.com/gnif/mod_rpaf/archive/stable.zip # Unzip. RUN unzip stable.zip # Change working directory, WORKDIR /root/mod_rpaf-stable # Compile and install. RUN make && make install # Register the module for load. RUN echo "LoadModule rpaf_module /usr/lib/apache2/modules/mod_rpaf.so" > /etc/apache2/mods-available/rpaf.load # Copy the configuration for mod_rpaf. COPY ./apache/mods/rpaf.conf /etc/apache2/mods-available/rpaf.conf # Enable the module. RUN a2enmod rpaf # Set working directory. WORKDIR /var/www/html
C。
./apache/mods/rpaf.conf
复制的文件包含:<IfModule mod_rpaf.c> RPAF_Enable On RPAF_Header X-Real-Ip RPAF_ProxyIPs 127.0.0.1 RPAF_SetHostName On RPAF_SetHTTPS On RPAF_SetPort On </IfModule>
d。
./static/local1.web.test:/var/www/html
绑定挂载一个index.php
文件,其中包含:<h1>local1.web.test</h1> <?php phpinfo(); ?>
也一样
./static/local2.web.test:/var/www/html
e. 中的
000-default.conf
虚拟主机app1
并app2
没有被修改:<VirtualHost *:80> ServerAdmin webmaster@localhost DocumentRoot /var/www/html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>
开始设置
一个。启动
proxy
服务器docker-compose -f nginx.yml up -d --build
湾。启动
app1
和app2
服务docker-compose -f apache.yml up -d --build
C。检查容器以查看是否
mod_rpaf
已启用docker-compose -f apache.yml exec app1 apachectl -t -D DUMP_MODULES
d。添加两个文件,这些文件将在容器上
./nginx
可用proxy
/etc/nginx/conf.d
local1.web.test.conf
包含
upstream app-1 { server app1; } server { listen 80; server_name local1.web.test; location / { return 301 https://$host$request_uri; } } server { listen 443 ssl; server_name local1.web.test; location / { proxy_pass http://app-1; 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; } ssl_certificate /etc/ssl/nginx/localhost.crt; ssl_certificate_key /etc/ssl/nginx/localhost.key; }
- 第二个文件
local2.web.test.conf
具有类似的设置(即,数字1
替换为2
)
e. 检查配置并重新启动
proxy
容器(或重新加载nginx
服务器)docker-compose -f nginx.yml exec proxy nginx -t docker-compose -f nginx.yml exec proxy service nginx reload
问题:
- 当我运行时,
docker logs proxy -f
我注意到上面提到的 SSL 内部错误:SSL_read() failed
- 有人遇到类似的错误(http2: SSL read failed while sent req in nginx)但在这种情况下,该消息更具体地指向证书颁发机构
- 如果我运行
docker logs app1 -f
并访问https://local1.web.test
,ip
则请求中的GET
匹配容器(即)而不是远程客户端的ip
proxy
172.19.0.2
- 我怀疑杯子是这个
RPAF_ProxyIPs 127.0.0.1
,但我无法手动修复,ip
因为我不知道ip
容器会在exp_proxy
网络中得到什么 - 我也不能使用主机名,因为
RPAF_ProxyIPs
需要一个ip
docker inspect proxy
节目"IPAddress": "172.19.0.2"
docker inspect app1
节目"IPAddress": "172.19.0.4"
- 我怀疑杯子是这个
我似乎无法理解出了什么问题,并感谢您的帮助。
解决方案
推荐阅读
- pandas - 如何更改数据透视列的顺序
- google-bigquery - bigquery sql:将列值转换为列名
- android - 如何设置 30 天的重复闹钟,直到 android 最新的操作系统版本(29)应该兼容?
- excel - 是否有 microsoft flow 功能可以使用最后收到的数据更新文档?
- angularjs - 角度甘特表:自定义标题
- c - 如何根据值打印不同的符号?
- python - 在 MSSQL Server 上使用 sqlalchemy-turbodbc 创建数据库
- powershell - 如何在 powershell 中运行 cppcheck?
- r - 缩放图 - 椭圆
- azure-devops - 我可以在另一个任务中使用来自一个 PowerShell 任务的函数吗?