HA behind NGINX reverse proxy strange behavior with domain/route URL

I have read all the posts about using NGINX as reverse proxy for HA, but all suggestions I tried didn’t solve my issue.
The configuration files are below. The scenario I want to create is a single domain (let’s call it sub.domain.tld) with various web servers behind an NGINX reverse proxy. One of those services is Home Assistant, to be accessed via https://sub.domain.tld/ha.
I should note that a setup without the /ha route works as advertised but has the side-effect of making the other web servers inaccessible (details below the configuration files) in a strange way.

Content of nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 1024;
    use epoll;
    multi_accept on;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    server_tokens off;
    # Needed for Home Assistant (?)
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

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

    client_body_buffer_size 10M;
    client_max_body_size 100M;
    server_names_hash_bucket_size 96;

    add_header X-Frame-Options DENY;   # don't display inside an iframe

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

Content of /etc/ngnix/sites-enabled/reverse-proxy.conf

(this is of course a softlink from sites-available/)

server {
    listen 80;
    server_name sub.domain.tld;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    server_name sub.domain.tld;

    # SSL settings
    include /etc/nginx/snippets/strong-ssl.conf;
    ssl_certificate /etc/letsencrypt/live/sub.domain.tld/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sub.domain.tld/privkey.pem;

    # Basic auth to protect the sites
    auth_basic "Restricted";
    auth_basic_user_file /etc/nginx/.htpasswd;

    # Let's Encrypt Webroot plugin location -- allow access
    location ^~ /.well-known/acme-challenge/ {
        auth_basic off;
        autoindex on;
    }

    # Home Assistant route
    location /ha/ {
        proxy_pass http://192.168.1.20: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;
    }

    # Other web server route
    location /xyz {
      proxy_pass bla bla;
      ...
    }
}

HA configuration.yaml snippet

...
http:
  api_password: secret
  trusted_networks:
    - 127.0.0.1
    - 192.168.1.0/24
  ip_ban_enabled: true
  login_attempts_threshold: 5
  base_url: sub.domain.tld/ha
  use_x_forwarded_for: true
...

Relevant log files

nginx error.log file

