首页 > 解决方案 > 如何正确使用 Nginx 作为具有 SSL 的多个 Apache Docker 容器的反向代理?

问题描述

给定以下 docker 容器:

使用以下示例域名:

我想实现以下行为:

我遇到两个问题:

  1. 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
  2. mod_rpaf似乎无法正常工作(即,访问日志中的ip地址是服务器 [例如,] 而不是发出请求的客户端的 地址apachenginx172.19.0.2ip
    • 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 机器上试过这个,所以有两个初步步骤。

  1. 初步步骤

    一个。在我的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.testvia

    openssl req -x509 -sha256 -nodes -newkey rsa:2048 -days 365 -keyout localhost.key -out localhost.crt
    
  2. 服务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>
    
  3. 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虚拟主机app1app2没有被修改:

    <VirtualHost *:80>
        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html
        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
    </VirtualHost>
    
  4. 开始设置

    一个。启动proxy服务器

    docker-compose -f nginx.yml up -d --build
    

    湾。启动app1app2服务

    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
    

问题:

  1. 当我运行时,docker logs proxy -f我注意到上面提到的 SSL 内部错误:SSL_read() failed
  2. 如果我运行docker logs app1 -f并访问https://local1.web.testip则请求中的GET匹配容器(即)而不是远程客户端的 ipproxy172.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"

我似乎无法理解出了什么问题,并感谢您的帮助。

标签: apachedockersslnginxproxy

解决方案


推荐阅读