Home assistant docker reverse proxy setup

Hi everyone,

I decided to work on creating a server that held all my projects on one device and use docker for the services.
The current setup is 2 odroid hc1’s , one is openmediavault and the other is home assistant OS.

The new setup will be a rockpro64 NAS server with openmediavault as the natively installed service on armbian buster running docker with a service for radicale caldav server, home assistant and nginx as a reverse proxy.

Through a lot of trial and error I believe I have it working correctly however a more experienced eye cast over my configuration, from the fine home assistant community would be much appreciated, before I write a tutorial for others to benefit from my research.

this is the main part of my configuration.yaml file

# Configure a default setup of Home Assistant (frontend, api, etc)
default_config:

http:
  use_x_forwarded_for: true
  trusted_proxies:
  - 127.0.0.1
  ip_ban_enabled: true
  login_attempts_threshold: 5
device_tracker:
  - platform: nmap_tracker
    hosts: 
      - 192.168.1.179
      - 192.168.1.130
    consider_home: 120
    exclude:
      - 192.168.1.136
    

this is my docker compose file

version: '3.7'
services:
  nginx:
    depends_on:
      - radicale
      - homeassistant 
    image: nginx:latest
    container_name: nginx_reverse_proxy
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /srv/dev-disk-by-label-Files/home/nginx.conf:/etc/nginx/nginx.conf
      - /srv/dev-disk-by-label-Files/home/nginx/error.log:/etc/nginx/error.log
      - /srv/dev-disk-by-label-Files/home/nginx/access.log:/etc/nginx/access.log
      - /etc/letsencrypt/:/etc/letsencrypt/
      - /srv/dev-disk-by-label-Files/home/nginx:/etc/nginx
    restart: unless-stopped
    network_mode: host
 
  radicale:
    image: tomsquest/docker-radicale
    container_name: radicale
    ports:
      - 127.0.0.1:5232:5232
    init: true
    read_only: true
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    cap_add:
      - SETUID
      - SETGID
      - CHOWN
      - KILL
    healthcheck:
      test: curl -f http://127.0.0.1:5232 || exit 1
      interval: 30s
      retries: 3
    restart: unless-stopped
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /srv/dev-disk-by-label-Files/home/radicale/data:/data
      - /srv/dev-disk-by-label-Files/home/radicale/config:/config:ro
      - /srv/dev-disk-by-label-Files/home/radicale/users:/etc/radicale/users

  homeassistant:
    container_name: home-assistant
    image: homeassistant/home-assistant:stable
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /srv/dev-disk-by-label-Files/home/homeassistant:/config
    environment:
      - TZ=Europe/London
    restart: always
    network_mode: host



and this is my nginx.conf file

user www-data;
worker_rlimit_core 500M;
worker_processes 1;

events {

  worker_connections 1024;

}

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

  error_log /etc/nginx/error.log warn;
  ssl_dhparam /etc/nginx/cert/dhparams.pem;
  ssl_prefer_server_ciphers on;
  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_protocols TLSv1.2 TLSv1.3;
  add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
  ssl_stapling on;
  ssl_stapling_verify on;
  ssl_certificate /etc/letsencrypt/live/myserver.duckdns.org/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/myserver.duckdns.org/privkey.pem;
  ssl_trusted_certificate /etc/letsencrypt/live/myserver.duckdns.org/chain.pem;

  server {
    listen 80;
    server_name myserver.duckdns.org;
    return 301 https://$server_name$request_uri;    
  }
  
  server {
    listen 443 ssl http2;
    server_name myserver.duckdns.org;

    location /radicale/ {
    proxy_pass           http://localhost:5232/;
    proxy_set_header     X-Script-Name /radicale;
    proxy_set_header     X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass_header    Authorization;
    }
  }

  server {
    listen 80;
    server_name myhomeassistant.duckdns.org;
    return 301 https://$server_name$request_uri;
  }

  server {
    listen 443 ssl http2;
    server_name myhomeassistant.duckdns.org;

    location / {
        proxy_pass http://localhost:8123;
        proxy_set_header Host $host;
        proxy_set_header     X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
     }

     location /api/websocket {
        proxy_pass http://localhost:8123/api/websocket;
        proxy_set_header Host $host;
        proxy_set_header     X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
     }
  }
}

I’ve then set the external IP in the home assistant UI

can anyone see any obvious issues with my configuration ? is there anything I should add to nginx.conf to increase security or improve performance?

thanks in advance

I see what you’re asking but the security comes from best practice end-to-end.

Assume they gain access into your nginx container, where will they be able to pivot or what information can they gain from that?

Oh and needless to say, that having host access by Home Assistant has its own security implications!

I see what your saying and of course obvious best practices such as a firewall,banning IP’s that fail login requests, limiting container permissions as much as possible and implementing 2 factor authentication login ( which I intend to implement on home assistant)
But what other best practices should I be aware of ?

I know that you can never be entirely secure unless you don’t open ports , but because of the research I did to get this far using several websites to advise on different aspects of my config ,I feel that a second set of eyes reading my config to point out the glaringly obvious things I might of missed will help with my understanding in general.

I originally asked a question on the forum regarding reverse proxying a while back and reading it now I cant believe how limited my understanding was on the topic here if you fancy a good chuckle

I moved leaps and bounds passed this previous ignorance but I’m always keen to learn more and advance my setup .

any advice you can give regarding best practices and missing improvements to my configuration would be great , even if its just pointing me in the direction of great research material would be greatly appreciated .