docs.na.id.au

Design goals

Deployment

How this installation is deployed and why — the design decisions that matter when you are standing up (or improving) your own Home Assistant instance.

Design goals

Postgres over a unix socket

The host’s /var/run/postgresql directory is bind-mounted into the container (as /postgresql), and the recorder DSN points at the socket (postgresql://user:pass@/hass?host=/postgresql...).

Why a socket when HA and the database live on the same machine:

The one constraint: the host’s PostgreSQL unix_socket_directories and the container’s auth settings must line up — the standard, well-trodden local-Postgres setup.

Reverse proxy (nginx)

The pattern in use is a dynamic subdomain reverse proxy: one map block converts the captured subdomain into a backend port, a single HTTP server redirects everything to HTTPS, and one master HTTPS server proxies to 127.0.0.1:$backend_port with WebSocket headers (needed for HA, ESPHome, etc.). Each subdomain also gets its own access log, which makes per-service diagnostics trivial.

map $dynamic_subdomain $backend_port {
    esphome    6052;
    grafana    3000;
    hass       8123;   # one subdomain per HA instance
    ha2        8123;   # same port — different subdomain, same local service
    # add new ones here as you spin them up
}
server {
    listen 80;
    listen [::]:80;
    server_name ~^(?<dynamic_subdomain>.+)\.<tld>$;
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name ~^(?<dynamic_subdomain>.+)\.<tld>$;
    http2 on;
    access_log /var/log/nginx/$dynamic_subdomain-access.log;
    include snippets/ssl-letsencrypt.conf;
    location / {
        proxy_pass http://127.0.0.1:$backend_port;
        include proxy_params;            # centralised Host / X-Forwarded-* headers
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_buffering off;
    }
}

Notes:

Secrets

Everything that varies per instance or that must not be committed lives in a local secrets.yaml (git-ignored) and is referenced from the shared config with !secret <name>. In this installation the per-instance secrets are the instance name, internal_url, external_url, the PostgreSQL DSN, and heartbeat_url (the partner instance’s webhook URL — see High Availability).

Never commit secrets.yaml, service_account.json, or SSH keys. Keep them in .gitignore.

docker compose

The complete compose file (each instance in the cluster runs the same file on its own server — only the config directory’s local secrets.yaml and the Postgres backend differ):

services:
  homeassistant:
    container_name: home-assistant
    image: ghcr.io/home-assistant/home-assistant:stable
    volumes:
      - /var/local/docker-files/home-assistant:/config
      - /Media:/Media
      - /var/run/postgresql:/postgresql
      - /run/dbus:/run/dbus:ro
    environment:
      - TZ=Australia/Perth
    restart: always
#    ports:
#      - 8123:8123
    network_mode: host
    privileged: true

Notes:



Source Disclaimer