[error] 3670#3670: *35 open() "/usr/share/nginx/html/static/core-2a7d01e45187c7d4635da05065b5e54e.js" failed (2: No such file or directory), client: 192.168.1.152, server: sub.domain.tld, request: "GET /static/core-2a7d01e45187c7d4635da05065b5e54e.js HTTP/1.1", host: "sub.domain.tld", referrer: "https://sub.domain.tld/ha/"
[error] 3670#3670: *35 open() "/usr/share/nginx/html/static/custom-elements-es5-adapter.js" failed (2: No such file or directory), client: 192.168.1.152, server: sub.domain.tld, request: "GET /static/custom-elements-es5-adapter.js HTTP/1.1", host: "sub.domain.tld", referrer: "https://sub.domain.tld/ha/"
[error] 3670#3670: *38 open() "/usr/share/nginx/html/static/frontend-7e13ce36d3141182a62a5b061e87e77a.html" failed (2: No such file or directory), client: 192.168.1.152, server: sub.domain.tld, request: "GET /static/frontend-7e13ce36d3141182a62a5b061e87e77a.html HTTP/1.1", host: "sub.domain.tld", referrer: "https://sub.domain.tld/ha/"
[error] 3670#3670: *37 open() "/usr/share/nginx/html/static/mdi-89074face5529f5fe6fbae49ecb3e88b.html" failed (2: No such file or directory), client: 192.168.1.152, server: sub.domain.tld, request: "GET /static/mdi-89074face5529f5fe6fbae49ecb3e88b.html HTTP/1.1", host: "sub.domain.tld", referrer: "https://sub.domain.tld/ha/"
[error] 3670#3670: *37 open() "/usr/share/nginx/html/frontend/panels/map-565db019147162080c21af962afc097f.html" failed (2: No such file or directory), client: 192.168.1.152, server: sub.domain.tld, request: "GET /frontend/panels/map-565db019147162080c21af962afc097f.html HTTP/1.1", host: "sub.domain.tld", referrer: "https://sub.domain.tld/ha/"
[error] 3670#3670: *38 open() "/usr/share/nginx/html/frontend/panels/kiosk-b40aa5cb52dd7675bea744afcf9eebf8.html" failed (2: No such file or directory), client: 192.168.1.152, server: sub.domain.tld, request: "GET /frontend/panels/kiosk-b40aa5cb52dd7675bea744afcf9eebf8.html HTTP/1.1", host: "sub.domain.tld", referrer: "https://sub.domain.tld/ha/"
[error] 3670#3670: *39 open() "/usr/share/nginx/html/frontend/panels/history-fe2daac10a14f51fa3eb7d23978df1f7.html" failed (2: No such file or directory), client: 192.168.1.152, server: sub.domain.tld, request: "GET /frontend/panels/history-fe2daac10a14f51fa3eb7d23978df1f7.html HTTP/1.1", host: "sub.domain.tld", referrer: "https://sub.domain.tld/ha/"
[error] 3670#3670: *35 open() "/usr/share/nginx/html/frontend/panels/dev-template-928e7b81b9c113b70edc9f4a1d051827.html" failed (2: No such file or directory), client: 192.168.1.152, server: sub.domain.tld, request: "GET /frontend/panels/dev-template-928e7b81b9c113b70edc9f4a1d051827.html HTTP/1.1", host: "sub.domain.tld", referrer: "https://sub.domain.tld/ha/"
[error] 3670#3670: *37 open() "/usr/share/nginx/html/frontend/panels/logbook-771afdcf48dc7e308b0282417d2e02d8.html" failed (2: No such file or directory), client: 192.168.1.152, server: sub.domain.tld, request: "GET /frontend/panels/logbook-771afdcf48dc7e308b0282417d2e02d8.html HTTP/1.1", host: "sub.domain.tld", referrer: "https://sub.domain.tld/ha/"
[error] 3670#3670: *38 open() "/usr/share/nginx/html/frontend/panels/config-61f65e75e39368e07441d7d6a4e36ae3.html" failed (2: No such file or directory), client: 192.168.1.152, server: sub.domain.tld, request: "GET /frontend/panels/config-61f65e75e39368e07441d7d6a4e36ae3.html HTTP/1.1", host: "sub.domain.tld", referrer: "https://sub.domain.tld/ha/"
[error] 3670#3670: *40 open() "/usr/share/nginx/html/frontend/panels/dev-state-7948d3dba058f31517d880df8ed0e857.html" failed (2: No such file or directory), client: 192.168.1.152, server: sub.domain.tld, request: "GET /frontend/panels/dev-state-7948d3dba058f31517d880df8ed0e857.html HTTP/1.1", host: "sub.domain.tld", referrer: "https://sub.domain.tld/ha/"
[error] 3670#3670: *39 open() "/usr/share/nginx/html/frontend/panels/dev-event-d409e7ab537d9fe629126d122345279c.html" failed (2: No such file or directory), client: 192.168.1.152, server: sub.domain.tld, request: "GET /frontend/panels/dev-event-d409e7ab537d9fe629126d122345279c.html HTTP/1.1", host: "sub.domain.tld", referrer: "https://sub.domain.tld/ha/"
[error] 3670#3670: *35 open() "/usr/share/nginx/html/frontend/panels/dev-info-b0e55eb657fd75f21aba2426ac0cedc0.html" failed (2: No such file or directory), client: 192.168.1.152, server: sub.domain.tld, request: "GET /frontend/panels/dev-info-b0e55eb657fd75f21aba2426ac0cedc0.html HTTP/1.1", host: "sub.domain.tld", referrer: "https://sub.domain.tld/ha/"
[error] 3670#3670: *37 open() "/usr/share/nginx/html/frontend/panels/dev-service-422b2c181ee0713fa31d45a64e605baf.html" failed (2: No such file or directory), client: 192.168.1.152, server: sub.domain.tld, request: "GET /frontend/panels/dev-service-422b2c181ee0713fa31d45a64e605baf.html HTTP/1.1", host: "sub.domain.tld", referrer: "https://sub.domain.tld/ha/"
[error] 3670#3670: *41 open() "/usr/share/nginx/html/frontend/panels/dev-mqtt-94b222b013a98583842de3e72d5888c6.html" failed (2: No such file or directory), client: 192.168.1.152, server: sub.domain.tld, request: "GET /frontend/panels/dev-mqtt-94b222b013a98583842de3e72d5888c6.html HTTP/1.1", host: "sub.domain.tld", referrer: "https://sub.domain.tld/ha/"

