简体   繁体   中英

Portainer: Client sent an HTTP request to an HTTPS server - despite the URL is https://

I am pretty new for the topic server configuration and now I got a problem with to reach a container with ssl certificate.

What is my setup:

I've got a raspberry pi with docker on it. The container which is connected to port 80 and 443 is a reverse proxy which is directing incoming subdomains to different other container. Example: webserver.my-domain.com is leading to IP 192.168.178.69:8080. I archived this through this config in the folder sites-enabled :

<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>

I also created a let's encrypt certificate inside of the reverse proxy container. This created an additional file 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>

So far so good. My content is available if I try the URL https://webserver.my-domain.com .

What is my Problem

I use Portainer to manage my docker container and I want Portainer to be available through portainer.my-domain.com . So this is the portainer config inside of sites-enabled :

<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>

And also the ssl config for this:

<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>

If I call 192.168.178.69:9443/ I can reach the container without problems. But if I try to reach the URL portainer.my-domain.com I just got the Message:

Client sent an HTTP request to an HTTPS server.

But in the URL shows: https://portainer.my-domain.com/ . So I don't understand why there is an HTTP request, even if my browser shows me that the connection is with https.

Can someone explain this to me and show me how to fix this?

Update: My solution With a lot of tries I found a solution: As I run the reverse proxy and the portainer as docker containers, I put both containers into a network with 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:

The volume of the apache2 is the complete config folder of /etc/apache2 . After that I changed the IP of the ProxyPass to the name of the container:

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

After this changes it worked.

So based on your question it seems that this works

ProxyPass / http://192.168.178.69:8080/

But this does not:

ProxyPass / http://192.168.178.69:9443/

Note that in both cases a plain http:// protocol is used, even though different port are involved. And a port number of 9443 suggests that you are expected https:// and not http:// here. If this is the case this would explain the error message you got: a plain HTTP request is send because of setting the protocol to http:// instead of https://.

But in the URL shows: https://portainer.my-domain.com/

This protocol here is relevant for the connection between client and nginx, not between nginx and the inner server. The latter one depends on the protocol given in the ProxyPass URL.

I had the same problem with Portainer 2.13.1 behind an Apache2 proxy. I solved it by running the image with the option enabling port 9000 which is Portainer's HTTP port. This assumes that you will block port 9000 externally and access it only via the proxy which is protected by HTTPS. This is my command:

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

My VirtualHost file then points to port 9000 like so:

<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>

Make sure ports 8000, 9000 and 9443 are not accessible externally using a tool like ufw in Linux.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM