Collection of cookbooks for Podman Quadlets
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
Nicolas Massé e1d3ae1e1e home-assistant: add cookbook 2 days ago
..
config/examples home-assistant: add cookbook 2 days ago
other home-assistant: add cookbook 2 days ago
tmpfiles.d home-assistant: add cookbook 2 days ago
Makefile home-assistant: add cookbook 2 days ago
README.md home-assistant: add cookbook 2 days ago
home-assistant-init.service home-assistant: add cookbook 2 days ago
home-assistant.container home-assistant: add cookbook 2 days ago
home-assistant.image home-assistant: add cookbook 2 days ago
home-assistant.target home-assistant: add cookbook 2 days ago
overlay.bu home-assistant: add cookbook 2 days ago

README.md

Podman Quadlet: Home Assistant

Overview

Home Assistant is an open-source home automation platform. This cookbook runs it as a Podman Quadlet.

This cookbook:

  • Runs Home Assistant as a non-root container (host UID 10034, GID 10000).
  • Uses PostgreSQL as the recorder (history) backend (requires the postgresql cookbook).
  • Publishes the UI behind Traefik (requires the traefik cookbook).
  • Stores /config (the whole Home Assistant state) as precious data on the virtiofs mount /var/lib/virtiofs/data/home-assistant, so it inherits the hypervisor's ZFS snapshot and backup levels.
  • Bootstraps /config from operator-provided templates on first boot, then never touches it again.
  • Runs a weekly native backup into /config/backups.
  • Uses host networking, which Home Assistant needs for local device discovery (mDNS/SSDP).
  • Supports automatic image updates via Podman auto-update (AutoUpdate=registry).

The upstream image ghcr.io/home-assistant/home-assistant:stable is multi-architecture (amd64 + arm64), so it runs on the aarch64 target VM. Verified on version 2026.9.3.

Prerequisites

  • The postgresql cookbook must be installed and running (recorder backend).
  • The traefik cookbook must be installed and running (reverse proxy).
  • The virtiofs mount var-lib-virtiofs-data.mount must be present (/config lives there).
  • The operator must provide the configuration files listed below.

Files the operator must provide

Everything site-specific is injected downstream into /etc/quadlets/home-assistant/. The cookbook itself ships no site value — only examples (used for development and as templates).

Path Purpose
/etc/quadlets/home-assistant/configuration.yaml Bootstrap Home Assistant configuration (copied to /config).
/etc/quadlets/home-assistant/secrets.yaml Bootstrap secrets, incl. the recorder database URL + password.

Nothing starts until /etc/quadlets/home-assistant/configuration.yaml exists (the home-assistant.target, home-assistant.service and home-assistant-init.service units all guard on it with ConditionPathExists).

Ready-to-use examples are provided under config/examples/. They are installed to /etc/quadlets/home-assistant/ during development and testing only, and are not part of the production package. Adjust the following site-specific values in your own copies:

  • the recorder database password in secrets.yaml;
  • http: trusted_proxies: if Traefik connects from an address other than the loopback;
  • the time zone (homeassistant: time_zone: in configuration.yaml) and the external URL, which are otherwise best set from the Home Assistant web interface;
  • the MQTT broker address (radio head), configured from the web interface once the mosquitto/zigbee2mqtt/zwave-js-ui cookbooks are in place — out of scope here.

Bootstrap configuration vs. live configuration — read this first

Home Assistant owns /config: it writes configuration.yaml, secrets.yaml, .storage/ and everything else from its own web interface. This conflicts with the usual repository convention where /etc/quadlets/ holds the live configuration. It is resolved as follows:

  • /etc/quadlets/home-assistant/configuration.yaml and secrets.yaml are bootstrap templates.
  • home-assistant-init.service (a one-shot unit that runs before the container) copies each of them into /config only if it is absent. It never overwrites a file Home Assistant owns.
  • The same unit creates the empty include targets automations.yaml, scenes.yaml and scripts.yaml (again, only if absent). configuration.yaml references them with !include so the UI can persist automations/scenes/scripts; without them Home Assistant would fail to parse the config on a fresh /config and fall back to recovery mode.
  • After first boot, /config/configuration.yaml is the live copy — editing the file in /etc/quadlets/home-assistant/ afterwards has no effect. To change the live configuration you must edit /config/configuration.yaml (on the virtiofs mount) or use the Home Assistant UI. This is the first thing most readers get wrong.

