← All posts

Homelab27 Oct 2026

Home Assistant on the NAS: a local-first smart home

One container, no cloud account, and a firewall that only lets it talk one way. How Home Assistant fits into my network and where it goes next.

Every gadget in my house wants its own app, its own account and its own cloud. The cameras stream through one company’s servers, the litter boxes report to another’s, the lights to a third.

Home Assistant replaces that pile with one hub that runs in my house and talks to the devices directly. This is how I set it up on the same NAS that runs my media server, how it fits into the network I split up in the UniFi post, and where I want to take it.

Why local-first

  • Fewer accounts. One login to protect instead of one per vendor.
  • Traffic stays home. A camera feed that goes from the camera to my NAS never needs to leave the building.
  • It keeps working. When a vendor’s cloud has a bad day, the hub still talks to the device on the LAN.
  • It makes a firewall rule possible. Once a local hub controls the devices, I can cut those devices off from the internet. I come back to that at the end.

Where it lives

Home Assistant is one more service in the same Docker Compose file as the media stack:

homeassistant:
  image: ghcr.io/home-assistant/home-assistant:2026.10.4   # pinned: the database migrates on upgrade
  container_name: homeassistant
  restart: unless-stopped
  mem_limit: 1g
  volumes:
    - ${CONFIG}/homeassistant:/config
  # no published port: Traefik serves it over HTTPS

A few choices in there are deliberate:

  • Pinned version. Home Assistant migrates its database when it upgrades, so I bump the tag on purpose, after a backup, never by accident.
  • Memory cap. One gigabyte on an 8 GB NAS keeps a runaway add-on from starving Jellyfin.
  • Config on the SSD. It sits in the same share as every other app, so it is covered by the daily Btrfs snapshots.
  • No published port. Nothing listens on the NAS for Home Assistant directly. The only way in is the reverse proxy.

The proxy side is two short entries in Traefik’s static routes file:

homeassistant: { rule: "Host(`ha.home.example.com`)", service: homeassistant }
# ...
homeassistant: { loadBalancer: { servers: [{ url: "http://homeassistant:8123" }] } }

My local DNS already has a wildcard record for *.home.example.com, and Traefik already holds a wildcard certificate, so a new hostname needed no DNS change and no new certificate. If you copy this, remember that Home Assistant refuses proxied requests until you list the proxy under trusted_proxies in its configuration.yaml.

How it reaches the devices

Diagram. A phone or laptop on the Main network opens Home Assistant through Traefik. Home Assistant runs as a container on the NAS, also in the Main network. A green arrow labelled rule 1 shows it can reach the IoT network, where the cameras, litter boxes and a light live. A red dashed arrow shows the IoT network cannot start connections back.
Home Assistant sits on the trusted side. Connections only start from Main to IoT, never the other way.

The NAS lives in my Main network and the devices live in IoT, so everything depends on the firewall rule I called Allow Internal to IoT. It lets Main start connections into IoT, with return traffic allowed automatically.

The other direction is the security win. A compromised camera cannot start a connection to Home Assistant or to the NAS. The hub can talk to the camera, and the camera can only answer.

Adding devices

Home Assistant runs on a Docker bridge network, which means it cannot auto-discover devices through mDNS. I add them by IP address instead, and that is fine for a handful of devices.

  • Cameras. Tapo cameras need a separate camera account, which is not the same as the Tapo cloud login. It lives under Camera Settings, Advanced, Camera Account. Home Assistant then connects to the camera by IP.
  • Fixed addresses. Because devices are added by IP, each one should keep its address. Give them DHCP reservations in UniFi. One of my cameras already showed a stale address after the VLAN move, which is exactly the kind of thing that would silently break a Home Assistant integration.

Trade-offs I accepted

  • It runs as root inside its container. The official image has no user ID setting like my other containers. I accept that because nothing exposes it and it is capped at one gigabyte.
  • No auto-discovery. Manual IPs are more typing, but host networking would put the hub’s ports directly on the NAS, which I do not want.
  • It now holds the keys. Camera account credentials live in its config. So it stays reachable only over HTTPS inside the house, and its own login matters.

Where it goes next

Diagram of the planned setup. A phone away from home reaches the house through UniFi Teleport. Home Assistant is the only thing that talks to the cameras, with a green local control arrow into the IoT network. A red dashed arrow shows the IoT network blocked from the internet. A dashed box shows an optional Zigbee or Matter dongle plugged into the NAS.
The target. Dashed items are ideas I have not built.

Next, in order:

  1. Add the cameras by IP with their camera accounts, and confirm Home Assistant sees them.
  2. Cut the cameras off from the internet. Once local control works, a firewall rule from IoT to External blocks them. A camera that cannot phone home cannot be told to do anything from outside.
  3. Keep a firmware window. Cameras still need updates, so I will leave that rule easy to switch off, allow the internet briefly, update, and turn it back on.
  4. Remote access through Teleport. My ISP’s router puts me behind a second NAT, and I do not want to forward a port to a smart-home hub. UniFi Teleport gets me to the same HTTPS address without exposing anything.

Ideas, not built yet:

  • Automations. Alerts when a litter box needs attention or a camera sees motion, and lights on a schedule.
  • Presence. Use our phones to know when the house is empty.
  • A Zigbee or Matter dongle plugged into the NAS. This is the one with a catch. Passing a USB device into the container is easy, but Matter discovery relies on mDNS, which does not cross VLANs. UniFi can reflect mDNS between networks, but I would be loosening a boundary I just built, so I would test it carefully first.

The pattern is the same as the rest of the network. One trusted hub, connections that only start in one direction, and devices that cannot reach the outside world unless I let them.