Anyone have an OPNsense reverse-proxy nginx or HAProxy tutorial?

I really want to offload my let’s encrypt/duckdns stuff to my router (running OPNsense) so I can host more services behind TLS. OPNsense has plug-ins for let’s encrypt and nginx or HAProxy so I spent the better part of today trying to get it working with Home Assistant. I tried nginx for a while, and then HAProxy and then back to nginx. After several hours of Googling lots of various terms and trying nearly everything I could find, I gave up.

I’ve already set up my HA installation with the duckdns add-on and let’s encrypt is running on it. I think that’s why I cannot get to HTTP version of my Home Assistant, only HTTPS. Is there a way to enable both secure HTTP and insecure at the same time? I found a few threads in the community of people who are using nginx reverse-proxy with Home Assistant possibly in TLS mode but it looks like they’re running it manually so they’ve hacked the config files. OPNsense allows some of that but it seems to be all menu driven…

Anyone have a good resource for setting up OPNsense to handle reverse-proxy using nginx or HAProxy for Home Assistant?

No, Home Assistant either runs on ssl or it doesn’t. You can’t do both.

If you have opnsense, then you can run an openvpn server on it (https://docs.opnsense.org/manual/how-tos/sslvpn_client.html) and connect on all your internal stuff through a proper vpn and not with a proxy.
You can even use TOTP to improve authentication part.
There is also an openvpn client on Android and it works well.
If you follow the guide step by step, at the end, it just works. A lot of steps though.

Thanks @greengolfer, yeah, I have that set up and I’m also using TOTP with it for 2-step security. I can use the Android app to get to my home new work and it works great. I don’t like using the VPN except in an emergency because takes extra steps and time. I like the idea of seamless use of mobile apps integrated with my home network via solid encryption.

I’ve now got a few services that I’m hosting and I’d like to put them all behind a security layer so I don’t need to kick off OpenVPN when I want to use something remotely. Some of the services, like Home Assistant, already have TLS coverage and some do not. I’m sure the further we go, the more I’m going to want to expose so I’d like to understand how to do it and implement this solution now.

The main reason I’d like to move on this right now is because of Google Photos locking down their storage space. I’ve found that there are open sourced apps like Nextcloud and Owncloud which can be used for the same cloud-like Google Photos experience allowing me to seamlessly take pictures and back them up to storage (at home). Anyway, I see the cloud as something powerful but also potentially nefarious. Because of that, I’d rather have my own version of it that I control.

Yesterday, I found this page: Reverse Proxy and Webserver — OPNsense documentation that explains a few methods to implementation, similar to what I’m talking about:

  1. Breaking up the connection on the firewall (down- and upstream are using TLS)
  2. Decrypt an encrypted upstream (downstream plain, upstream TLS protected)
  3. TLS Offloading (downstream is TLS protected, upstream is plain)
  4. TLS Passthough

The problem is that the webpage shows these methods that could be deployed but but not how to deploy them. I’ve found a few videos on YouTube for implementing some of these strategies but it seems to all be with pfSense. I’ve watched two or three of them but the interface is just different enough that many of the seemingly important inputs don’t map to the OPNsense framework. That’s basically what I spent all day yesterday trying to do.

Some options:

I actually found those both yesterday too and tried to follow them. I think the biggest problem I’m having is that I have two cases I’m trying to cover. Services with TLS enabled internally (like HA with DuckDNS/Let’s Encrypt) and services without TLS enabled internally. These all only cover non-TLS-enabled services.

I tried to follow this guys tutorial about pfsense with duckdns, haproxy, and let’s encrypt and interestingly he’s using virtual IPs to route the traffic for reverse-proxy or something. I was able to get a service without TLS to work that way but not a service with TLS.

Ooh, I really like this idea. I’m also not a big fan of putting all my eggs in one basket. I’ll have to look into that.

I just found this post from @Tinkerer :

If you’re using a proxy server then your internal URL for Home Assistant on 192.168.0.42 will look like:

http://192.168.0.42:8123

Is it true that when there’s a proxy I won’t be able to use the external duckdns.org address from within my home network to get to HA?

  1. A native, not proxied HA instance is using HTTP or HTTPS but not both. This is “kind of” a limitation of HA
  2. Normally if you have an HTTPS proxy, then, there is usually no real need to run HTTPS on HA as well

So, the message from Tinkerer is just that. I think.

However, at the moment, you have HA running with HTTPS (and duckdns)?
If from your LAN, you go to httpS://HA_IP_ADDRESS:8123 it should work with a warning from the browser. Right?
If that is the case, then on NGINX you should proxy to the internal IP and not duckdns one. From a network point of view, it doesn’t make a lot of sense to proxy on the LAN to an external IP. Your opnsense firewall will need to punch a lot of holes to make it work and I am not sure it will even work.

If you want to:

  1. keep HA on HTTPS and nevertheless have the proxy for external access
  2. avoid the whining of the browser when you do httpS://HA_IP_ADDRESS:8123 you can install yet another tool :slight_smile:
    With PiHole on your LAN (always useful, avoid ads!) you can have a “fake” DNS server and resolve something.duckdns.org as your local IP. So, everyone will be happy: HA continue using HTTPS, your browser will not complain about the mismatch for the IP address vs. your domain.
    When on the LAN with that setup, you will not go through the proxy. But, who cares…

If you are able to manage opnsense, you can do it :slight_smile:

Correct, that’s how I have it configured right now. It actually works great because OPNsense supports DNS hair-pining so I can use the external duckdns name internally and it’s completely transparent with HTTPS. Last night, I played with disabling HA’s secure HTTPS so I could try to implement #2 above using “TLS Offloading” but I wasn’t successful.

I just tried this because I have pihole on my network and it doesn’t work. If I insert a Local DNS Record on PiHole to redirect my something.duckdns.org name to my local IP for my Home Assistant it results in a “retry” connection screen and won’t come up. There must be something else I need to do?

I verified that the name was redirected using nslookup. As soon as I restored the value to my external IP, everything started working again. I tried it both on my OPNsense unbound DNS and my PiHole and both resulted in the “retry” connection error screen.

It’s weird. I have this setup and it just works…
I guess your internal PC is using pihole as the primary DNS?
So nslookup gives you the real internet IP, but, when you try to access it (don’t forget the :8123 !) it doesn’t?

What is the address declared in HA configuration at internal_url and external_url ? Not sure this makes a difference, but, makes sense to check.

Yeah part of my DHCP rules but I made sure to check what I was doing on the client by issuing nslookups to both my Pi-Hole and my OPNsense DNS services at each step.

  1. Add OPNsense DNS override to point to internal address on external name query
  2. Checked that nslookup resolved on both OPNsense and Pi-Hole devices to the new internal IP
  3. Tried to navigate to my something.duckdns.org site and got the “Retry” message
  4. Undid the override
  5. Issued an ipconfig /flushdns
  6. Checked that nslookup resolved correctly again, may have had to restart the Pi-Hole resolver to clear it out.
  7. Reloaded webpage and everything worked.

I currently have my https://something.duckdns.org address as external_url and nothing declared as my internal but I tried setting internal_url to https://hassio_machine:8123 and it didn’t seem to matter.

I tried it again just now and I know why it broke. It’s because the local machine isn’t watching on 443, it’s watching on 8123 so if I remap the Pi-Hole to local address, then use https://something.duckdns.org:8123 it works. I think this just means that I need to map my internal machine with the same port number (443) as the external port number.

Is there any reason why Home Assistant doesn’t just use 443 anyway? Maybe that was just to avoid collision with other services…

SWEET!!! I got it working, I just had to use the solution I found here: Local and remote access by single URL

# Example configuration.yaml entry
http:
  server_port: 443

That enabled the same port internal as external (and of course updating my router mapping to I forward to 443 instead of 8123 and BOOM! It works!

And port above 1024 are accessible to non root users. So, having HA on 443 would me HA running as root…

Told you so :wink: Don’t forget the :8123 !

I saw your last email! All good now. Enjoy !

What the heck does this mean? HA isn’t running as root just because I assigned it to 443. I think you have your wires crossed…

Maybe, but I am not the only one.


Ports below 1024 are called “privileged” ports.

And you think this means that the service is running as root?

Not necessarily. But, either the security is lowered on the system to allow ports below 1024 to be opened by non root, or the binary as a setuid positioned, or it runs as root.
Otherwise, on a linux system out of the box, a program run by “normal” user isn’t be allowed to bind to a port below 1024.