HA Settings to Expose Externally - Nginx on Separate Host

Hello, could use a bit of assistance exposing my HA externally.
I already have an Nginx instance running in my network on a separate physical host machine that listens on 80/443. I want to add in the logic to expose HA externally there, as going the route of using HA Nginx/Duck/Let’s Encrypt will interfere.

What I’ve done so far.

  • Obtained new duckdns domain for HA
  • Configured DDNS in my router to update duckdns with external IP (Success)
  • Generated new SSL certs from Let’s Encrypt on machine that hosts Nginx (not HA machine)
  • Edited Nginx config file for new server block (Accepted config, looks good)

What I’m confused about:

  • Where in HA do I set this up? Searching around, I see some http entries that could go in the config.yaml file. I also see some settings for Internal and External URLs in Configuration/General UI.

Most of the documentation out there assumes you are running Duck/LE/Nginx from the HA Add-On store. I am not… Any advice?

For further context:

  • 192.168.1.12 hosts Nginx as well as a separate exposed service (example1.ddns.net)
  • 192.168.1.13 hosts Home Assistant (Docker on Ubuntu) which will be externally exposed as example2.duckdns.org
  • All 80/443 requests forward to 192.168.1.12 at the router level to be handled by Nginx.
  • Nginx config forwards example1.ddns.net to 127.0.0.1:5000 and example2.duckdns.org to 192.168.1.13:8123

Thanks

I’ve done something similar with HomeAssistant Core (virtualenv) running on a Banana Pi on my home network, and an nginx reverse proxy on a Linode VPS that I run a variety of services on. No DuckDNS, although I have a static home IP. The DNS is handled by Linode’s DNS manager.

My router (a Ubiquiti USG) is set up to forward inbound port 8123 to the Pi only from the VPS’s IP address. The VPS nginx is set up as below with a Let’s Encrypt certificate, listening for traffic on port 443 for a domain I use for HA only.

Once you’ve solved the “safely expose your proxy machine to the internet”, the rest should be straightforward port / websocket forwarding.

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    send_timeout 300;
    server_name MY_DOMAIN;

    access_log /var/log/nginx/access.log timed_combined;
    error_log /var/log/nginx/error.log;

    ssl_certificate /etc/letsencrypt/live/MY_DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/MY_DOMAIN/privkey.pem;
    ssl_stapling on;
    ssl_stapling_file /etc/letsencrypt/live/MY_DOMAIN/ocsp.resp;
    ssl_trusted_certificate /etc/letsencrypt/live/MY_DOMAIN/fullchain.pem;
    ssl_dhparam /etc/nginx/ssl/dhparams.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # Use HTTP Strict Transport Security to force secure connections only
    add_header Strict-Transport-Security max-age=31536000;

    location / {
        proxy_pass http://MY_HOME_IP:8123;
        proxy_set_header Host             $host;
        proxy_set_header        X-Forwarded-Proto   $scheme;
        proxy_intercept_errors  on;
        proxy_http_version      1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Thanks. I think I’ve got the nginx config part figured. I’m more so wondering about the settings within HomeKit itself to accept these connections. I see some settings in Configuration/General for Internal and External URL, and I also see some using http entries in main config.yaml file.

If you can access HA (not HomeKit?!) from within your network using an IP address — which is all nginx needs to do — I think you may be over-complicating things. I don’t have an external URL set in my config, and the internal is the IP:port of the HA on the LAN (http://192.168.x.x:8123). I have made no other adjustments beyond router port forwarding to deal with the incoming traffic from the VPS.

For the HA Android app, I use the same internal and https://MY_DOMAIN as the external. That then gives me seamless access to my HA whether I’m home or away.