Home Automation

Home Assistant remote access with DynIP

Home Assistant runs happily on a LAN, but the moment you want the dashboard from outside — the companion app away from home, a webhook from a SaaS, voice integrations that aren't local-only — you need a stable public hostname, TLS, and a reverse proxy that handles HA's heavy WebSocket traffic. DynIP gives you the hostname (even on a residential connection where the IP rotates), and a small reverse proxy in front of HA handles the rest. This guide covers the full path: DDNS updates, the reverse proxy, the HA-side config that everyone forgets, and the smoke tests.

What you'll need

  • A running Home Assistant install (HA OS, HA Container, or Supervised — the network setup is the same).
  • A DynIP zone, e.g. ha.ddns.dynip.dev or a name under your own BYOD namespace.
  • A reverse proxy host with port 443 reachable from the internet. This can be the same machine as HA, a separate VM, or a small container. The examples below use Caddy; Traefik works just as well.
  • Port 443 forwarded from your router to the reverse proxy (port 80 is not required — DynIP's DNS-01 challenge issues certs without it).

Setup

1. Get a DynIP hostname pointing at your public IP

Create the zone in the DynIP dashboard and run the snippet from the snippets-generator on a host that stays online — HA itself works, or any always-on box on your LAN. The dashboard generates a cURL/PowerShell/Python/router-native command that updates the zone every few minutes; pick the one that matches what you've got.

2. Stand up the reverse proxy

Follow the Caddy + DynIP guide to get a Caddy with the RFC 2136 plugin installed, then add a site block for HA. The key difference from a vanilla reverse-proxy config is the explicit WebSocket upgrade handling — HA's frontend uses a long-lived WebSocket for all state updates, and a misconfigured proxy will produce a UI that loads and then sits at "Connecting…" forever.

ha.ddns.dynip.dev {
    reverse_proxy 192.168.1.50:8123
}

Caddy's reverse_proxy directive handles WebSocket upgrades automatically — no extra config needed. If you're using nginx, you'll need explicit proxy_set_header Upgrade $http_upgrade and proxy_set_header Connection "upgrade" directives.

3. Tell Home Assistant about the proxy

By default HA refuses requests that don't come from a recognized trusted proxy, and it logs client IPs as the proxy's IP rather than the real client's. Edit configuration.yaml:

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 192.168.1.10    # IP of the reverse proxy host
    # Add 127.0.0.1 instead if the reverse proxy runs on the same machine as HA

Restart HA after this change. While you're in configuration.yaml, you may also want to set external_url: "https://ha.ddns.dynip.dev" so HA generates correct webhook and OAuth callback URLs.

4. Open port 443 on your router

Forward TCP 443 from your router to the reverse proxy host. Do not forward port 8123 directly to HA — that bypasses the TLS termination and exposes the HA admin UI unencrypted. Port 80 is not needed: certificate issuance and renewal happen entirely through DynIP's DNS-01 challenge.

Verification

From a device off your home network (cellular data is the easiest test):

  • Open https://ha.ddns.dynip.dev in a browser. You should land on the HA login screen with a green padlock — no certificate warnings.
  • Sign in. The dashboard should populate within a second or two; if it sits at "Connecting…" the WebSocket isn't getting through (see common issues below).
  • In the HA companion app, set the External URL to https://ha.ddns.dynip.dev in App Configuration → Connection. The app should switch to the external URL automatically when you leave Wi-Fi.

For programmatic checks:

$ curl -I https://ha.ddns.dynip.dev/api/
HTTP/2 401
content-type: application/json
# 401 is the expected response from the HA API without a token — it confirms the proxy is reaching HA.

Common issues

"Connecting…" forever on the dashboard

The page loads but the live data never appears — that's a WebSocket failure. With Caddy this usually means the upstream reverse_proxy address is wrong or the proxy can't reach HA. With nginx it almost always means the Upgrade / Connection headers aren't being forwarded. Open browser devtools, look at the Network tab, filter to WS — you'll see the failed upgrade.

"400: Bad Request" or "Loading data" stuck on the login page

HA's trusted_proxies doesn't include the IP your proxy actually presents. Check the HA log immediately after a request — it'll log the rejected IP, which is what you should add to the list. If HA and the proxy are on the same Docker network, the proxy's container IP (not the host IP) is what HA sees.

Cert issuance fails with "no valid A/AAAA records found for host"

Either the DynIP updater hasn't run yet (give it a minute and check dig ha.ddns.dynip.dev) or the zone was just created and the secondaries haven't picked up the TSIG key for DNS-01 yet. The dashboard surfaces this as is_tsig_ready; wait for it to flip and retry.

Companion app can't reach HA when away from home

Make sure the External URL in the app is the DynIP hostname, not your LAN IP. The app picks Internal vs External based on which Wi-Fi network it's on — if your phone joined a guest Wi-Fi that happens to share an SSID with home, the app may try the internal URL.

For Home Assistant Container (docker-compose) users

If you're running Home Assistant as a Docker container rather than Home Assistant OS, the cleanest place for the DDNS updater is the same docker-compose file as HA itself. Drop the dynip-updater container in alongside the homeassistant service — it has no shared volumes, no startup order requirement, and runs as a non-root user. See the Docker container section of the docs for the snippet and full env reference.

For Home Assistant OS users, sidecar containers aren't available — the platform's built-in DDNS add-ons (Duck DNS, Cloudflare, etc.) or a small custom_components integration are the right path. The dashboard's snippets-generator emits a shell command that fits cleanly into an HA shell_command: automation if you want to keep everything inside HA.

Related guides

  • Caddy + DynIP — full walkthrough for the reverse proxy used here.
  • Traefik + DynIP — if HA runs as part of a wider Docker Compose stack, Traefik labels are often cleaner than a separate Caddyfile.
  • Tailscale + DynIP — pair this setup with Tailscale so trusted devices use the private mesh and only off-network access goes through the public reverse proxy.
  • Netbird + DynIP — self-hosted mesh VPN alternative for off-network access if you want full control of the control plane.