【问题标题】:nginx redirect to docker containernginx 重定向到 docker 容器
【发布时间】:2017-05-07 00:45:27
【问题描述】:

在发布我的问题之前,我想知道是否有可能实现我想要的。

比方说,myserver.com 使用 nginx 和letsencrypt 运行一个docker 容器。在同一台服务器上还有 2 个运行网站的 docker 容器。

现在所有重定向都很好,所以 www.myserver.com 转到 docker 1,site2.myserver.com 转到 docker 2。

我希望所有通信都通过 HTTPS 运行,但这里开始出现问题。 所以,我的问题是:带有 nginx 和letsencrypt的docker是否可以使用letsencrypt的证书连接到另一个docker? 对我来说,这似乎是某种中间人“攻击”。 更简略一点:

浏览到 http://site2.myserver.com -> nginx 重定向到 https://site2.myserver.com -> 在端口 80 上连接到容器 2 (192.168.0.10)。 或另一种选择: 浏览到 http://site2.myserver.com -> nginx 重定向到 https://site2.myserver.com -> 在端口 443 上连接到具有 site2.myserver.com 证书的容器 2 (192.168.0.10)。

如果做不到,那有什么解决办法呢?将证书复制到 docker 容器并使其运行 https,以便将 http 请求重定向到该容器的 https 端口?

浏览到 http://site2.myserver.com -> nginx 转发请求 -> 在端口 443 上连接到具有 site2.myserver.com 证书的容器 2 (192.168.0.10)。

谢谢, 格雷格

【问题讨论】:

标签: nginx docker url-redirection


【解决方案1】:

这是我的方法:

NGINX 配置文件(default.conf)

使用来自https://github.com/KyleAMathews/docker-nginx的docker镜像,我做了如下自定义默认文件:

server {
    root /var/www;
    index index.html index.htm;

    server_name localhost MYHOST.COM;

    # Add 1 week expires header for static assets
    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        expires 1w;
    }

    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to redirecting to index.html
        try_files $uri $uri/ @root;

        return 301 https://$host$request_uri;
    }

    # If nginx can't find a file, fallback to the homepage.
    location @root {
        rewrite .* / redirect;
    }

    include /etc/nginx/basic.conf;
}

Dockerfile

这是我的 Dockerfile,考虑到我的静态内容在 html/ 目录下。

COPY conf/default.conf /etc/nginx/sites-enabled/default

ADD certs/myhost.com.crt /etc/nginx/ssl/server.crt
ADD certs/myhost.com.key /etc/nginx/ssl/server.key
RUN ln -s /etc/nginx/sites-available/default-ssl /etc/nginx/sites-enabled/default-ssl

COPY html/ /var/www

CMD 'nginx'

测试

对于本地测试,通过将 myhost.com 添加到 127.0.0.1 来更改文件 /etc/hosts 并运行以下命令:

curl -I http://www.myhost.com/

结果

HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Sun, 04 Mar 2018 04:32:04 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: https://www.myhost.com/
X-UA-Compatible: IE=Edge

