Apache proxy with SSL

I try to use a apache reverse proxy to connect to an instante of HA running with SSL enabled.

https://home-assistant.io/docs/ecosystem/apache/ only refers to a http proxy but not https.

my apache config is:

<IfModule mod_ssl.c>
<VirtualHost *:443>
ProxyPreserveHost On
ProxyRequests Off
ServerName servername
ServerAdmin mymail

# Lets encrypt for external ssl
SSLEngine On
SSLCertificateFile /etc/letsencrypt/live/xx.xx.de/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/xx.xx.de/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/xx.xx.de/chain.pem
Include /etc/letsencrypt/options-ssl-apache.conf

# Singed with my own signing authority. malte.crt added but its also installed.
SSLProxyEngine On
SSLProxyCACertificateFile /usr/local/share/ca-certificates/malte.crt
SSLProxyCheckPeerName Off  # Makes no difference if on or off
#SSLProxyCheckPeerExpire On
# I tested ws:// and wss:// but no diference
ProxyPass /api/websocket wss://serv:443/api/websocket
ProxyPassReverse /api/websocket wss://serv:443/api/websocket
ProxyPass / https://serv:443/
ProxyPassReverse / https://serv:443/
</VirtualHost>

Upon connection the apache error log shows:

[Thu Aug 17 07:49:28.575671 2017] [proxy:error] [pid 20692] (502)Unknown error 502:    [client xx.xx.xxx.xxx:53950] AH01084: pass request body failed to 172.16.1.102:443 (serv), referer: https://xx.xx.de/
[Thu Aug 17 07:49:28.575850 2017] [proxy:error] [pid 20692] [client xx.xx.xxx.xxx:53950] AH00898: Error during SSL Handshake with remote server returned by /static/custom-elements-es5-adapter.js, referer: https://xx.xx.de/
[Thu Aug 17 07:49:28.575933 2017] [proxy_http:error] [pid 20692] [client xx.xx.xxx.xxx:53950] AH01097: pass request body failed to 172.16.1.102:443 (serv) from xx.xx.xxx.xxx (), referer: https://xx.xx.de/
[Thu Aug 17 07:49:28.709895 2017] [proxy:error] [pid 20685] (502)Unknown error 502: [client xx.xx.xxx.xxx:53952] AH01084: pass request body failed to 172.16.1.102:443 (serv), referer: https://xx.xx.xx/
[Thu Aug 17 07:49:28.710064 2017] [proxy:error] [pid 20685] [client xx.xx.xxx.xxx:53952] AH00898: Error during SSL Handshake with remote server returned by /static/webcomponents-lite.js, referer: https://xx.xx.de/
[Thu Aug 17 07:49:28.710144 2017] [proxy_http:error] [pid 20685] [client xx.xx.xxx.xxx:53952] AH01097: pass request body failed to 172.16.1.102:443 (serv) from xx.xx.xxx.xxx (), referer: https://xx.xx.de/
[Thu Aug 17 07:49:29.487714 2017] [proxy:error] [pid 20686] (502)Unknown error 502: [client xx.xx.xxx.xxx:53954] AH01084: pass request body failed to 172.16.1.102:443 (serv)
[Thu Aug 17 07:49:29.487907 2017] [proxy:error] [pid 20686] [client xx.xx.xxx.xxx:53954] AH00898: Error during SSL Handshake with remote server returned by /service_worker.js
[Thu Aug 17 07:49:29.487986 2017] [proxy_http:error] [pid 20686] [client xx.xx.xxx.xxx:53954] AH01097: pass request body failed to 172.16.1.102:443 (serv) from xx.xx.xxx.xxx ()

and the cennection log shows:

