Home Assistant for Home Automation
Bring your smart home devices under one local dashboard and write real automations across brands, instead of juggling a separate app -- and a separate cloud account -- for each one.
What you'll build and why
Most smart home devices ship with their own app and their own cloud account -- turning off your lights and checking your thermostat are two unrelated apps, and both stop working correctly if that manufacturer's cloud has a bad day. Home Assistant is a free, open-source hub that integrates with essentially every major smart home ecosystem into one local dashboard, running entirely on hardware you control, and lets you automate across brands together instead of per-app.
Don't build this if: you have exactly one smart device from one brand and its own app already does everything you want -- Home Assistant's value is specifically in unifying multiple things, and the setup/learning cost isn't worth it for a single device. You also don't need this today if you have zero smart devices and no near-term plan to add any -- though this guide works fine with none, there's not much to actually automate until you do.
This guide uses the Container installation method (Docker), the right fit if you're already running other services in Docker and want Home Assistant alongside them. It's a deliberate trade-off, covered in Before you start: Container gives up some things Home Assistant OS has, in exchange for fitting your existing Docker-based homelab.
How it works
Smart devices (lights, sensors, thermostats, etc.)
│
▼
Integrations ── each device/service connects through one of these.
│ Some are fully local (Zigbee/Z-Wave via a local
│ radio, most local network devices). Others still
│ depend on the manufacturer's cloud even though
│ Home Assistant itself runs on your network --
│ worth knowing per-integration, not assumed.
▼
Home Assistant core
│
├──► Dashboard (what you see and control)
│
└──► Automation engine (trigger → condition → action,
running across every connected integration together)
The privacy benefit of self-hosting Home Assistant is real but not absolute: Home Assistant itself runs locally and doesn't phone home, but a specific integration you add might still route through that device manufacturer's cloud if that's how the manufacturer built their API. Local-only protocols (Zigbee, Z-Wave, most standard network devices) don't have this issue; some consumer smart-home brands' cloud-only APIs do. Check an integration's own documentation page for whether it's local or cloud-dependent before assuming "self-hosted" means "never leaves my network" for every device.
Before you start
Decision: Container vs. Home Assistant OS. Home Assistant's own documentation states plainly that the Container installation "does not have access to apps" -- meaning no Supervisor and no first-party Add-on store, the curated collection of one-click extra services (things like a Zigbee coordinator manager, or a database add-on) that Home Assistant OS provides. This guide uses Container anyway because it fits directly into an existing Docker-based homelab, and because HACS (the community integration/dashboard store -- see Go further) works fine on Container without needing Supervisor at all; what you actually lose is convenience for the specific extras that ship as official Add-ons, not core functionality. If you specifically want the Supervisor/Add-on ecosystem, Home Assistant OS (a dedicated VM or physical install) is the right choice instead -- a different guide from this one.
Steps
Step 1: Run Home Assistant with Docker Compose
$ mkdir -p ~/homeassistant/config && cd ~/homeassistant
services:
homeassistant:
container_name: homeassistant
image: "ghcr.io/home-assistant/home-assistant:stable"
volumes:
- "./config:/config"
- "/etc/localtime:/etc/localtime:ro"
- "/run/dbus:/run/dbus:ro"
restart: unless-stopped
stop_grace_period: 60s
privileged: true
network_mode: host
environment:
TZ: "America/New_York"
This matches Home Assistant's own current official example. A few things worth understanding, not just copying: network_mode: host matters specifically because automatic device discovery (mDNS, SSDP) doesn't work correctly through Docker's default bridge networking. The /run/dbus mount and privileged: true support Bluetooth-based integrations and certain hardware access -- if you're certain you'll never use Bluetooth devices, you can omit both, but this guide keeps them since they match the documented default and cost nothing if unused.
$ docker compose up -d
Expected output: Home Assistant takes a minute or two to finish first-run initialization after the container starts -- don't be concerned if the web UI isn't immediately responsive.
Step 2: Complete onboarding
Visit http://<host-ip>:8123. Create your account, set your home's location (used for sunrise/sunset-based automations and weather), and let the initial device discovery scan run -- it will likely find some devices on your network automatically.
Step 3: Add integrations for your devices
Settings → Devices & Services → Add Integration, search for your device's brand or protocol (Philips Hue, TP-Link Kasa, Google Cast, MQTT, Zigbee2MQTT if you have a Zigbee USB coordinator, etc.). Most walk you through pairing directly. Check each integration's own documentation page for whether it's local or cloud-dependent (see How it works) -- this varies by integration, not by Home Assistant as a whole.
Step 4: Build a dashboard
Home Assistant auto-generates a basic dashboard from your devices. Settings → Dashboards → Edit Dashboard to organize it: group by room, surface your most-used controls, remove what you don't need to see daily.
Step 5: Write your first automation
Settings → Automations & Scenes → Create Automation → Create new automation. Every automation is a trigger, optional conditions, and one or more actions. A simple, genuinely useful first one:
- Trigger: a specific time, e.g. sunset
- Action: turn on a light entity
Save it, then use Run actions on the automation's own page to fire it manually and confirm it does what you expect without waiting for the actual trigger time.
Verify it works
-
http://<host-ip>:8123loads the dashboard after onboarding - At least one real device shows under Settings → Devices & Services, and its state updates when you change it physically or through its own app
- The Step 5 automation appears under Automations as enabled, and Run actions produces the expected result
- Failure test: restart the container (
docker compose restart). Confirm Home Assistant comes back up with your devices, dashboard, and automations all intact -- confirms/configis actually where state lives, not somewhere ephemeral
Secure it
- What's exposed: the web UI on port 8123. Home Assistant's own documentation explicitly recommends against exposing it directly to the internet -- use Home Assistant Cloud (a paid, official remote-access product), a DuckDNS + Let's Encrypt setup behind a reverse proxy, or a VPN/SSH tunnel instead of port-forwarding 8123 directly.
- Default credentials: none -- the account you create during onboarding (Step 2) is the only one, with the password you set then.
- Multi-factor authentication: Home Assistant's own docs recommend enabling MFA for your account -- Your profile (click your name) → Multi-factor authentication, worth doing even for a LAN-only instance, since it's cheap insurance if your network is ever compromised some other way.
- The failure that hurts most: a compromised or leaked account controlling physical devices in your home, not just data. Home Assistant integrates with door locks, garage doors, and similar for some users -- treat the account protecting that the same way you'd treat any account with real physical-world consequences, not like a typical low-stakes login.
- Update strategy: Home Assistant ships monthly releases with their own release notes and occasional security advisories -- check home-assistant.io/blog before updating, since breaking changes are called out there, not silent.
Back it up and maintain it
What matters: the /config directory (mapped to ./config) -- every integration, automation, dashboard, and the account database all live there. Back it up regularly; Home Assistant also has a built-in Settings → System → Backups feature that snapshots this for you, worth enabling on a schedule rather than relying only on an external backup of the raw directory.
Update cadence: monthly releases are normal for Home Assistant -- read the release notes (breaking changes are explicitly called out) before updating, then docker compose pull && docker compose up -d.
What to monitor: integrations occasionally break when a manufacturer changes their API -- Settings → Devices & Services surfaces integrations with errors; check it after any update.
Troubleshooting
Logs: Settings → System → Logs in the web UI, or docker logs homeassistant.
| Symptom | Likely cause | Diagnostic | Fix |
|---|---|---|---|
| A device never shows up in discovery | Not actually on network_mode: host (Step 1) -- bridge networking is the most common reason discovery silently finds nothing |
Confirm the compose file's network_mode setting |
Switch to network_mode: host, or add the integration manually by IP/host instead of waiting on discovery |
| An automation doesn't fire when it should | A condition is silently failing, or the trigger itself never matched what you expected | Settings → Automations & Scenes, open the automation, check its Traces (execution history) | Traces show exactly which step it reached and why it stopped -- usually more useful than guessing |
| The container restarts in a loop after a manual config-file edit | Invalid YAML introduced by hand | Developer Tools → YAML → Check Configuration before restarting, not after | Fix the reported syntax error; always validate before letting a manual edit take effect |
| An integration shows as failed/unavailable after an update | The manufacturer changed their API, or the update itself introduced a breaking change (see release notes) | Settings → Devices & Services, check the specific integration's error detail | Check the integration's own GitHub issues or Home Assistant's release notes for a known fix; sometimes a temporary manufacturer-side outage that resolves itself |
| Bluetooth-based integrations don't work even though you kept the dbus mount | The host itself doesn't have a Bluetooth adapter, or the container can't actually reach it despite the mount | docker exec homeassistant bluetoothctl list (if available in the image) or check host-side hciconfig/bluetoothctl |
Confirm the host has working Bluetooth first, independent of Home Assistant, before debugging the container side |
| Restarting the container loses devices/automations | /config isn't actually persisted -- a volume mapping mistake |
Check the compose file's volume line for /config points at a real host path, not an anonymous volume |
Fix the mapping; already-lost config isn't recoverable without a backup |
Undo
docker compose down in the Home Assistant directory stops and removes the container. Delete ./config to remove all state. If you set up a DuckDNS/reverse-proxy path for remote access, remove that separately (it's outside Home Assistant itself).
Go further
- Look into Zigbee2MQTT or Z-Wave JS if you want local, non-cloud-dependent device protocols instead of manufacturer cloud accounts for as many devices as possible
- HACS (Home Assistant Community Store) for community-built integrations and dashboard cards beyond what ships by default -- works on Container installs without needing Supervisor
- Enable Settings → System → Backups on a schedule rather than relying only on manual exports
Resources
Official documentation:
- Home Assistant Container installation -- the compose setup this guide is based on
- Securing Home Assistant -- remote access and MFA recommendations
- Home Assistant documentation home
Source and releases:
- home-assistant/core releases
- Home Assistant blog -- monthly release notes, breaking changes called out here
Community:
Go deeper:
- HACS -- the community store mentioned in Go further; its own docs cover Container-install compatibility in more depth than this guide does
Last verified: 2026-09-21, checked against official Home Assistant documentation (see Resources above).
Changelog:
- 2026-09-21 -- Full rewrite: corrected the Docker Compose example to match Home Assistant's current official one, which includes
stop_grace_period,privileged: true, and a/run/dbusmount -- none of which were in the original at all (they support Bluetooth-based integrations and aren't optional extras the original simply chose not to mention, they're part of the documented default config). Added the integration/automation-engine diagram, explicit disclosure of what the Container install method gives up vs. Home Assistant OS (the original mentioned it in passing without explaining the actual trade-off), a real discussion of local-vs-cloud-dependent integrations (earning theprivacytag properly instead of asserting it), Secure it (Home Assistant's own explicit anti-internet-exposure and MFA recommendations), Back it up and maintain it, Undo, and a full Resources section. Expanded Troubleshooting from 3 to 6. Moved fromhomelabtoself-hosted-services. - 2026-09-21 (earlier) -- Original version published with an incomplete Docker Compose example.