Reverse proxy using NGINX

Guys, just for info. There is all information in this thread to make it work. My problem was that the response time was very slow if I go via my domain and reverse proxy. But the problem was in my ASUS RT-AX56U router. I do all port forwarding and everything worked, except for slow loading time.

In the end, I have to disable DoS protection in the Asus router. I can’t tweak it but just disable it. And now it works.

I will put all words for google, hopefully someone will find my post: slow loading time nginx home assistant reverse proxy

1 Like

Yeah — I found this too. DDOS protection, QOS, etc — turn it all off!

Hi Batts, are you running Home Assistant in a VM external to your Docker Network?

I run HAOS on a dedicated machine. Different box to my unraid/docker containers.

Ah right, I am trying to get it working with a VM running on my unraid server (so would think pointing it to the IP would work the same as yours does). But just cannot get it to work. Cloudflare or the Port Forward may be the issue. Just cannot figure it out :smiley:

Not up to date on VMs but shouldn’t be much different once the VM is accessible via a LAN IP

Ah cool, cheers. Any chance you are using cloudflare? I am struggling with this info from the top of the swag proxy config for HA.

## Version 2021/10/11
# make sure that your dns has a cname set for homeassistant and that your homeassistant container is not using a base url

# As of homeassistant 2021.7.0, it is now required to define the network range your proxy resides in, this is done in Homeassitants configuration.yaml

And my cloudflare config - I would have thought the CNAME and A record that SWAG uses for the rest of my docker containers would suffice?

I make a specific CNAME for every container I proxy through swag.
So I have one called homeassistant pointing to @ which is the A record. But if yours is already working with other containers I suppose it’s fine.

Until one doesn’t work! Might try a specific cname for this one

Mine are proxied also, I see yours aren’t. A and cnames

Whatever guide I followed said if you just use an A name record you do not proxy it, only for cnames (or something along those lines).

All working now though that I added a specific cname record for home assistant

Are there any advantages on using NGINX vs direct HA with SSL in terms of security? I mean if it’s breached both are in the same boat. No?

If you have them in separate containers, they’re separate boats. It also gives you a little more flexibility. And, you don’t have to restart Home Assistant whenever the cert renews.

Edited post with short description of problem and solution. Original post at the end.

HA only saw proxy IP address, not the real client IP. I was running HA and Nginx Proxy Manager as docker containers.

Apparently, it has something to do with how Docker networks work: Document how to get real remote client ip for service running in container · Issue #15086 · moby/moby · GitHub.

To solve it, you need to:

  • use --net=host
  • disable the userland proxy
  • install Nginx on the host

I went for option 3 and installed Nginx in a VM on a completely different host. All is good now!

Original post

In my case HA is still blocking the proxy IP address. I already checked the documentation and compared to my configuration a dozen times, but can’t figure out what is wrong. I hope a couple of extra pair of eyes can help.

Server architecture:

  • Server running docker with IP 192.168.0.8
  • HA runs in docker, using host as network_mode.
  • Nginx Proxy Manager runs in docker. No network_mode specified.

Nginx Proxy Manager configuration:

  • Forward to 192.168.0.8 on port 8123.
  • Ticked ‘Block Common Exploits’
  • Ticked ‘Websockets support’
  • Ticked ‘Force SSL’
  • Ticked ‘HTTP/2 support’
  • Nothing in ‘Custom locations’ and ‘Advanced’ tab

The proxy as such works, because I can use my own domain to reach HA. On the internal network, I’m also using the public domain.

Digging into the raw Nginx Proxy Manager config files:

server {
  set $forward_scheme http;
  set $server         "192.168.0.8";
  set $port           8123;

  listen 80;
listen [::]:80;

listen 443 ssl http2;
listen [::]:443 ssl http2;

  server_name my.custom.domain;

  # Let's Encrypt SSL
  include conf.d/include/letsencrypt-acme-challenge.conf;
  include conf.d/include/ssl-ciphers.conf;
  ssl_certificate /etc/letsencrypt/live/npm-3/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/npm-3/privkey.pem;

  # Block Exploits
  include conf.d/include/block-exploits.conf;

    # Force SSL
    include conf.d/include/force-ssl.conf;

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_http_version 1.1;

  access_log /data/logs/proxy-host-4_access.log proxy;
  error_log /data/logs/proxy-host-4_error.log warn;

  location / {  
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;
    proxy_http_version 1.1;

    # Proxy!
    include conf.d/include/proxy.conf;
  }

  # Custom
  include /data/nginx/custom/server_proxy[.]conf;
}

proxy.conf:

add_header       X-Served-By $host;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Scheme $scheme;
proxy_set_header X-Forwarded-Proto  $scheme;
proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP          $remote_addr;
proxy_pass       $forward_scheme://$server:$port$request_uri;

HA configuration:

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 172.21.0.0/16
  ip_ban_enabled: true
  login_attempts_threshold: 5