xx.xx.xxx.xxx - - [17/Aug/2017:07:58:17 +0200] "GET /static/custom-elements-es5-adapter.js HTTP/1.1" 500 3963 "https://xx.xx.de/" "Mozilla/5.0 (X11; Linux x86_64; rv:55.0) Gecko/20100101 Firefox/55.0"
xx.xx.xxx.xxx - - [17/Aug/2017:07:58:17 +0200] "GET /static/webcomponents-lite.js HTTP/1.1" 500 3945 "https://xx.xx.de/" "Mozilla/5.0 (X11; Linux x86_64; rv:55.0) Gecko/20100101 Firefox/55.0"
xx.xx.xxx.xxx - - [17/Aug/2017:07:58:18 +0200] "GET /service_worker.js HTTP/1.1" 500 819 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:55.0) Gecko/20100101 Firefox/55.0"

To some extend it seems to work, because I see tha HA banner, but then it shows:

Home Assistant had trouble
connecting to the server.

It appears as if you have created some sort of loop in your Apache configuration.
Apache is listening on port 443, so HA cannot listen on the same port, but that’s where you sent the proxy requests to.
You are saying that you have enabled SSL in HA as well, so what port is HA listening on? That port number needs to go into the serv:443 part in all the proxy pass directives.

oh answering the mail. doesn’t show up here.

I don’t believe I created a loop, because the apache proxy is physically a different machine, then the machine where HA is running on. So it looks like:

Internet -----> Apache Proxy pc ------> HA pc (serv)

Therefore it should be fine if both proxy and HA run on port 443. Or my I wrong?

Cheers

My bad. In that case, you can use the same port numbers.

I start to believe this is a bug. I can not seem to find any mistake in the config, and looking at the error log, the

makes me believe that HA is somehow responding gibberish

The error messages indicate that the issue happens during the SSL handshake, i.e. while the secure connection is being established. Since your HA certificate is self signed, Apache may stumble upon that. You could increase the log level and see if that shows any more detail why the handshake fails.

Ahh that was the hint I needed. I thought apache was already logging everything, but it has loglevels as well ^^. So I found the issue. I needed to add:

SSLProxyCheckPeerCN Off to my config. Now it works.

I found out by adding: LogLevel info to my config and then I reconnected. Afterwards I could find:

[Mon Aug 21 20:57:47.824662 2017] [ssl:info] [pid 9526] [remote 172.16.1.10:443] AH02005: SSL Proxy: Peer certificate CN mismatch: Certificate CN: serv Requested hostname: xx.xx.de
In my Log file. And then a crosscheck with the documentation of apache showed, that there is the option SSLProxyCheckPeerCN to toggle this.

So Next step would be to find out how to fix this really instead of just turning it off. I Issued the certificate singing request with a Common Name of: serv because, that is the name of the machine where HA is running on. Looking at the log, I assume apache tries to connect via ip address, and that obviously fails, because its not the CN of the certificate.

I google around to see if I can find a solution.

1 Like

hi Deisi!

your configuration is bad because you encrypt tls twice:
client <–tls–>apache <–tls–> hass
i’m proposing to you this scheme:
client <–tls–>apache <–http–> hass

<VirtualHost *:443>
  ProxyPreserveHost On
  ProxyRequests Off
  ServerName domain.com
  
  SSLProxyEngine On
  ProxyPass "/" "http://localhost:8123/"
  ProxyPassReverse "/" "http://localhost:8123/"

  RewriteEngine on
  RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
  RewriteCond %{HTTP:CONNECTION} ^Upgrade$ [NC]
  RewriteRule .* ws://localhost:8123%{REQUEST_URI} [P]

  SSLEngine on
  SSLCertificateFile /etc/letsencrypt/live/domain.com/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/domain.com/privkey.pem
  SSLCertificateChainFile  /etc/letsencrypt/live/domain.com/chain.pem

  ErrorLog /var/log/apache2/domain.com.error.log
  TransferLog /var/log/apache2/domain.com.access.log
</VirtualHost>


<VirtualHost *:80>
  ServerName domain.com
  ServerSignature Off

  RewriteEngine on
  RewriteCond %{HTTPS} !=on
  RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [NE,R,L]
