The four install shapes
- Home Assistant OS — a small purpose-built Linux distro that runs only Home Assistant. Bare-metal, VM (Proxmox / virt-manager), or Raspberry Pi. Most full-featured: the add-on store, the Supervisor service, and one-click backups all require this.
- Home Assistant Supervised — the same Supervisor running on top of Debian. The official requirements list is strict (Debian 12, specific kernel features). Mostly historical now — HAOS in a VM is easier.
- Home Assistant Container — Core in Docker. No add-on store, no Supervisor; integrations and HACS still work. Best when the host is doing other things too.
- Home Assistant Core — the Python app in a venv. Manual upgrades. Niche — only useful when neither the Container nor the OS path fits.
Home Assistant OS in a VM
Download the qcow2 image from home-assistant.io/installation. Create a VM with virt-manager, qemu-system, or Proxmox:
- 2 vCPUs, 4 GB RAM (start)
- UEFI firmware (Q35 + OVMF in libvirt)
- 32 GB+ virtual disk
- Bridged networking so devices on the LAN can reach it directly
- Pass through any USB radios (Zigbee/Z-Wave sticks) to the VM
Boot, wait two to three minutes for the Supervisor to come up, then browse to http://homeassistant.local:8123. On first run, walk through the onboarding wizard, create a user account, set a location.
Home Assistant Container on an existing server
Quadlet (see Podman/Quadlet) or docker compose:
# ~/.config/containers/systemd/home-assistant.container
[Unit]
Description=Home Assistant
[Container]
Image=ghcr.io/home-assistant/home-assistant:stable
ContainerName=home-assistant
PublishPort=8123:8123
Volume=%h/home-assistant/config:/config:Z
Volume=/etc/localtime:/etc/localtime:ro
Volume=/run/dbus:/run/dbus:ro
Network=host
AddDevice=/dev/ttyUSB0 # Zigbee USB stick, adjust per device
[Service]
Restart=always
[Install]
WantedBy=default.target
Network=host matters for HomeKit, mDNS discovery, and Wake-on-LAN to work — container-network bridges break those.
The first three integrations to add
Settings → Devices & Services → Add Integration:
- HACS (Home Assistant Community Store) — opt-in third-party integration manager. Install via the official instructions; opens up the long tail of community integrations.
- Z2M / ZHA — if a Zigbee stick is connected, pick one of these to talk to it. Zigbee2MQTT (z2m) is more feature-complete and uses MQTT (see that tutorial); ZHA is the built-in option and needs no broker.
- ESPHome — for any ESP32/ESP8266 device flashed with the ESPHome firmware. The Home Assistant add-on lets you edit YAML for each device, compile, and OTA-flash all in one UI.
YAML configuration
Most configuration is now done via the UI, but the file-based config still works and is the path of least resistance for some integrations:
# /config/configuration.yaml
default_config:
http:
use_x_forwarded_for: true
trusted_proxies:
- 127.0.0.1
- 192.168.1.0/24
automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml
# Custom sensor pulling from MQTT
mqtt:
sensor:
- name: "Living Room Temperature"
state_topic: "home/living_room/temperature"
unit_of_measurement: "°C"
Validate before reloading: Developer Tools → YAML → Check Configuration. Then either reload the affected integration or restart Home Assistant from the UI.
Automations
An automation is "trigger → condition → action." The UI builds them; advanced users edit the YAML directly. Example: turn the porch light on at sunset, off at midnight:
- alias: Porch light on at sunset
trigger:
- platform: sun
event: sunset
offset: "-00:15:00"
action:
- service: light.turn_on
target: { entity_id: light.porch }
- alias: Porch light off at midnight
trigger:
- platform: time
at: "00:00:00"
action:
- service: light.turn_off
target: { entity_id: light.porch }
Reverse proxy
To get HTTPS on a real domain, put Home Assistant behind Caddy/nginx/Traefik. Two HA-specific things:
- Set
use_x_forwarded_for: trueandtrusted_proxiesinhttp:(above) — otherwise HA logs every login as coming from the proxy's IP and blocks them after a few attempts. - Allow WebSocket upgrades. Caddy does this by default; nginx needs the
Upgrade/Connectionheaders.
# Caddy
home.example.com {
reverse_proxy 127.0.0.1:8123
}
Backups
HAOS / Supervised installs have one-click full backups in Settings → System → Backups. The output is a tarball that includes:
- The Home Assistant config
- Add-ons and their data
- The Supervisor state
For Container installs, back up /config (the mount that holds configuration.yaml, the SQLite recorder database, the Zigbee coordinator's network keys). A restic job (see that tutorial) is enough.
The Zigbee coordinator stores the network key, channel, and pan-id on the USB stick itself. If the stick fails, the only way to keep your existing devices paired is to flash the same network state onto a replacement. ZHA exposes a backup command in the integration; z2m writes coordinator_backup.json automatically — include both in your backup set.
Voice and ML add-ons
Home Assistant Year of the Voice / Year of the LLM (2023–25) added local voice processing: Whisper for STT, Piper for TTS, and the Assist conversation agent that can be backed by Ollama or a cloud LLM. The add-ons live under Settings → Add-ons; once installed, Assist becomes a wake-word-capable voice interface that runs entirely on your hardware. For LLM-backed automations, an Ollama integration points at an Ollama server (see that tutorial) and exposes any pulled model as a conversation agent.
When to stay with the cloud version
"Local-first" doesn't mean "no internet allowed." For mobile push notifications, secure remote access, and a public IPv6/IPv4 endpoint without a fixed home IP, Nabu Casa (Home Assistant Cloud) is a $7.50/month optional add-on that gives you all three; it also funds the project. If those features aren't needed, plain Home Assistant with a self-hosted reverse proxy and Tailscale (see that tutorial) for remote access covers it.