Skip to content

Home Assistant

Home Assistant runs as a Podman OCI container (virtualisation.oci-containers) using the official image (ghcr.io/home-assistant/home-assistant:stable). It runs with host networking (--network=host) for direct LAN and local loopback connectivity with other homelab services (such as Mosquitto, Matter Server, Whisper, and Piper).

The state directory /var/lib/hass is mounted to /config inside the container. This preserves all runtime state, entity registries, Lovelace dashboards, automations, and long-lived tokens, while eliminating the operational maintenance of declaring Python packages or component derivations in NixOS.

In this homelab, Home Assistant is enhanced with HACS (Home Assistant Community Store) for custom integrations and LLMs (OpenAI, Gemini, Anthropic, Ollama) for advanced voice conversation capabilities. Entities are exposed to voice platforms through the dedicated Matter Hub bridge rather than an in-instance integration.

PortProtocolPurpose
8123TCPWeb UI and API (Local)
Access MethodURL
Local networkhttp://<homelab.ip>:8123
Cloudflare Tunnelhttps://home-assistant-home.javiersc.com

The Home Assistant iOS/Android app does not natively support the Cloudflare Access login screen. For seamless mobile app access, use Tailscale: connect your phone to the Tailscale network and configure the Home Assistant app to use the Tailscale IP as both internal and external URL (e.g., http://100.82.100.68:8123).

Home Assistant uses 1Password for sensitive API keys (OpenAI, Anthropic, etc.). These are injected or managed through the UI and secret store. Long-lived access tokens used by internal homelab services (matter-hub, litellm, picoclaw) are stored persistently in .storage/auth.

Secret1Password ItemField
OpenAI API Keyop://Homelab/OpenAI/credentialAPI key for GPT-4 conversation
Anthropic API Keyop://Homelab/Anthropic/credentialAPI key for Claude conversation

Data is backed up daily to Backblaze B2 via Restic. Because the host state directory remains /var/lib/hass, the Restic snapshot group ([Host + Paths]) remains consistent with the homelab backup schedule.

  • Restic Path: /var/lib/hass (excluding /backups, tts, and logs)
  • Internal Snapshots: Managed via Home Assistant UI (Daily, Retention: 1-7 days). These are kept locally for fast “undo” operations but are not stored in the cloud.

Retention policy: 7 daily, 4 weekly, 6 monthly snapshots.

Home Assistant runs as an OCI container with all core integrations pre-bundled:

  • Container Runtime: Managed by systemd via podman-home-assistant.service.
  • Config Persistence: Bound to /var/lib/hass:/config.
  • No NixOS Component Declarations: Because the official image pre-bundles all dependencies, official integrations (such as mqtt, tuya, google_generative_ai_conversation, openai_conversation, esphome) are installed and configured directly via the UI without requiring extraComponents or rebuilds in NixOS.

To allow UI-driven automations, scripts, and scenes, the persistent configuration.yaml includes:

default_config: {}
automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml
http:
server_host:
- 0.0.0.0
- '::'
server_port: 8123
trusted_proxies:
- 127.0.0.1
- ::1
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
use_x_forwarded_for: true

The system automatically creates these files with root permissions via systemd.tmpfiles.rules if they don’t exist.

Custom components reside in /var/lib/hass/custom_components/.

  • HACS: Installed in /var/lib/hass/custom_components/hacs. Updates to HACS and custom components are performed directly through the HACS interface without requiring Nix rebuilds.
  • Custom Integrations: Integrations like midea_ac_lan and xiaomi_miot are placed directly in custom_components/.

Multiple LLM components are supported out of the box in the container, including:

  • OpenAI Conversation
  • Google Generative AI (Gemini)
  • Anthropic
  • Ollama (Local LLM at http://127.0.0.1:11434)
  • OpenRouter

The Home Assistant UI is configured for Spanish (es) localization. This affects date/time formats, number formatting, and the default language for the frontend.

When configuring the MQTT integration in the UI:

  • Broker: Use 127.0.0.1 (port 1883).
  • Username/Password: Use the credentials managed in 1Password (Homelab/Mosquitto).
  • Nanoleaf: Discovery finds Nanoleaf devices automatically on the local network via host networking and mDNS.
  • ESPHome: Native support for managing and controlling ESPHome-flashed devices.
    • Ball_v2 (ESP32-S3 + GC9A01A round display): Custom voice assistant device with I2S microphone/speaker, RGB LED (WS2812) for state feedback, and touch button. Microphone gain set to 12dB. LED colors indicate assistant state: green during listening, blue during thinking, and amber during replying. Config lives in assets/esphome/Ball_v2.yaml.

HA entities — including Zigbee devices bridged through Zigbee2MQTT — are exposed to Alexa, Apple Home, and Google Home by the Matter Hub. The Matter Hub connects to Home Assistant over local loopback (http://127.0.0.1:8123/).

To view runtime logs for Home Assistant:

Terminal window
journalctl -u podman-home-assistant -f

Or directly from Podman:

Terminal window
podman logs -f home-assistant

To restart the Home Assistant container:

Terminal window
sudo systemctl restart podman-home-assistant

Symptom: Accessing Home Assistant through Nginx or Cloudflare returns 400: Bad Request.

Cause: Reverse proxy IP is not listed under trusted_proxies in configuration.yaml.

Solution: Verify /var/lib/hass/configuration.yaml includes use_x_forwarded_for: true and trusted_proxies includes 127.0.0.1, ::1, and LAN subnets (192.168.0.0/16). Restart the container.