6

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.

Michael
  • 313
  • 1
  • 4
  • 10
  • Have you managed to get a solution to this @Michael? I have exactly the same issue with Apache proxy and Portainer 2.13.1. It worked with an older version until I upgraded. I can access using the internal IP address https://192.168.0.100:9443, but with a browser warning that this connection is insecure because this access bypasses the Letencrypt SSL certificate defined in the proxy config file.. – Lukuluba Jun 18 '22 at 09:25
  • @Lukuluba yes I found a solution and updated my post. – Michael Jun 19 '22 at 17:21

2 Answers2

4

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.

Lukuluba
  • 381
  • 1
  • 5
  • 18
2

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.

Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • Ok, that makes clearly sense. I changed the ProxyPass to `https://192.168.178.69:9443`. But then I got an Internal Server Error when I try to call the site: `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` Do you know what I forgot? Or were I can find information about that? – Michael Jun 11 '22 at 20:19
  • 1
    @Michael: Basically nothing is known about your inner application. Is the URL `https://192.168.178.69:9443` even working, i.e. can you successfully access exactly this URL from the server using curl, wget or similar tools? And why do you want to use a `https://...:9443` where where in the other (working) place you use `http://...:8080`? – Steffen Ullrich Jun 12 '22 at 02:29
  • Maybe I didn't understand you correctly. I want that portainer.my-domain.com is leading to `https://192.168.178.69:9443` and the request should be in https not in http. But portainer is telling me, that the request is in http, so I can't use portainer. So I understand your answer like this, that the request from client to my reverse proxy is in https, but the request from my reserve proxy to portainer is in http and changing the proxy pass from `http://192.168.178.69:9443/` to `https://192.168.178.69:9443/` could solve the problem. Did I understand this right? – Michael Jun 12 '22 at 05:30
  • And when I am calling `http://192.168.178.69:9443/` I am getting the message `Client sent an HTTP request to an HTTPS server.`. But if I am calling `https://192.168.178.69:9443/` I am getting the message from the browser that the connection is not secure and I can add an exception for it to enter the site. And than it works, but this should not be the normal case. I want to enter the site with a secure connection – Michael Jun 12 '22 at 05:48
  • 1
    @Michael: *"I am getting the message from the browser that the connection is not secure"* - and nginx is stumbling over the same problem - that's why it fails. Again, why do you insist on using `https://...9443` in ProxyPass instead of `http://...:8080` (different protocol and different port) as you do in the working part of the configuration? – Steffen Ullrich Jun 12 '22 at 06:07