Websockets not working while running Portainer with Httpd proxying

1.3k views Asked by At

I've set up the Portainer UI as a docker container, and it's working great if I connect my browser to port 9000 (as in http://foo.bar.com:9000). I can navigate around the UI and open up container consoles (which use websockets) without a problem.

But, what I need to do i connect with SSL (as in https://foo.bar.com).

I set up an httpd container on the same machine, and gave it the following configuration file:

<VirtualHost *:443>
  ServerName foo.bar.com

  ProxyPass / http://foo.bar.com:9000/
  ProxyPassReverse / http://foo.bar.com:9000/
  RequestHeader set X-Forwarded-Proto "https"

  <Location /api/websocket/>
    RewriteEngine on
    RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
    RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
    RewriteRule /api/websocket/(.*) ws://foo.bar.com:9000/api/websocket/$1 [P]
  </Location>
  
  ## SSL directives
  SSLEngine on
  SSLCertificateFile      "/usr/local/apache2/conf/server.crt"
  SSLCertificateKeyFile   "/usr/local/apache2/conf/server.key"

  ## Logging
  ServerSignature Off
  ErrorLog "logs/error_ssl.log"
  CustomLog "logs/access_ssl.log" common 

</VirtualHost>

Both httpd and portainer are being brought up by separate docker-compose.yml files.

Now, the Portainer web pages still come up just fine, but the consoles for the containers won't work. Somehow, my websocket configuration above is broken. Any ideas on what I might be doing wrong?

2

There are 2 answers

0
John Fisher On

After hours of playing with it, I finally got this to work and wanted to share. First, at least in httpd 2.4, you need to explicitly load mod_proxy_wstunnel.so so make sure and put a LoadModule in. Until you do that, nothing will work.

Here is the httpd configuration that was successful:

<VirtualHost *:443>
  ServerName foo.bar.com
  ProxyPreserveHost on
  ProxyPreserveHost On
  ProxyRequests Off

  # allow for upgrading to websockets
  RewriteEngine On
  RewriteCond %{HTTP:Upgrade} =websocket [NC]
  RewriteRule ^/?(.*) ws://foo.bar.com:9000/$1 [P,L]
  RewriteCond %{HTTP:Upgrade} !=websocket [NC]
  RewriteRule ^/(.*)           http://foo.bar.com:9000/$1 [P,L]

  ProxyPass "/" "http://foo.bar.com:9000/"
  ProxyPassReverse "/" "http://foo.bar.com:9000/"

  ## SSL directives
  SSLEngine on
  SSLCertificateFile "/usr/local/apache2/conf/server.crt"
  SSLCertificateKeyFile "/usr/local/apache2/conf/server.key"

  ## Logging
  ServerSignature Off
  ErrorLog "logs/error_ssl.log"
  CustomLog "logs/access_ssl.log" common 

</VirtualHost>
0
Tymose On

Thanks a lot - saved me lot of trouble setting this up in Apache. I'm using it in local network only so I don't care much about https and certs so I've modified it bit to go through http

<VirtualHost *:80>
  ServerName foo.bar.com
  ServerAlias foo.bar.alias.com
  ProxyPreserveHost On
  ProxyRequests Off

  # allow for upgrading to websockets
  RewriteEngine On
  RewriteCond %{HTTP:Upgrade} =websocket [NC]
  RewriteRule ^/?(.*) ws://localhost:9000/$1 [P,L]
  RewriteCond %{HTTP:Upgrade} !=websocket [NC]
  RewriteRule ^/(.*)           http://localhost:9000/$1 [P,L]

  ProxyPass "/" "http://localhost:9000/"
  ProxyPassReverse "/" "http://localhost:9000/"

  # Logging

  ErrorLog ${APACHE_LOG_DIR}/portainer_error.log
  CustomLog ${APACHE_LOG_DIR}/portainer_access.log combined
</VirtualHost>