Home assistant web server + proxy_protocol on nginx

Hello,
for those who use nginx as reverse proxy serving multiple domains, has anyone successfully combined home assistant and nginx reverse proxy with proxy_protocol feature enabled on the nginx?

My reverse proxy serves many other services on the LAN on different host and is configured with the stream{} upstream{} method. HA web server has been working but without X-Forwarded-For properly working. I read somewhere that enabling proxy_protol on nginx can allow the X-Forwarded-For to work but HA web server broke when it’s turned on.

Any ideas?

Did you follow https://www.home-assistant.io/integrations/http#reverse-proxies?

I’m doing the same thing here, and using proxy_protocol on; in the nginx config (separate from HA) breaks access to HA. I get PR_END_OF_FILE_ERROR in firefox. On other systems, I’ve had to tell them to accept the “proxy protocol”, most recently in lighttpd via extforward.hap-PROXY .

I think this PR aims to implement this. I’m not sure if that will be through an add-on, but it makes sense to have this feature available in the http: block of the HA configuration.

edit: enabling use_x_forwarded_for: and specifying trusted_proxies: as in the link provided by @Tinkerer has no effect.

It has to be some sort of config setting though, because Nginx Proxy Manager which obviously is using Nginx behind the scenes, works without a problem, as long as you remember to enable websockets.

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 172.30.33.0/24
    - 172.30.33.2
    - 192.168.2.17
  ip_ban_enabled: true
  login_attempts_threshold: 8

Let me see if I can pull up the config for Nginx Proxy Manager…

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

  listen 80;
listen [::]:80;

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

  server_name gaia.mydomain.co.uk;

  # 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-1/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/npm-1/privkey.pem;

# Asset Caching
  include conf.d/include/assets.conf;

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

  # HSTS (ngx_http_headers_module is required) (63072000 seconds = 2 years)
  add_header Strict-Transport-Security "max-age=63072000; preload" always;

    # 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-1_access.log proxy;
  error_log /data/logs/proxy-host-1_error.log warn;

  location / {

    # Access Rules
    allow 192.168.2.0/24;
    allow <My IP6 Prefix>::/64;
    deny all;

    # Access checks must...
    
    satisfy any;
    

  # HSTS (ngx_http_headers_module is required) (63072000 seconds = 2 years)
  add_header Strict-Transport-Security "max-age=63072000; preload" always;

    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;
}

Our nginx configuration is different. Alluded to in the OP, we’re using stream {} upstream {}, so SSL isn’t terminated on that nginx instance, e.g.:

stream {
  map $ssl_preread_server_name $name {
    hassio.mydomain.com    hassio;
  }

  upstream hassio {
    server    192.168.1.50:8123;
  }

  server {
    listen                   443;
    proxy_protocol    on;
    proxy_pass         $upstream;
    ssl_preread         on;
}

Headers are not / cannot be edited with stream {}. For this to work, the endpoint must support the proxy protocol.

I’m trying to get that addon working in my own instance to test, but there’s not a clear guide to loading custom add-ons from forks

I got it to work. Note that this uses an addon that I built using @miguelrjim’s changes to the nginx_proxy in the aforementioned PR. It pulls code from my personal github and runs a docker container from my personal dockerhub repository. It is in no way official nor supported.

  1. In the add-on store, add https://github.com/gingerbreadassassin/ha-addons.nginx-proxy_protocol as a repository
  2. Install the nginx addon
  3. In configuration:
    a. Set the Domain to whatever is your HA fqdn
    b. Set proxyProtocol.enabled to true
    c. Set proxyProtocol.realIpFrom to the ip of your “downstream” proxy (whatever is proxying traffic to your HA, 192.168.1.40 in my case)
enabled: true
realIpFrom: 192.168.1.40
  1. Start the nginx_proxy plugin
  2. In the http block of your main HA configuration:
    a. Comment out the ssl options
    b. add:
use_x_forwarded_for: true
trusted_proxies:
  - 172.30.33.0/24

c. Restart HA
6. In your “downstream” proxy, modify your upstream’s port from 8123 to 443

upstream hassio {
  server    192.168.1.50:443;
}
  1. Reload the “downstream” nginx config

You should now be able to access your HA remotely with SSL, using nginx as a TCP proxy with proxy_protocol.