Reverse proxy (minus tls), with subdomain pointing to another RPi with HASS & Let's Encrypt

Hi,

I finally got Let’s Encrypt add-on working on HASS, it’s great! But I do not want my HASS RPi to face the traffic from the internet - I already have a Reverse Proxy on nginx for other reasons (hosting websites - using sub domains). After reading all the post on SSL, Reverse Proxy, etc, I am not convinced anyone else is asking for the same config. So, in summary:


  1. I configured subdomain.domain.pro in GoDaddy - and confirmed, it works to bring it to my fixed IP.

  2. My router has a Port Forward to the NGINX RPi on ports 80 and 443.

  3. On above NGINX - I have configured to point subdomain traffic received to the internal RPi with HASS, using port 8123; without any Let’s Encrypt certs, or any tls setup in the forwarding conf. (conf-1)

  4. On HASS, I have Let’s Encrypt setup and working - I have tested it by disabling port forwarding to the NGINX RPi, and enabling port forwarding on the router to the HASS RPi. See conf-2 for configuration.yaml setup


The above setup does bring up the HASS interface, asks me for credentials, spins a wheel for a time, then goes to a screen with HASS logo, and “retry”. That’s it.

My configs:


conf-1: NGINX

  • This conf - under /sites-available, linked to /sites-enabled, nginx started again:
#HTTP Server
server {
  listen 80;
  server_name [subdomain].[domain].pro ;
}

# HTTPS Server
server {
  server_name [subdomain].[domain].pro;

  location / {
      proxy_pass https://[IP of hass RPi]:8123 ;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_buffering off;
  }
} 

conf-2: hass configuration.yaml

  • As mentioned before - Let’s Encrypt correctly setup, as I have tested it by pointing port forward for traffic 80 here - in stead of to the reverse proxy.
# For Let's Encrypt
http:
  base_url:         https://[subdomain].[domain].pro
  ssl_certificate:  /ssl/fullchain.pem
  ssl_key:          /ssl/privkey.pem
  use_x_forwarded_for: true
  trusted_proxies: [IP of the reverse proxy]

Chrome reports:

This site can’t be reached [subdomain].[domain].pro unexpectedly closed the connection.
Try:

Checking the connection
Checking the proxy and the firewall
ERR_CONNECTION_CLOSED

Any pointers?

Ever heard of Nginx Proxy Manager? Saved me a lot of headaches!

Actually, not, looking into it now…, I see it’s Docker based - on the NGINX I run bare-boned NGINX & failtoban - this could be an option for that replacement. Still looking for opinions of havingHASS RPi separately with Certs, and NGING passing through outside requests. Thank you!

Your reverse proxy needs to be the one serving up your Let’s Encrypt SSL certificate, not Home Assistant. Right now it looks like your reverse proxy is listening for unencrypted HTTP traffic on [subdomain].[domain].pro and trying to then encrypt that traffic and pass it on to HA. Which has multiple problems:

  1. Generally people want external traffic to be encrypted and don’t really care if traffic moving between two machines on their LAN is encrypted, the exact opposite of what you appear to be doing
  2. You are connecting to HA via https://[IP of hass RPi]:8123 but HA is serving up an SSL certificate which says [subdomain].[domain].pro. Since the common name on the certificate does not match the host name NGinx will rightfully reject that invalid certificate and refuse to talk to HA using it.

Instead would suggest doing this:

  1. Have NGinx listen on port 443
  2. Move the Let’s Encrypt certificate over to that machine and have it serve up that certificate
  3. Proxy the traffic to http://[IP of hass RPi]:8123
  4. Turn off all the SSL options in HA and just have it listen for unencrypted traffic. But don’t forward any ports on your router to it so only LAN traffic is unencrypted, external traffic is encrypted and runs through NGinx

You’ll also need to set up a process to move the certificate from the one RPI to the other every time it updates. Or alternatively just set up a automated certbot process on the RPi running the reverse proxy and uninstall the Let’s Encrypt add-on. Or use a different reverse proxy with automated certificate management built in like Caddy 2 or Nginx Proxy Manager and let it take care of everything for you.

Thank you! Issuing certs on the NGINX RPi - doing it with an Ansible role - works well - also for my other sites, but will look into your suggestions - maybe cleaner solution.

Regarding HASS RPi - setting that one up without TLS - pity - as ESPHome have cool functionality which only works if it has TLS. I tried to copy the keys across from the process that issues them in HASS - but NGINX reported an error - so I created a 2nd subdomain - which I then issued Lets Encrypt certs for.

Regarding configuration.yaml - Do I then need this?

http:
  use_x_forwarded_for: true
  trusted_proxies: [IP of Proxy]

Without above, (whilst hitting site https://[subdomain].[domain].pro from) - I get to the login screen of the HASS Pi (yeah!!), …

Screenshot 2021-06-20 at 21.32.00

but when I log in - it waits… and shows the logo, and Retry… that’s all.

Screenshot 2021-06-20 at 21.36.27

Aggg No !!!

Also thinking if it could be my setup on Unifi routers - I have a “hosting” VLAN where NGINX and HASS sits. Wondering if any other rules needed there.

Just tried configuration.yaml with

http:
  use_x_forwarded_for: true
  trusted_proxies: [IP of Proxy]

Coming in with https://[subdomain].[domain].pro takes one to the # Welcome to nginx! page - which says to me its not forwarding the request - or its not accepted.

But, using the (http://) internal IP - works. Both on Browser, and iOS. Looking into concept ‘harirpin NAT’ - here.

Interesting. Well if there is a benefit you can have HA be accessible over SSL, you just need to use a private cert.

Let’s encrypt will only give you a certificate for a public domain that it can verify your ownership of. And then that certificate can only be used in conjunction with that domain. It won’t give you a certificate for a private domain or IP address because it has no way to verify your ownership (and it means something different on every LAN network).

But that doesn’t mean you can’t get an SSL certificate, you just have to get a self-signed one. Here’s a decent looking guide I found from some quick searching for making one. Basically just make your own root CA then make a certificate with the common name set to the domain you access the HA RPI at and sign them with your root CA. Then you can move your root CA certificate over to your reverse proxy and provide using the proxy_ssl_trusted_certificate directive so it knows to trust the CA that signed the cert HA is serving up.

However the annoying part is that you’ll have to manually get each device to trust your CA by installing its certificate in its list of trusted CAs and instructions for that vary per device. Also browsers have extra rules you’ll have to meet or they won’t trust the certificate anyway, like ensuring the expiration date no more then 365 days away. In short its a hassle but its not impossible, depends whether its worthwhile to you.

Yes. That’s important otherwise HA will think all logins are coming from your proxy which will mess up reporting, logging and fail2ban stuff (among other things I’m sure). You need that so HA knows the actual IP of who’s logging in for each session. Also I think recent releases added more stringent requirements around proxies so it may not work at all without that anymore, not sure.

Well that’s weird. Not sure about the VLAN, I would think if it was a VLAN issue then the two devices wouldn’t see each other at all and you wouldn’t even get to the login screen but not sure. Anything relevant in the logs of either of those devices?

If this is the problem there is a super easy test. Take your mobile phone and try to visit https://[subdomain].[domain].pro while connected to your wifi. Then turn off wifi so you’re on your mobile network and try again. If the first one fails and the second one succeeds then a hairpin NAT problem is likely. If they both fail to get to the login screen or both succeed then its probably something else.

Let me look into this.