Signing in with faulty credentials gives the following log message in HA:

WARNING (MainThread) [homeassistant.components.http.ban] Login attempt or request with invalid authentication from 172.21.0.1 (172.21.0.1). ...

In logs of Nginx Proxy Manager I see this:

POST https my.custom.domain "/auth/login_flow/cffa75b8bc3155346c38890081a141e7" [Client 172.21.0.1] [Length 204] [Gzip -] [Sent-to 192.168.0.8] 

Note the client IP addres…

Any idea what is wrong? Sorry for the lengthy post, just wanted to give as much info as possible.

I’m hoping to run HA on a separate VM from the VM that’s hosting my Swag-letsencrypt(nginx) container (because I’m looking for the full HASS OS experience and I dont think I can get that via docker image?) I’ve looked at some solutions for configuring nginx but nothing seems to be working. I’m getting either a 502 or a 400 error when I hit my subdomain address.

Is there way add trusted proxies without editing configuration.yaml?

Thank you, thank you, thank you. Spent like 2h or so today by trying different guides and always something did not work. This is the only guide that I got working with HA. All the lines under “location” are not mentioned in standard guides at all. Thanks a lot!

Hope someone can help me out…
I want to setup my existing Nginx server with nginxui to forward my sub domain.

Nginx: 10.1.254.1
HA: 10.1.254.12
Domain: home.mydomain.com

Ideally I want to use the GUI.
I started with:

Then I added:

Nothing of this works…
I do see the HA logo but the connection can’t be established.

I noticed that under “Advanced” and und “Custom locations” I could add additional configs. However I am not sure how this is compatible with the rest.

Hope someone can help!

Solution:
My fault.
I had to add the following lines to the configuration.yaml

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 10.1.254.1

The IP was wrong because of the old proxy I had.
Custom location is not needed.
Problem solved.

1 Like
configuration.yaml


http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 172.22.0.3
    - ::1

it worked for me.

Hi all,
I have been trying for several days to do a reverse proxy with Nginx for homeassistant, but unfortunately the page stops at the hass logo.

I would like to pass a location (folder) for example:
https://xxxxxxxxxx.ddns.net/hass/
Pero it stops at the logo.
My Nginx configuration:

upstream homeassistant {
        server 192.168.1.2:8123;
        keepalive 64;
    }

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

#################
server {
    listen 0.0.0.0:80;
    root /var/www/html;
    charset utf-8; 
    #sendfile off;  
    client_max_body_size 100m; 
    # Required for LE certificate enrollment using certbot
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }  
    error_page  404              /404.html;
    error_page  403              /403.html;
    location = /favicon.ico { access_log off; log_not_found off; }  
    location = /robots.txt { access_log off; log_not_found off; }
    # Deny hidden files (.htaccess, .htpasswd, .DS_Store).
    location ~ /\.ht { deny all; }  
    location ~ /\.DS { deny all; } 
    location / {
        index index.php;
    }
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
        allow 192.168.0.0/16;
        allow 172.16.0.0/12;
        allow 127.0.0.1;
        allow 10.0.0.0/8;
        deny all;
    } 
 location /api/websocket {
    proxy_pass http://homeassistant/api/websocket;
    }
 location /api/webhook/blabla {
    proxy_pass http://homeassistant/api/webhook/blabla;
    }
 location /api/alexa/smart_home {
    proxy_pass http://homeassistant/api/alexa/smart_home;
    }
################ 
    ########################
    # mappings             #
    ########################
    location ~ \.(js|css|jpg|sh|exe|asp|net|env) {
        expires 5d;
        try_files $uri $uri/ =403;
        return 403;
        access_log      off;
        log_not_found   off;
    }

}
#############################
server {
    listen 0.0.0.0:443 default_server ssl http2;
    root /var/www/html;
    server_name xxxxxxxxxxx.ddns.net;
    ssl_certificate /etc/nginx/ssl/live/xxxxxxxx.ddns.net/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/live/xxxxxxxx.ddns.net/privkey.pem;
  	# Improve HTTPS performance with session resumption
  	ssl_session_cache shared:SSL:10m;
  	ssl_session_timeout 10m;
	# Enable server-side protection against BEAST attacks
  	ssl_protocols TLSv1.2;
	ssl_prefer_server_ciphers on;
	ssl_ciphers "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384";
	# Aditional Security Headers
	# HSTS
	add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";

	add_header X-Frame-Options DENY always;

	add_header X-Content-Type-Options nosniff always;

	add_header X-Xss-Protection "1; mode=block" always;

  	ssl_stapling on;
  	ssl_stapling_verify on;
  	ssl_trusted_certificate /etc/nginx/ssl/live/xxxxxxxxx.ddns.net/fullchain.pem;
  	resolver 1.1.1.1 1.0.0.1 [2606:4700:4700::1111] [2606:4700:4700::1001] valid=300s; # Cloudflare
  	resolver_timeout 5s;    
    charset utf-8;        
    error_page  404              /404.html;
    error_page  403              /403.html;
    proxy_buffering off;
    location = /favicon.ico { access_log off; log_not_found off; }  
    location = /robots.txt { access_log off; log_not_found off; }  
    location / {
        index index.php;
    }
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass php:9000;
        #fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name;
    }
    # Deny hidden files (.htaccess, .htpasswd, .DS_Store).
    location ~ /\.ht { deny all; }  
    location ~ /\.DS { deny all; } 
    location ~ \.php$ {
        deny all;
        access_log      off;
        log_not_found   off;
    }
