给定如下docker容器:
- 运行未修改的官方
nginx:latest
映像的nginx
服务 - 容器名称:
proxy
- 两个应用程序基于修改后的官方
php:7.4.1-apache
镜像在单独的容器中运行 - 容器名称:
app1
和app2
- 所有容器
proxy
、app1
和app2
都在同一个Docker创建的网络中,并具有自动DNS解析功能
示例域名如下: local.web.test
local1.web.test
local2.web.test
我想实现以下行为:- 将
nginx
中的local.web.test
用作默认服务器块 - 将
nginx
配置为将来自local1.web.test
和local2.web.test
的请求分别代理到app1
和app2
,这两个请求都侦听端口80
- 将
nginx
配置为使用wildcard SSL certificate服务所有三个域名
我遇到两个问题: - 我注意到
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
似乎无法正常工作(即,apache
访问日志中的ip
地址属于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
phpinfo()
forApache Environment的输出显示:HTTP_X_REAL_IP
列出客户端ip
SERVER_ADDR
列出app1
容器ip
(例如,172.19.0.4
)REMOTE_ADDR
显示proxy
容器ip
(例如172.19.0.2
),而不是客户端ip
为了使其可重现,这就是一切的设置方式。我在我的Windows机器上尝试了这个,所以有两个初步步骤。
1.初步步骤
a.在我的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
B.我通过以下方式生成了一个自签名的SSL证书,通用名设置为***.local.test
**
openssl req -x509 -sha256 -nodes -newkey rsa:2048 -days 365 -keyout localhost.key -out localhost.crt
1.proxy
服务设置
a. 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
B.在绑定挂载到/etc/nginx/conf.d
的./nginx
中,有一个文件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;
}
./certs:/etc/ssl/nginx
绑定挂载包含自签名证书和密钥的文件夹
d. ./static/local.web.test:/usr/share/nginx/html
使包含以下内容的文件index.html
可用
<h1>local.web.test</h1>
1.app1
和app2
业务设置
a. 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
B. 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.不修改app1
和app2
中的000-default.conf
虚拟主机:
<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
B.启动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 sending req in nginx),但在这种情况下,消息更具体地指向证书颁发机构
- 如果我运行
docker logs app1 -f
并访问https://local1.web.test
,则GET
请求中的ip
与proxy
容器(即172.19.0.2
)的ip
匹配,而与远程客户端的ip
不匹配 - 我怀疑是这个
RPAF_ProxyIPs 127.0.0.1
,但我不能手动修复ip
,因为我不知道容器将在exp_proxy
网络中获得什么ip
- 我也不能使用主机名,因为
RPAF_ProxyIPs
需要一个ip
docker inspect proxy
显示"IPAddress": "172.19.0.2"
docker inspect app1
显示"IPAddress": "172.19.0.4"
我不知道出了什么问题,希望你能帮忙。
1条答案
按热度按时间iugsix8n1#
根据所提供的信息,您似乎遇到了两个问题。以下是解决这些问题的一些建议:
rpaf.conf
中的RPAF_ProxyIPs指令更新为RPAF_ProxyIPs <network_gateway_ip>
。docker network inspect <network_name>
获取exp_proxy
网络的网关IP。rpaf.conf
中的RPAF_ProxyIPs指令,并重新启动容器。