Proxying Cockpit over Apache with LetsEncrypt

Cockpit works on a web socket combined with http/https interface, Web Socket is used to deliver active content back and forth between client and server. But when a proxy sits in between, it needs to be configured likely.

We will need to create a virtual host, give the virtual host a domain name, install TLS/SSL certificate and set up a reverse proxy. (instructions adapted from here and here)

Set up Apache X-Frame-Options

Edit Apache X-Frame-Options policy by running:

sudo nano /etc/apache2/conf-available/ssl-params.conf

Find a line that says Header always set X-Frame-Options DENY and change it to Header always set X-Frame-Options SAMEORIGIN

Set up Apache Virtual Host

Install Apache web server with the following command:

sudo apt install apache2

Run the following command to create an Apache virtual host file. Replace the domain name with your actual domain name for Cockpit. Don’t forget to create an A record for this domain name.

sudo nano /etc/apache2/sites-available/cockpit.your-domain.com.conf

Put the following text into the file.

<VirtualHost *:80>
 ServerName cockpit.your-domain.com
</VirtualHost>

Save and close the file. Enable this virtual host with the following command:

sudo a2ensite cockpit.your-domain.com.conf

Then restart Apache.

sudo systemctl restart apache2

TLS/SSL certificate with Let’s Encrypt

HTTPS helps us prevent man-in-the-middle attack and password sniffing. We can obtain a free TLS/SSL certificate from Let’s Encrypt CA. First Let’s install the certbot client. The client is still named letsnecrypt in Ubuntu repository. The following command will install the client and apache plugin.

sudo apt install letsencrypt python-letsencrypt-apache

Now issue the following command to obtain a free TLS/SSL certificate. Replace the text with your actual data.

sudo letsencrypt --apache --agree-tos --email YOUR-EMAIL-ADDRESS -d COCKPIT.YOUR-DOMAIN.COM

You will be asked to choose easy or secure. It’s recommended to choose secure so that all http requests will be redirected to https.

Once you hit the OK button, a free TLS/SSL certificate is obtained and installed on the Apache virtual host.

Now copy the certificates information into the cockpit certificate folder using the following commands

cat /etc/letsencrypt/live/cockpit.your-domain.com/fullchain.pem >> /etc/cockpit/ws-certs.d/1-my-cert.cert

cat /etc/letsencrypt/live/cockpit.your-domain.com/privkey.pem >> /etc/cockpit/ws-certs.d/1-my-cert.cert

You will need to do this every time the certificate gets renewed (every 3 months).

Set up Apache Reverse Proxy in a Subdomain

To be able to proxy traffic using Apache, run the following commands to enable each of these Apache modules.

sudo a2enmod proxy proxy_wstunnel proxy_http ssl rewrite

Then run the following command to edit the new virtual host file created by Let’s Encrypt (certbot) client.

sudo nano /etc/apache2/sites-enabled/cockpit.your-domain.com-le-ssl.conf

Change this file so it looks like the following.

<IfModule mod_ssl.c>
<VirtualHost *:443>
  ServerName cockpit.your-domain.com
  SSLCertificateFile /etc/letsencrypt/live/cockpit.your-domain.com/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/cockpit.your-domain.com/privkey.pem
  Include /etc/letsencrypt/options-ssl-apache.conf

  ProxyPreserveHost On
  ProxyRequests Off

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

  # Proxy to your local cockpit instance
  ProxyPass / http://127.0.0.1:9090/
  ProxyPassReverse / http://127.0.0.1:9090/
</VirtualHost>
</IfModule>

With Apache 2.4.47 or later, this could also be written as:

<IfModule mod_ssl.c>
<VirtualHost *:443>
  ServerName cockpit.your-domain.com
  SSLCertificateFile /etc/letsencrypt/live/cockpit.your-domain.com/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/cockpit.your-domain.com/privkey.pem
  Include /etc/letsencrypt/options-ssl-apache.conf

  ProxyPreserveHost On
  ProxyRequests Off

  # Proxy to your local cockpit instance
  ProxyPass / http://127.0.0.1:9090/ upgrade=websocket
  ProxyPassReverse / http://127.0.0.1:9090/