Home Assistant log file

INFO (MainThread) [homeassistent.components.http] Serving / to 192.168.1.152 (auth: True)

Browser window

Message in browser window (Chrome or FF): “Home Assistant had trouble connecting to the server. TRY AGAIN”

If I leave out the /ha/ part in both the NGINX and HA configuration files, it works fine for HA, but than other routes via the same reverse proxy start to fail, probably because of the javascripts and caching for HA that somehow get loaded for other URL routes (e.g. sub.domain.tld/xyz). These other routes work initially as expected until I visit https://sub.domain.tld/ha once to display the HA page. From then on the previously accessible web server pages fail to load and show a partial HA screen (just the left menu and the blue top bar) instead of their own web pages.

What am I missing here? ;o(

You shouldn’t need the base_url in your config.

you can’t put HA behind a different directory since it essentially has hardcoded paths to /xyz, which will not be proxied correctly to /ha/xyz.

Either put everything else in a different path (sub.domain.tld/otherservice) or use sub subdomians (ha.sub.domain.tld) or actually buy a domain and use as many subdomains as you need (ha.mydomain.tld)

Removing the base_url didn’t work (resulted in 502). But it looks like @nordlead2005 clarifies the issue. The hardcoded path implementation seams consistent with the behavior I’ve witnessed. Looks like I’ll have to create a separate subdomain for HA…

BTW, thanks to both for the swift response! ;o)

@justClouds – How did you change your setup to get it to work? I have been seeing this for days and I’ve tried everything I can think of.

I have switched to subdomain format, e.g. homeassistant.domain.ext instead of domain.ext/homeassistant.

Steps taken:

  1. Add the subdomain to your (public) DNS entries.
  2. Create a virtual host in ‘/etc/nginx/sites-available’ with symlink from ‘…/sites-enabled’ of course. This entry redirects it to the local IP/Port of HA (running on another server in my case).
  3. Generate a Let’s Encrypt certificate for the HA subdomain using certbot.
  4. Open ports 80 and 443 on the system where NGINX runs (iptables or ufw).
  5. Open the HA port on the system where HA runs (iptables or ufw).
    That’s it!

Just let me know if there is any specific step(s) that need clarification.

1 Like

Please mind the following security issue if using HA with NGINX:

Hi, I’m trying to access to 2 home assistant running on proxmox vm and have same problem, I use semplified nginx addon and want to use only 1 myurl.duckdns.org, so reading this post it is not possible to have myurl.duckdns.org/server1 or /server2 etc? but in the simple nginx addon I don’t know how to setup a subdomain to access to almost 2 ha instance running on different local vm, I have very low knowledge-base about this topic and even if I search the web for similar situations I get only complicated answers

Is this issue still the same in current version?

I tried to put HA behind a traefik reverse proxy with “/hassio” as path for HA but it is not loading properly (missing /hassio prefix in all subsequent requests).

I tried to set “external_url” and “internal_url” to https://hostname/hassio but it did not fix it either…