The shipped bootstrap configuration is enough for an unattended first start on an empty /config, with the recorder already pointed at PostgreSQL.

Reverse proxy

Behind a reverse proxy, Home Assistant rejects requests with 400 Bad Request unless it is told to trust the proxy. The bootstrap configuration.yaml therefore sets:

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 127.0.0.1
    - ::1

trusted_proxies must list the address Traefik connects from. In this deployment Traefik shares the host network and forwards to 127.0.0.1:8123, so the loopback addresses are correct. If your proxy connects from a different address, adjust the list — this is the single most common deployment failure for Home Assistant.

The Traefik router shipped in other/traefik/home-assistant.yaml routes Host(\home-assistant`)tohttp://127.0.0.1:8123`.

Recorder (PostgreSQL)

other/postgresql/home-assistant.sql creates the home_assistant role and database. The recorder connection string is referenced from configuration.yaml via !secret, so the password stays in secrets.yaml and never appears in a packaged file:

recorder:
  db_url: !secret recorder_db_url

The upstream image ships psycopg2 (2.9.12, verified on a running container), which is the driver SQLAlchemy uses for postgresql:// URLs. On first start the recorder creates its schema (13 tables) in the home_assistant database.

Native backup

Home Assistant's own backup format is the only one its interface can restore, and the one that survives a major-version upgrade. The ZFS snapshots protect the bytes; this protects the restore path.

The bootstrap configuration.yaml defines a weekly automation that calls the backup.create service (Sundays at 04:30). Home Assistant writes the archive to /config/backups, i.e. inside the virtiofs perimeter. Because this lives in the bootstrap configuration, it only applies to instances started from the shipped template; on an existing /config you set up the equivalent automation (or a scheduled backup) from the UI under Settings → System → Backups.

TCP ports

Port Protocol Description
8123 TCP Home Assistant web UI / API (HTTP).

Host networking is used, so Home Assistant also sends/receives the multicast traffic it needs for mDNS/SSDP discovery.

UID and GID

Item Value
User 10034 (home-assistant)
Group 10000 (itix-svc)

Deviations from the repository rules

  • Running as root — not needed. The upstream image uses s6-overlay v3 with ENTRYPOINT /init and declares no USER, so it is designed to start as root. It was tempting to run it as root like samba and vsftpd do. That turned out to be unnecessary: s6-overlay v3 detects a non-root UID, fixes up /run itself, and then runs Home Assistant as that user. Verified on 2026.9.3 — with User=10034/Group=10000 the process runs as host UID 10034 and owns everything it writes under /config, and the recorder connects to PostgreSQL normally. This cookbook therefore does not run as root, and needs no user-namespace/idmap workaround either.
  • Configuration is bootstrapped into /config, not kept read-only in /etc/quadlets. Home Assistant owns its configuration directory (see "Bootstrap vs. live configuration" above), so the usual "configuration lives read-only in /etc/quadlets" rule cannot hold. The /etc/quadlets/home-assistant/ files are one-time bootstrap templates, copied into /config only if absent.

Usage

In a separate terminal, follow the logs.

sudo make tail-logs

Install the Podman Quadlets and start Home Assistant (pulls in postgresql and traefik).

sudo make clean install

You should see the home-assistant.service waiting for PostgreSQL to be available, then starting up. The first start takes one to three minutes.

Verify Home Assistant is running (no authentication needed on this endpoint):

curl -sSf http://127.0.0.1:8123/manifest.json

Open http://127.0.0.1:8123/ to reach the onboarding page.

Restart the home-assistant.target unit.

sudo systemctl restart home-assistant.target

Finally, remove the quadlets, their configuration and their data.

sudo make I_KNOW_WHAT_I_AM_DOING=yes uninstall clean