Running Home Assistant in Docker: Installation, Compose, and Updates
This post may contain affiliate links. As an Amazon Associate we earn from qualifying purchases. Disclosure.
Want Home Assistant inside Docker? The short answer: run the official ghcr.io/home-assistant/home-assistant:stable container, bind a config volume, set network_mode: host, and you're live in about five minutes. That's the install most experienced users pick when they already have a server doing other jobs.
I've run Home Assistant as a Docker container on a 2019 Intel NUC for over three years now. Same box hosts Plex, Pi-hole, and a couple of databases. Spinning up a whole Home Assistant Operating System just for automations felt wasteful. Docker let me share the hardware. The tradeoff? You lose the one-click Add-on store. Worth it for me. Maybe not for you.
TL;DR: Home Assistant Container is the lightest install method, perfect if you already run a Docker host. You get the full Core app and fast updates, but no Supervisor and no Add-ons. Use docker-compose, mount a config volume, and run
docker compose pull && docker compose up -dto update. Pick HA OS instead if you want Add-ons without managing containers yourself.
Why run Home Assistant in Docker?
Docker is the second most popular install method for Home Assistant, behind the dedicated HA OS image, according to the project's own Home Assistant Analytics dashboard. Containers isolate the app, keep your host OS clean, and let one machine run many services at once. That last point sells it for most homelab folks.
The appeal is simple. You don't dedicate a whole Raspberry Pi or mini PC to a single app. My NUC idles at 9 watts and runs five containers. Compare that to three separate Pis humming away in a closet. Less heat, less cable mess, one thing to back up.
There's a catch, though. The Container method ships only Home Assistant Core, the Python application itself. No Supervisor process manages it. That means no Add-on store, which is where things like Mosquitto, ESPHome, and the file editor normally live. You can still run those as separate containers. It's just manual work.
How do you install Home Assistant with docker-compose?
A working install needs three things: the official image, a mounted config directory, and host networking so device discovery works. The Home Assistant docs recommend network_mode: host because mDNS and Bluetooth discovery break behind Docker's default bridge network. Here's the compose file I actually use.
The docker-compose.yml file
Create a folder, drop in this docker-compose.yml, and adjust the volume path:
services:
homeassistant:
container_name: homeassistant
image: ghcr.io/home-assistant/home-assistant:stable
volumes:
- /home/maciek/ha-config:/config
- /etc/localtime:/etc/localtime:ro
- /run/dbus:/run/dbus:ro
restart: unless-stopped
privileged: true
network_mode: host
The /config mount is the important bit. Everything Home Assistant cares about, your configuration.yaml, the SQLite database, automations, lives there. Lose the container, keep the folder, lose nothing. Then run docker compose up -d and open https://homeassistant.local:8123/ in a browser, or use your server's LAN IP at port 8123.
First boot takes a minute or two while it builds the onboarding wizard. Why so slow the first time? It's writing the default config and initializing the recorder database. Patience.
Extra service options worth setting
The bare minimum compose file works, but I tweak a few extra keys on every install. They've saved me grief over three years of running this thing.
environment:
- TZ=Europe/Warsaw
healthcheck:
test: ["CMD", "curl", "-f", "127.0.0.1:8123/"]
interval: 30s
timeout: 10s
retries: 3
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
Set TZ explicitly. If you skip it, scheduled automations fire at the wrong hour, and that's a maddening bug to chase. The healthcheck block lets Docker restart the container if Core hangs, which mine did once after a bad recorder migration. And the logging cap? Without it, Home Assistant's chatty logs filled 40GB on my SSD before I caught it. Cap them at three 10MB files. Your disk will thank you.
One more thing. Don't run two volumes pointing at the same /config from two containers. I tried that during a migration and corrupted the SQLite database. One container per config folder. Always.
Mapping USB devices like Zigbee sticks
Got a SkyConnect or a ConBee II? You'll need to pass the USB device through. Add this under the service:
devices:
- /dev/ttyACM0:/dev/ttyACM0
Check the actual path first with ls -l /dev/serial/by-id/. I learned this the hard way when a reboot renamed my stick from ttyACM0 to ttyACM1 and every Zigbee device dropped offline. Use the by-id path instead. It survives reboots.
So the safer mapping looks like this:
devices:
- /dev/serial/by-id/usb-Nabu_Casa_SkyConnect_v1.0-if00-port0:/dev/ttyACM0
That long string ties the mapping to the physical stick, not the slot order. Run the ls command above to find yours. The names differ per vendor. A ConBee II shows up as usb-dresden_elektronik..., while a SkyConnect reads Nabu_Casa.
What about Bluetooth? If you want native Bluetooth proxying, you already mounted /run/dbus in the base compose file, and network_mode: host handles the rest. In my testing on Ubuntu 22.04, BlueZ 5.64 worked fine for tracking a few BLE temperature sensors. It got flaky past about eight devices, though. For anything serious, I'd run a dedicated ESPHome Bluetooth proxy on an ESP32 instead. Cheaper and more reliable than wrestling the host's Bluetooth stack inside a container.
How do you update Home Assistant in Docker?
Updating a Home Assistant container is two commands and takes under 30 seconds of downtime. The official image follows the monthly release cadence, with point releases roughly weekly, so you'll update often. There's no in-app update button like HA OS has. You do it from the shell.
Run these from your compose folder:
docker compose pull
docker compose up -d
The first command grabs the newest stable tag. The second recreates the container with it. Your config volume stays untouched. Done.
One word of warning from experience: back up your /config folder before any major version jump. Home Assistant ships breaking changes, usually around integrations being removed or YAML syntax shifting. I keep a nightly tar of the config dir on a separate drive. Saved me twice. Don't pin to :latest either, that tag can pull beta builds. Stick with :stable.
external Home Assistant release notes
Docker vs HA OS vs Supervised: which should you pick?
The official Home Assistant installation page lists four methods, and only two get full support: HA OS and Container. Supervised is documented but the team calls it an advanced, fragile setup. Here's how the three stack up for a typical home.
| Method | Add-ons | Auto-updates | Best for |
|---|---|---|---|
| HA OS | Yes | Yes (in-app) | Most people, dedicated device |
| Container (Docker) | No | Manual (compose) | Existing Docker hosts |
| Supervised | Yes | Partial | Experts who want Add-ons on Debian |
HA OS is the recommended path for a reason. It's an appliance. Flash it to an SD card or SSD, and updates, backups, and Add-ons all live in the UI. Your grandmother could keep it running. The cost is that it wants the whole machine.
The Container route, the one this guide covers, trades convenience for flexibility. You manage updates yourself. You run Mosquitto or ESPHome as separate containers instead of clicking install. In return you get a tiny footprint and full control over the host.
Supervised? Honestly, I'd avoid it unless you have a specific reason. It tries to give you Add-ons on a plain Debian box, but the team only supports it under strict conditions, and it breaks if you stray. Most people chasing Supervised actually want either HA OS or plain Container. Pick one of those.
How do you back up and restore a Docker install?
The whole backup story for Container mode lives in one folder: /config. There's no Supervisor snapshot button, so you script it. Stop the container, copy the directory, restart. That's a consistent, restorable backup every time, because the SQLite database isn't being written mid-copy.
Here's the script I run nightly from cron at 3am:
docker compose stop homeassistant
tar czf /mnt/nas/ha-$(date +%F).tar.gz /home/maciek/ha-config
docker compose start homeassistant
find /mnt/nas -name "ha-*.tar.gz" -mtime +14 -delete
The last line prunes backups older than 14 days. Why stop the container first? Copying a live SQLite file can grab it mid-write, and you end up with a backup that won't open. Three seconds of downtime at 3am beats a corrupt restore when you actually need it.
Restoring is the reverse. Stop the container, extract the tarball over a fresh /config, start it back up. Your devices, automations, and history all come back exactly as they were. I migrated my entire setup from the old NUC to a new Beelink mini PC this way in about ten minutes. No re-pairing Zigbee devices, no rebuilding dashboards. That portability is the quiet superpower of the Container method.
What are the common Docker errors and their fixes?
Most install problems trace back to three causes: networking, permissions, or USB paths. Knowing which one you're hitting saves an evening of forum scrolling. Here are the failures I've actually run into and how I fixed each.
Container starts then immediately exits
Check docker compose logs homeassistant first. Nine times out of ten it's a YAML syntax error in configuration.yaml, a stray tab or bad indentation. Home Assistant refuses to boot with broken config. Fix the YAML, then docker compose restart. If the logs mention a database error instead, your home-assistant_v2.db might be corrupt. Rename it and let Core rebuild a fresh one.
Permission denied on the config volume
This bites people running rootless Docker. The container needs read and write access to your config folder. Run sudo chown -R 1000:1000 /home/maciek/ha-config to match the default user, or check which UID your daemon uses. I hit this exact error switching from Docker Desktop to a headless server. Took me an hour to spot it.
Integrations can't find devices
Almost always the network mode. If you forgot network_mode: host, mDNS discovery dies and half your integrations show nothing. Add it back, recreate the container. Cast devices, Sonos, HomeKit bridges, they all depend on broadcast traffic the bridge network silently drops.
Does Docker affect performance or security?
Performance is a wash, since the same Python Core runs underneath either way, but security needs your attention because the recommended config runs privileged: true. That flag hands the container broad host access. Fine on a trusted home server. Not fine if that box is exposed to the internet.
A few hardening steps I'd actually bother with. Put Home Assistant behind a reverse proxy like Nginx Proxy Manager or Caddy, and terminate TLS there so you get a real certificate instead of the self-signed warning. Never forward port 8123 straight to the open internet, use a VPN like WireGuard or a Cloudflare Tunnel for remote access. And drop privileged: true if you don't need USB or Bluetooth, swapping it for targeted cap_add entries instead. Is that overkill for a LAN-only setup? Probably. But the moment you want remote access, do it properly.
On the resource side, a fresh Container install sits around 350MB of RAM and barely touches the CPU on my four-year-old hardware. The recorder database grows fastest. Mine hit 2GB before I trimmed history retention to 10 days in configuration.yaml. If your install feels sluggish after a few months, that database is usually the reason. Set purge_keep_days and move on.
Frequently asked questions
Can I use Home Assistant Add-ons in Docker?
No, not directly. Add-ons need the Supervisor, which only ships with HA OS and Supervised installs. The Container method runs Core alone. You can replicate any Add-on by running its equivalent Docker image yourself, like eclipse-mosquitto for MQTT or esphome/esphome for ESPHome. It's more setup but works fine.
Why does my Home Assistant container miss devices on the network?
Device discovery relies on mDNS and broadcast traffic, which Docker's default bridge network blocks. Set network_mode: host in your compose file so the container shares the host's network stack. After I switched to host mode, my Sonos speakers and Chromecasts showed up within seconds. Bridge mode hides them.
How do I back up Home Assistant running in Docker?
Back up the mounted /config directory, since it holds your entire setup including the database and secrets. A simple cron job running tar czf ha-backup.tar.gz /home/maciek/ha-config works. There's no built-in Supervisor backup in Container mode, so this is on you. Store copies off the host, ideally on a NAS or cloud bucket.
Is Docker or HA OS faster for Home Assistant?
Performance is nearly identical since both run the same Python Core. Docker can feel marginally leaner because it skips the Supervisor overhead. On my NUC, startup time and automation latency between the two methods differed by under a second. Pick based on whether you want Add-ons, not raw speed.
So which install fits you? If you already run a server stuffed with containers, Docker is the obvious move, and you now have a compose file that works. If a single appliance that updates itself sounds better, flash HA OS and skip the shell entirely. Both run the same software underneath. The only real question is how much you enjoy managing it yourself. For me, the answer was always Docker. Your closet, your call.