【讨论】:

    【解决方案2】:

    据我了解,您的 nginx 反向代理与容器位于同一网络上,因此没有太多需要使用 TLS 保护它们之间的连接(因为这是一个私有网络,如果攻击者可以访问该网络他也可以访问服务器以及所有未加密的数据)。

    如果您绝对需要有效的证书来保护本地网络上的连接,您可以创建额外的子域来解析本地 IP。然后您将需要使用手动 DNS 选项来获取您的证书(这是一个 certbot 选项,您需要手动输入一个密钥作为您域的 TXT 条目)。

    将 http 重定向到 https 的示例 Nginx 配置

    server {
        listen 80;
    
        server_name example.com;
        return 301 https://example.com/;
    }
    server{
        listen 443 ssl http2;
    
        server_name  example.com;
    
        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
        ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    
        location / {
            proxy_pass http://container:8080/;
            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;
        }
    
        include tls.conf;
    }
    

    【讨论】:

    • 所有容器都在一台主机上运行。由于容器运行在自己的虚拟 192.168.0.x 网络上,因此不需要对 nginx 和容器之间的数据进行加密。 IP 地址由 docker 分配。我只想将来自浏览器的 http 连接重定向到 https。我找到了很多关于如何在同一主机上执行此操作的文档,但不是针对另一个 IP 地址(虚拟地址)。
    • 可以使用设置Nginx返回301状态码重定向到HTTPS页面
    • 这对我不起作用:(它重定向到自己的 443 端口上的 nginx 容器。这就是我所拥有的:site2.myserver.com { server 192.168.0.13:8069; } server { server_name site2.myserver.com; listen 80 ; return 301 site2.myserver.com$request_uri; location / { proxy_pass site2.myserver.com; }} 有没有“location /”,没有任何区别。当我删除“return 301 " 与容器建立了 http 连接。因此,一旦连接被加密,它就指向自己的而不是容器。
    • ...第一行应该是:upstream site2.myserver.com { server 192.168.0.13:8069; }
    • 是的,您需要另一个带有 HTTPS 配置的服务器部分
    【解决方案3】:

    很好,通过合并 opHASnoNAME 和 Paul Trehiou 的答案,我终于可以得到我想要的了。我为 opHASnoNAME 的回答做的额外工作是在 nginx 和letsencrypt docker之间挂载一个文件系统。它可以将 nginx 的配置文件链接到正确的证书(见下文)。

    这就是我所做的:

    docker run --name nginx-prod --restart always -d -p 80:80 -p 443:443 -v /choose/your/dir/letsencrypt:/etc/nginx/certs:ro -v /etc/nginx/vhost.d -v /usr/share/nginx/html -v /var/run/docker.sock:/tmp/docker.sock:ro -e DEFAULT_HOST=myserver.com jwilder/nginx-proxy
    
    docker run --name letsencrypt --restart always -d -v /choose/your/dir/letsencrypt:/etc/nginx/certs:rw --volumes-from nginx-prod -v /var/run/docker.sock:/var/run/docker.sock:ro jrcs/letsencrypt-nginx-proxy-companion
    

    然后使用网络服务器运行任何容器;无需设置 LETSENCRYPT 变量。无需设置即可访问我当前的容器。

    jwilder/nginx-proxy 将列出 /etc/nginx/conf.d/default.conf 中所有正在运行的容器。不要在此文件中添加任何内容,因为它将在下次重新启动时被覆盖。 在同一目录中为每个网络服务器创建一个新的 .conf 文件。该文件将包含 Paul Trehiou 建议的 https 信息。例如,我创建了 site2.conf:

    server{
        listen 443 ssl http2;
        server_name  site2.myserver.com;
        ssl_certificate /etc/nginx/certs/live/myserver.com/fullchain.pem;
        ssl_certificate_key /etc/nginx/certs/live/myserver.com/privkey.pem;
        ssl_trusted_certificate /etc/nginx/certs/live/myserver.com/fullchain.pem;
    
        location / {
            proxy_pass http://192.168.0.10/;
            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_pass 地址是您可以从 default.conf 文件中获取的地址,其中列出了每个容器的 IP 地址。 为了能够备份这些 .conf 文件,我将重新创建我的 nginx 容器并将本地文件系统挂载到 /etc/nginx/conf.d。如果容器由于 .conf 文件中的错误而无法启动,这也会让生活变得更轻松。

    非常感谢大家的意见,现在拼图已经完成;-)

    【讨论】:

      【解决方案4】:

      我会选择开箱即用的解决方案:

      JWilder Nginx + Lets Encrypt。

      首先我们启动 NGINX Container 作为反向代理:

      docker run -d -p 80:80 -p 443:443 \
          --name nginx-proxy \
          -v /path/to/certs:/etc/nginx/certs:ro \
          -v /etc/nginx/vhost.d \
          -v /usr/share/nginx/html \
          -v /var/run/docker.sock:/tmp/docker.sock:ro \
          jwilder/nginx-proxy
      

      接下来我们启动 Lets Encrypt Container:

      docker run -d \
      -v /path/to/certs:/etc/nginx/certs:rw \
      --volumes-from nginx-proxy \
      -v /var/run/docker.sock:/var/run/docker.sock:ro \
      jrcs/letsencrypt-nginx-proxy-companion
      

      对于您的网站,您需要设置一些环境变量:

      docker run -d \
      --name website1 \
      -e "VIRTUAL_HOST=website1.com" \
      -e "LETSENCRYPT_HOST=website1.com" \
      -e "LETSENCRYPT_EMAIL=webmaster@website1" \
      tutum/apache-php
      

      Nginx 容器将在他的配置中创建一个新条目,而让 encrypt 容器将请求一个证书(并进行更新)。

      更多:Nginx+LetsEncrypt

      【讨论】:

      • 我认为这个解决方案非常适合当你想要快速完成某件事但你不是这样学习的时候
      • 当然,如果您想学习从地面设置这些东西,这不是最好的解决方案 :-) 但是创建这样的设置需要很多时间(注册每个新容器,调整nginx tmpl,请求ssl cert..)
      • 感谢您的回答,但我又遇到了同样的问题。转到网络服务器的 80 端口,我可以看到 Tutum 默认页面,因此重定向到 tutum 容器可以正常工作。转到 https 页面时,我收到错误“无法连接”。
      猜你喜欢
      • 1970-01-01
      • 2020-12-10
      • 1970-01-01
      • 2021-12-27
      • 2018-05-23
      • 2019-03-11
      • 2022-01-20
      • 1970-01-01
      • 2023-03-17
      相关资源
      最近更新 更多