</VirtualHost>

replace domain.com to your domain

p.s. sorry for my english.:slightly_smiling_face:

and i recomend you to use client ssl authentification:
my result cfg file is:

<VirtualHost *:443>`
  ProxyPreserveHost On
  ProxyRequests Off
  ServerName domain.com
  SSLProxyEngine On

  ProxyPass "/" "http://localhost:8123/"
  ProxyPassReverse "/" "http://localhost:8123/"
  RewriteEngine on
  RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
  RewriteCond %{HTTP:CONNECTION} ^Upgrade$ [NC]
  RewriteRule .* ws://localhost:8123%{REQUEST_URI} [P]
  SSLEngine on
  SSLCertificateFile /etc/letsencrypt/live/domain.com/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/domain.com/privkey.pem
  SSLCertificateChainFile  /etc/letsencrypt/live/domain.com/chain.pem

  ErrorLog /var/log/apache2/domain.com.error.log
  TransferLog /var/log/apache2/domain.com.access.log

  SSLVerifyClient require
  SSLVerifyDepth 10
  SSLCACertificateFile /home/rishat/mySslCerts/clientAuth/ca.cer
</VirtualHost>


<VirtualHost *:80>
  ServerName domain.com
  ServerSignature Off

  RewriteEngine on
  RewriteCond %{HTTPS} !=on
  RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [NE,R,L]
</VirtualHost>

you’ll need ca and client ssl certs

2 Likes

Hello,

I have my apache server available at https:mydomain.ddns.net and I want to access HA via https:home.mydomai.ddns.net.

But I’m not getting the setup working.

I use a rpi3.

Anyone using apache with HA could help me?

Thank´s

1 Like

i migrated to nginx, https://home-assistant.io/docs/ecosystem/nginx/

Have you set up the “home…” hostname with DDNS or does that service support wildcard subdomains? Have you added a virtual host configuration entry for that new hostname in Apache? Have you set up an SSL certificate for that new hostname? Are requests to that histname arriving at Apache? Have you followed the documentation to set up the proxypass rules that forward all requests to HA?

I wanted to point out something for macos users:

Don’t rely on OSX-Server for apache anymore. Unfortunately it’s a dead end. I switched to the preinstalled apache on mac os high sierra.

I’m looking for the same configuration.
Unfortunately Apache Proxy manual is unusefull for me.
Main_domaim woking well on 443. But https connection not working for hassio, because start with main_domain certs…
Is it working scheme if hassio start on differnt PC (pri3)? Looks like working only on the same localhost.

I spent hours trying to find out why the default Apache Proxy config for the RewriteEngine broke my other ProxyPass’s within the same VirtualHost.

E.G.

<VirtualHost *:443>
   ServerName home.example.org
   ProxyPreserveHost On
   ProxyRequests off
   ProxyPass /api/websocket ws://localhost:8123/api/websocket
   ProxyPassReverse /api/websocket ws://localhost:8123/api/websocket
   ProxyPass / http://localhost:8123/
   ProxyPassReverse / http://localhost:8123/
 
   RewriteEngine on
   RewriteCond %{HTTP:Upgrade} =websocket [NC]
   RewriteRule /(.*)  ws://localhost:8123/$1 [P,L]
   RewriteCond %{HTTP:Upgrade} !=websocket [NC]
   RewriteRule /(.*)  http://localhost:8123/$1 [P,L]
</VirtualHost>

This however, breaks my other reverse proxies within the same server, such as

 ProxyPass /pihole/ http://192.168.1.10:80/admin/
 ProxyPassReverse /pihole/ http://192.168.1.10:80/admin/

As I believe the provided RewriteRule example effectively nullifies the other reverse proxies.

Your method seems to fix this:

   RewriteEngine on
   RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
   RewriteCond %{HTTP:CONNECTION} ^Upgrade$ [NC]
   RewriteRule .* ws://localhost:8123%{REQUEST_URI} [P]

Is this correct?