Portainer: 客户端向HTTPS服务器发送HTTP请求 - 尽管URL是https://

6

我对服务器配置这个主题还比较新,现在我遇到了一个问题,无法使用SSL证书访问容器。

我的设置是什么:

我有一个带有Docker的树莓派。与端口80和443连接的容器是一个反向代理,它将传入的子域名定向到不同的其他容器。 例如: webserver.my-domain.com 导向 IP 192.168.178.69:8080。我通过文件夹中的此配置实现了这一点:

<VirtualHost *:80>
 ServerName webserver.my-domain.com
 ProxyPreserveHost On 
 DocumentRoot /var/www/html
 ProxyPass /.well-known !
 ProxyPass / http://192.168.178.69:8080/
 ProxyPassReverse / http://192.168.178.69:8080/
RewriteEngine on
RewriteCond %{SERVER_NAME} =webserver.my-domain.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

我还在反向代理容器内创建了一个Let's Encrypt证书。这将创建一个额外的文件webserver-le-ssl.conf

<IfModule mod_ssl.c>
<VirtualHost *:443>
 ServerName webserver.my-domain.com
 ProxyPreserveHost On 
 DocumentRoot /var/www/html
 ProxyPass /.well-known !
 ProxyPass / http://192.168.178.69:8080/
 ProxyPassReverse / http://192.168.178.69:8080/

SSLCertificateFile /etc/letsencrypt/live/my-domain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/my-domain.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

目前为止还不错。如果我尝试使用URL https://webserver.my-domain.com,我的内容就可以访问。

我的问题是什么

我使用Portainer来管理我的docker容器,我希望通过portainer.my-domain.com来访问Portainer。 因此,这是sites-enabled中的portainer配置:

<VirtualHost *:80>
 ServerName portainer.my-domain.com
 ProxyPreserveHost On 
 DocumentRoot /var/www/html
 ProxyPass /.well-known !
 ProxyPass / http://192.168.178.69:9443/
 ProxyPassReverse / http://192.168.178.69:9443/
RewriteEngine on
RewriteCond %{SERVER_NAME} =portainer.my-domain.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

同时,还需要针对此进行SSL配置:

<IfModule mod_ssl.c>
<VirtualHost *:443>
 ServerName portainer.my-domain.com
 ProxyPreserveHost On 
 DocumentRoot /var/www/html
 ProxyPass /.well-known !
 ProxyPass / http://192.168.178.69:9443/
 ProxyPassReverse / http://192.168.178.69:9443/

SSLCertificateFile /etc/letsencrypt/live/my-domain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/my-domain.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

如果我调用192.168.178.69:9443/,我可以毫无问题地访问容器。 但如果我尝试访问URLportainer.my-domain.com,我只会得到以下信息:
Client sent an HTTP request to an HTTPS server.

但是URL显示为:https://portainer.my-domain.com/。 所以我不明白为什么会有HTTP请求,即使我的浏览器显示连接是使用https。

有人可以解释一下这个问题并告诉我如何解决吗?

更新:我的解决方案 经过多次尝试,我找到了一个解决方案: 由于我运行反向代理和Portainer作为Docker容器,因此我将两个容器都放入了一个docker-compose网络中:

version: "3.4"

services:
  apache:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /home/pi/reverse-proxy/:/etc/apache2
    networks:
      - homeserver

  portainer:
    image: portainer/portainer-ce:latest
    ports:
      - "8000:8000"
      - "9000:9000"
      - "9443:9443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - portainer_data:/data
    networks:
      - homeserver

networks:
  homeserver:

volumes:
  portainer_data:

Apache2的配置文件目录是/etc/apache2。在这之后,我将ProxyPass的IP更改为容器的名称:

 ProxyPass / http://reverse-proxy_portainer_1:9000/
 ProxyPassReverse / http://reverse-proxy_portainer_1:9000/

经过这些更改,它开始工作了。


你解决了这个问题吗,@Michael?我在使用Apache代理和Portainer 2.13.1时遇到了完全相同的问题。在旧版本中它可以工作,但是在我升级后就不行了。我可以通过内部IP地址https://192.168.0.100:9443访问,但浏览器会警告此连接不安全,因为此访问绕过了代理配置文件中定义的Letencrypt SSL证书。 - Lukuluba
@Lukuluba 是的,我找到了解决方案并更新了我的帖子。 - Michael
3个回答

4