</VirtualHost>
</IfModule>

Save and close the file. Then restart Apache web server.

sudo systemctl restart apache2

Make sure you changed /etc/cockpit/cockpit.conf to include the following:

[WebService]
Origins = https://cockpit.your-domain.com http://127.0.0.1:9090
ProtocolHeader = X-Forwarded-Proto
AllowUnencrypted = true

Restart cockpit

sudo systemctl restart cockpit.service

You can now login to cockpit at the specified subdomain.

Set up Apache Reverse Proxy in a Subdirectory

The following steps allow proxying traffic from a subdirectory of an existing Apache virtual host.
Important: /cockpit/ and /cockpit+/ are reserved. Do not use any reserved names listed here. This example will use /UrlRoot/.

Run the following command to enable all the required Apache modules.

sudo a2enmod proxy proxy_wstunnel proxy_http ssl rewrite

Then run the following command to edit the new virtual host file created by Let’s Encrypt (certbot) client.

sudo nano /etc/apache2/sites-enabled/cockpit.your-domain.com-le-ssl.conf

If you are not using certbot, an example file normally exists at the following:

sudo nano /etc/apache2/sites-available/default-ssl.conf

Otherwise, consult your man pages/packager for the correct filepath, or follow the prior certbot tutorial, or create a site manually.

Assuming you followed the prior LetsEncrypt strategy, are using the common default file, or have an existing virtual host such that the file starts with <IfModule mod_ssl.c> <VirtualHost *:443> and has the appropriate directives for TLS/SSL, append the following to your virtual host, replacing UrlRoot with your desired subdirectory name.

                SSLProxyEngine          On
                # required module
                RewriteEngine           On
                # required module
                ProxyPreserveHost       On
                # required
                ProxyRequests           Off
                # RECOMMENDED, disables forwarding, see https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#proxyrequests
                ProxyErrorOverride      Off
                # if possible, present cockpit's error pages instead of apache's
                SSLProxyVerify optional_no_ca
                # cockpit has a self-signed cert by default, therefore no CA
                SSLProxyCheckPeerCN Off
                # SSL error without this
                SSLProxyCheckPeerName Off
                # SSL error without this
                SSLProxyCheckPeerExpire Off
                # recommended since potential SSL error without this
                RequestHeader set "X-Forwarded-Proto" "https"
                # required by cockpit.conf
                # following is adapted from https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html
                RewriteCond %{HTTP:Upgrade} websocket [NC]
                RewriteCond %{HTTP:Connection} upgrade [NC]
                RewriteRule "^/UrlRoot/(.*)" "wss://127.0.0.1:9090/UrlRoot/$1" [P,L]
                # when websocket in upgrade AND
                # within UrlRoot, rewrite proxy with wss://
                RewriteCond ${HTTP:Upgrade} !=websocket [NC]
                RewriteRule "^/UrlRoot/(.*)" "https://127.0.0.1:9090/UrlRoot/$1" [P,L]
                # when no websocket upgrade AND
                # within UrlRoot, rewrite proxy with https://
        </VirtualHost>
</IfModule>

Save and close the file. Then restart Apache web server.

sudo systemctl restart apache2

Lastly, change the /etc/cockpit/cockpit.conf to include the following:

[WebService]
Origins = https://your-domain.com http://127.0.0.1:9090
ProtocolHeader = X-Forwarded-Proto
UrlRoot = /UrlRoot/

Replace /UrlRoot/ with your choice of subdirectory, though keep the enclosing /.
This method does not require you to disable encryption (AllowUnencrypted = true) since the self-signed certificate is allowed.

Restart cockpit

sudo systemctl restart cockpit.service

You can now login to cockpit at https://your-domain.com/UrlRoot/.