Reverse proxy using NGINX

does it work when you are not on home network?
some home routers/CPE don’t support “hairpinning” and wont let you use the external DNS name

does http://192.168.1.2:8123 work?

Hello,

it doesn’t work either inside the home network or outside.

Thank you very much.

how do I find the trusted proxies?

guys with the latest update with the SWAG container it has been so rubbish I have lost all connectivity to my HA outside my LAN. I have followed every single step in reconfiguring according to SWAG instructions but it wouldnt work.

I just struggled with my reverse proxy setup and homeassistant. Then I enabled websockets support on my proxy. Voila! It Works!

Hello guys, I am getting 502 Bad Gateway. My nginx conf:
Can you help me please?

server {
listen 80 default_server;
server_name domain.xyz;

return 301 https://$host$request_uri;

}

server {
listen 443 ssl;
server_name domain.xyz;

ssl on;
ssl_certificate /etc/letsencrypt/live/domain.xyz/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain.xyz/privkey.pem;
ssl_prefer_server_ciphers on;

location / {
    proxy_pass http://192.168.0.73:8123;
    proxy_set_header Host $host;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

location /api/websocket {
    proxy_pass http://192.168.0.73:8123/api/websocket;
    proxy_set_header Host $host;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

}

}

My host machine is 192.168.0.110
And HA is running (the HAOS) on that machine via official KVM image

I run HAOS on a VM with a NixOS host. I wanted to share my NixOS reverse proxy config in case that’s useful for anyone.

Disclaimer: This is lightly modified from my config and thus is technically untested.

This assumes the use of Let’s Encrypt and replaces steps 2 - 7 and the nginx configuration part of step 9 (as of the time I’m writing this). Be sure to change the VirtualHost to your dns entry and proxyPass to your HAOS IP and defaults.email to whatever email address you want to give to Let’s Encrypt.

  services.nginx = {
    enable = true;
    recommendedProxySettings = true;
    recommendedTlsSettings = true;    
    virtualHosts."your.example.com" = {
      forceSSL = true;
      enableACME = true;
      locations."/" = {
        proxyPass = "http://192.168.1.9:8123"; 
        proxyWebsockets = true;
      };
    };

  security.acme = {
    acceptTerms = true;
    defaults.email = "[email protected]";
  };

Make sure to poke the appropriate holes (80, 443) in networking.firewall.allowedTCPPorts as well if needed.

I’d like to also suggest adding another empty VirtualHost with a different but valid dns entry and setting it as default so if someone or some script stumbles across your IP, it obfuscates your HAOS instance.

That’d probably look like this, also untested but I do something similar.

    virtualHosts."obfuscation.your.example" = {
      default = true;
      forceSSL = true;
      enableACME = true;
    };

Thanks a lot for this guide.
I have spent a day on integrating alexa… It was working with my previous smarthome solution… But I could not get it to work with HA.
Using your nginx config I made it. Thanks!

I’d be curious to know the reason for my failure before though…

server {
    listen [::]:443 ssl;
    server_name homeassistant.x.myonlineportal.net;
    ssl_certificate /etc/letsencrypt/live/x.myonlineportal.net/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/x.myonlineportal.net/privkey.pem;
    access_log /var/log/nginx/homeassistant.log combined;
    #ssl_protocols TLSv1 TSLv1.3
    #ssl_protocols TLSv1.2 TLSv1.3;
    error_log /var/log/nginx/homeassistant-error.log debug;
    include /etc/nginx/include.d/common;
    client_max_body_size 512M;
    client_body_timeout 300s;
    location / {
        proxy_pass http://192.168.177.185:8123/;
        proxy_set_header Host $host;
        proxy_http_version 1.1;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        #proxy_set_header Upgrade $http_upgrade;
        #proxy_set_header Connection $connection_upgrade;
        proxy_set_header Upgrade       $http_upgrade;
        proxy_set_header Connection    $connection_upgrade;
        #proxy_set_header Host $host;
        #proxy_set_header X-Real-IP $remote_addr;
        #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }


}

If you see an obvious reason, I’d be happy to learn. Otherwise: never mind :slight_smile: I just came here to thank you!

Greetings,
Hendrik

Can recommend everyone that’s using nginx to add this to there serverblock

    location ~ /\.ht {
       access_log off;
       log_not_found off;
       deny all;
    }
    location = /robots.txt {
       allow all;
       log_not_found off;
       access_log off;
       try_files $uri /index.php?$args;
    }

Do you have this above your server block?

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

Note, if you are using docker-compose with homeassistant, nginx, and certbot containers on the same device, you would have to create a docker network to allow communication between home assistant and nginx. Without a docker network, I had Bad 400 and 502 errors. Unfortunately, this solution would break network_mode: host on homeassistant. Therefore, I had to migrate from nginx and certbot to swag to allow me to maintain homeassistant network discovery.

For those running ESPHome and having problems talking to devices (i.e. logs / upgrades), if you’re exposing HA on a non-standard port (i.e. not 443), you need to slightly modify your nginx config as follows:

proxy_set_header Host $host;

becomes

proxy_set_header Host $host:8123;

(assuming you’re exposing HA on TCP:8123 rather than TCP:443

This allows web sockets to be correctly mapped through, and ESPHome returned to full health.

1 Like

How is your esphome device connnected to your HA then? Externally and via proxy?

Ah, no - you misunderstand me. I use nginx to access HA remotely and while everything else works fine, you can’t use the ESPHome UI to access the device (e.g. open the log window, recompile updates) as nginx incorrect rewrites the external port. All of the tutorials (including this one) seem to use this same nginx config, which works fine for everything, apart from esphome, so I thought I’d share this fix.

1 Like

You should just make the static ip of nginx-proxy-manager static by --ip 172.18.0.4
Use the ip that you see from “docker inspect network …”.
All related docker container should be in the same network.

And then you can set the config like this:

http:
  # For extra security set this to only accept connections on localhost if NGINX is on the same machine
  # Uncommenting this will mean that you can only reach Home Assistant using the proxy, not directly via IP from other clients.
  # server_host: 127.0.0.1
  use_x_forwarded_for: true
  # You must set the trusted proxy IP address so that Home Assistant will properly accept connections
  # Set this to your NGINX machine IP, or localhost if hosted on the same machine.
  trusted_proxies: 172.18.0.4

Hi there,

I’ve same problem but never fund a solution.

Do you do it?

Hate to necropost, but I just got Nginx working as a reverse proxy for HA. I’m running Ubuntu, and I’m running HA in a container (not that it should make a big difference).

# /etc/nginx/sites-available/default
server {
        listen 80 default_server;
        listen [::]:80 default_server;

        # put your desired domain(s) here.
        #
        # I have a bunch of stuff on this server, so I use *
        # If HA is the only thing on this machine, I could have
        # used ha.robin.lan instead.
        server_name *.robin.lan;

        return 302 https://$server_name$request_uri;
}
# /etc/nginx/sites-available/home-assistant
server {
        # SSL configuration
        listen 443 ssl;
        listen [::]:443 ssl;

        # all the SSL junk lives here.
        # I followed this guide to set it up: https://www.howtogeek.com/devops/how-to-create-and-use-self-signed-ssl-on-nginx/
        include snippets/self-signed.conf;

        # put your domain(s) here too
        server_name ha.robin.lan www.ha.robin.lan;

        location / {
                proxy_pass http://127.0.0.1:8123/;
                proxy_set_header Host $http_host;
                proxy_redirect off;
                proxy_http_version 1.1;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
        }
}
# Add this to HA's configuration.yaml:
http:
  use_x_forwarded_for: true
  trusted_proxies: 127.0.0.1

Don’t forget to enable the nginx sites:

ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default
ln -s /etc/nginx/sites-available/home-assistant /etc/nginx/sites-enabled/home-assistant

Then restart the services:

systemctl restart home-assistant@user
systemctl restart nginx

Hi, the guide should be updated regarding the nginx configuration.

It is better to use the /conf.d/ directory instead of sites-available and sites-enabled.
As soon as a configuration file in /conf.d/ has the ending .conf, it is used by nginx.
If the .conf file-extension is removed, the configuration file is ignored by nginx.

This makes it easier to manage the various pages, you immediately have an overview of which pages exist and which of them are enabled, and you don’t have to fiddle around with symlinks, where a lot can go wrong.

Furthermore, step 6. Enable the Home Assistant NGINX configuration would also be omitted, as the activation is already done, adding the .config extension.

Step 5 would have to be updated to the following:

## 5. Install configuration file in NGINX

Create a new file `/etc/nginx/conf.d/hass.conf` and paste the content of the below shown configuration file (which you will need to edit) into the new file.

it’s definitely working here. I’ve just adapted the configuration for a proxy running on a distant server but on the same network.
Thank you for sharing.

Update Sept 2024.
I can confirm that the majority of these instruction are still ‘current’ as of late Sept 2024.
Especially the all important step 9 - settings in NGINX configutation. I have not found such specific instructions/settings elsewhere.

My build is Raspberry Pi 4 running Raspberry OS. HA in Docker.

All attempts to install Certbot/LetsEncrypt and Nginx in docker failed so I am happy to follow these steps which leave these components outside of docker.
Step by step commentary
2. Install NGINX on your server. As listed
Note: notwithstanding comments elsewhere in this thread, this still installed with folders ‘/etc/nginx/sites-available’ and ‘sites-enabled’
3. Obtain an SSL certificate
The Certbot instructions strongly encourage use of ‘snap’ so I did
Certbot Instructions | Certbot is a menu driven set of instructions. I chose software=nginx, System=‘Linux Snap’
After several false starts I actually let it edit the nginx configuration automatically. It looks like all the lines it played with are marked ‘# managed by Certbot’ so you get some idea what it did
4. Create dhparams file
Not done - seems step 3 already included one in ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
5. Install configuration file in NGINX
Because of the entries made by certbot to the ‘default’ configuration file I chose to merge the settings shown in this post directly into default; hopefully keeping the ability for certbot to keep the file updated.
None of the changes were near lines managed by certbot
6. Enable the Home Assistant NGINX configuration
skipped because ‘default’ is still linked
7. Start NGINX
Before starting this the command sudo nginx -t will test/validate the file.
If you had already started nging then use sudo systemctl reload nginx
8. Port forwarding. Exactly as listed
9. Configure Home Assistant
As listed. I had been mucking around trying to work out what the proxy address was. So the comment “or 127.0.0.1 if hosted on the same machine” was particularly useful to me.

Changes made to ‘default’ file are

# jc added (from https://community.home-assistant.io/t/reverse-proxy-using-nginx/196954) >>>>>>
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}
# <<<<<<<<

    ## >>>>>>>>>>>>>>> jc added / replaced
    proxy_buffering off;

    location / {
        proxy_pass http://127.0.0.1:8123;
        proxy_set_header Host $host;
        proxy_redirect http:// https://;
        proxy_http_version 1.1;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
    ## <<<<<<<<
    ## >>>> jc removed
    ##	location / {
    ##		# First attempt to serve request as file, then
    ##		# as directory, then fall back to displaying a 404.
    ##		try_files $uri $uri/ =404;
    ##	}
    ## <<<<<<<

After this external access is achieved by
https://<<mydomain>>.duckdns.org
Notes:

  • no port is mentioned.
  • this works from web browser
  • this works as ‘external’ setting in the HA App

Internal (ie at home) access is achieved by
http://192.168.1.54:8123
Notes:

  • port is mentioned.
  • it is http not https
  • the local hostname can be used but the HA app never seems to find it.
  • this works from web browser
  • this works as ‘internal’ setting in the HA App

I hope this refresh help others.
JC