我曾在Apache2代理后面使用Portainer 2.13.1时遇到同样的问题。我通过启用端口9000来运行镜像来解决这个问题,该端口是Portainer的HTTP端口。这意味着你需要在外部阻止9000端口,并仅通过受HTTPS保护的代理访问它。以下为我的命令:

docker run -d -p 9000:9000 -p 8000:8000 -p 9443:9443 \
   --name portainer \
   --restart=always \
   -v /var/run/docker.sock:/var/run/docker.sock \
   -v portainer_data:/data 
   portainer/portainer-ce:latest

我的 VirtualHost 文件将端口 9000 指向如下:

<IfModule mod_ssl.c>
    <VirtualHost *:443>

            ProxyPreserveHost On
            Proxyrequests Off

            ServerName docker.<domain.tld>
            ServerAdmin admin@<domain.tld>

            ProxyPass / http://127.0.0.1:9000/
            ProxyPassReverse / http://127.0.0.1:9000/

            ErrorLog ${APACHE_LOG_DIR}/portainer-error.log
            CustomLog ${APACHE_LOG_DIR}/portainer-access.log combined

            SSLCertificateFile /etc/letsencrypt/live/docker.<domain.tld>/fullchain.pem
            SSLCertificateKeyFile /etc/letsencrypt/live/docker.<domain.tld>/privkey.pem
            Include /etc/letsencrypt/options-ssl-apache.conf

    </VirtualHost>

请使用像Linux中的ufw这样的工具,确保端口8000、9000和9443不可从外部访问。


UFW 无法与 Docker 兼容! - S. Saeid Hosseini
我假设您的Docker镜像将安装在物理/云服务器上。这里提到的UFW是安装在服务器上而不是Docker镜像上的。 - Lukuluba
是的,我也在谈论这个问题。Docker直接操作iptables,不遵守ufw规则。 - S. Saeid Hosseini

2
根据您的问题,似乎这个是有效的。
ProxyPass / http://192.168.178.69:8080/

但这个不行:
ProxyPass / http://192.168.178.69:9443/

请注意,在这两种情况下都使用了纯http://协议,即使涉及不同的端口。而9443端口号表明您预期使用https://而不是http://。如果是这种情况,这将解释您收到的错误消息:由于将协议设置为http://而不是https://,因此发送了一个纯HTTP请求。

但是URL显示:https://portainer.my-domain.com/

这里的协议与客户端和nginx之间的连接有关,而不是nginx和内部服务器之间的连接。后者取决于ProxyPass URL中给定的协议。

好的,那很清楚。我将ProxyPass更改为https://192.168.178.69:9443。但是当我尝试调用该站点时,我遇到了一个内部服务器错误:The server encountered an internal error or misconfiguration and was unable to complete your request. Apache/2.4.53 (Debian) Server at portainer.my-domain.com Port 443。你知道我忘了什么吗?或者我可以在哪里找到相关信息? - Michael
1
@Michael:基本上我们对你的内部应用程序一无所知。URL https://192.168.178.69:9443 是否有效,即您是否可以使用curl、wget或类似工具从服务器成功访问此URL?为什么要使用 https://...:9443,而在其他(工作)地方使用 http://...:8080 - Steffen Ullrich
也许我没有正确理解您的意思。我的要求是将portainer.my-domain.com导向到 https://192.168.178.69:9443,并且请求应该是使用https而不是http。但是portainer告诉我请求使用了http,所以我无法使用portainer。所以我理解您的答复是这样的,即客户端对我的反向代理的请求是使用https,但是从我的反向代理到portainer的请求是使用http,将代理传递从 http://192.168.178.69:9443/更改为https://192.168.178.69:9443/可能会解决问题。我理解得对吗? - Michael
当我调用 http://192.168.178.69:9443/ 时,我会收到消息 Client sent an HTTP request to an HTTPS server.。但是如果我调用 https://192.168.178.69:9443/,我会从浏览器中收到连接不安全的消息,并且我可以添加一个例外来进入该站点。然后它就可以工作了,但这不应该是正常情况。我想使用安全连接进入该站点。 - Michael
1
@Michael:我从浏览器那里收到的信息是连接不安全,而且Nginx也因为同样的问题而遇到了麻烦,这就是为什么它会失败的原因。再次问一下,为什么您坚持使用https://...9443代替http://...:8080(不同协议和不同端口)作为配置的工作部分中所做的那样呢? - Steffen Ullrich

0
我有同样的信息。 经过研究,我解决了这个问题: 我的旧网址:http://IP:9443 我的新网址:https://IP:9443

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接