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:

  1. HACS (Home Assistant Community Store) — opt-in third-party integration manager. Install via the official instructions; opens up the long tail of community integrations.
  2. 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.
  3. 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:

  1. Set use_x_forwarded_for: true and trusted_proxies in http: (above) — otherwise HA logs every login as coming from the proxy's IP and blocks them after a few attempts.
  2. Allow WebSocket upgrades. Caddy does this by default; nginx needs the Upgrade/Connection headers.
# 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.

Back up the Zigbee/Z-Wave coordinator state

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.