########################
# mappings             #
########################
 #location ~ \.(js|css|png|jpg|sh|exe|asp|net|env) {
 #  expires 5d;
 #   try_files $uri $uri/ =403;
 #   return 404;
 #   access_log      off;
 #   log_not_found   off;
 #   }
########################
#certbot conf
 location /.well-known/acme-challenge/ {
    root /var/www/certbot;
    }
#######

#Home Assistant
    location /ha/ {
        proxy_pass http://homeassistant/;
        proxy_redirect / /ha/;
        proxy_cookie_path / /ha/;
        proxy_set_header Host $host;
        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 X-Forwarded-Protocol $scheme;
        proxy_set_header X-Url-Scheme $scheme;
    }

  location /has/ {    
    ### force timeouts if one of backend is died ##
    proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
    proxy_set_header        Accept-Encoding   "";
    proxy_set_header        Host            $host;
    proxy_set_header        X-Real-IP       $remote_addr;
    proxy_set_header        X-Forwarded-Proto $scheme;
    add_header                  Front-End-Https   on;
    add_header       Strict-Transport-Security "max-age=15552000";
    proxy_http_version 1.1;
    proxy_set_header        Upgrade $http_upgrade;
    proxy_set_header        Connection "upgrade";
    proxy_pass  http://homeassistant/;
    proxy_redirect     off;
  }
  location /api/websocket {
    proxy_pass http://homeassistant/api/websocket;
    proxy_set_header        Accept-Encoding   "";
    proxy_set_header        Host            $host;
    proxy_set_header        X-Real-IP       $remote_addr;
    proxy_set_header        Host $host;
    proxy_set_header        X-Forwarded-Proto $scheme;
    add_header                 Front-End-Https   on;
    add_header       Strict-Transport-Security "max-age=15552000";
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_redirect     off;   
  }
# location /api/websocket {
#    proxy_pass http://homeassistant/api/websocket;
#    }
 location /api/webhook/blabla  {
    proxy_pass http://homeassistant/api/webhook/blabla;
    }
 location /api/alexa/smart_home {
    proxy_pass http://homeassistant/api/alexa/smart_home;
    }
################    
}
########################

proxy.conf:

# Timeout if the real server is dead
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;

# Proxy Connection Settings
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size    256k;
proxy_connect_timeout 240;
proxy_headers_hash_bucket_size 128;
proxy_headers_hash_max_size 1024;
proxy_http_version 1.1;
proxy_read_timeout 240;
proxy_redirect  http://  $scheme://;
proxy_send_timeout 240;

# Proxy Cache and Cookie Settings
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;

# Proxy Header Settings
proxy_set_header Connection $connection_upgrade;
proxy_set_header Early-Data $ssl_early_data;
proxy_set_header Host $host;
proxy_set_header Proxy "";
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Real-IP $remote_addr;

Log Nginx:

172.19.0.1 - - [07/Nov/2023:17:16:00 +0100] "GET /ha/ HTTP/2.0" 200 4876 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15" "-"
172.19.0.1 - - [07/Nov/2023:17:16:01 +0100] "GET /fontawesome/main.js HTTP/2.0" 404 589 "https://xxxxxxxxxx.ddns.net/ha/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15" "-"
172.19.0.1 - - [07/Nov/2023:17:16:01 +0100] "GET /webrtc/webrtc-camera.js?v=v3.5.0 HTTP/2.0" 404 589 "https://xxxxxxxxxx.ddns.net/ha/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15" "-"
172.19.0.1 - - [07/Nov/2023:17:16:01 +0100] "GET /hacsfiles/iconset.js HTTP/2.0" 404 589 "https://xxxxxxxxxx.ddns.net/ha/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15" "-"
172.19.0.1 - - [07/Nov/2023:17:16:01 +0100] "GET /manifest.json HTTP/2.0" 404 589 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15" "-"
172.19.0.1 - - [07/Nov/2023:17:16:01 +0100] "GET /hacsfiles/lovelace-card-mod/card-mod.js HTTP/2.0" 404 589 "https://xxxxxxxxxx.ddns.net/ha/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15" "-"
172.19.0.1 - - [07/Nov/2023:17:16:01 +0100] "GET /browser_mod.js HTTP/2.0" 404 589 "https://xxxxxxxxx.ddns.net/ha/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15" "-"

Could somebody help me?