13 changed files with 457 additions and 0 deletions
@ -0,0 +1,12 @@ |
|||||
|
##
|
||||
|
## Makefile for Home Assistant quadlet
|
||||
|
##
|
||||
|
|
||||
|
DEPENDENCIES = postgresql traefik |
||||
|
|
||||
|
# Home Assistant quadlet is mapped to the 10034 user (home-assistant) and 10000 group (itix-svc)
|
||||
|
PROJECT_UID = 10034 |
||||
|
PROJECT_GID = 10000 |
||||
|
|
||||
|
# Include common Makefile
|
||||
|
include ../../scripts/common.mk |
||||
@ -0,0 +1,201 @@ |
|||||
|
# Podman Quadlet: Home Assistant |
||||
|
|
||||
|
## Overview |
||||
|
|
||||
|
[Home Assistant](https://www.home-assistant.io/) 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. | |
||||
|
|
||||
|
`home-assistant-init.service` only bootstraps `/config` when |
||||
|
`/etc/quadlets/home-assistant/configuration.yaml` is present; `home-assistant.service` only |
||||
|
starts once `/config/configuration.yaml` exists (created by the init unit on first boot, or |
||||
|
already present if Home Assistant was configured before). So on a fresh system nothing runs |
||||
|
until the operator provides the bootstrap files, and once Home Assistant owns `/config` the |
||||
|
files under `/etc/quadlets/home-assistant/` are no longer required. |
||||
|
|
||||
|
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: |
||||
|
|
||||
|
```yaml |
||||
|
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\`)` to `http://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: |
||||
|
|
||||
|
```yaml |
||||
|
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. |
||||
|
|
||||
|
```sh |
||||
|
sudo make tail-logs |
||||
|
``` |
||||
|
|
||||
|
Install the Podman Quadlets and start Home Assistant (pulls in `postgresql` and `traefik`). |
||||
|
|
||||
|
```sh |
||||
|
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): |
||||
|
|
||||
|
```sh |
||||
|
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. |
||||
|
|
||||
|
```sh |
||||
|
sudo systemctl restart home-assistant.target |
||||
|
``` |
||||
|
|
||||
|
Finally, remove the quadlets, their configuration and their data. |
||||
|
|
||||
|
```sh |
||||
|
sudo make I_KNOW_WHAT_I_AM_DOING=yes uninstall clean |
||||
|
``` |
||||
@ -0,0 +1,56 @@ |
|||||
|
## |
||||
|
## Home Assistant BOOTSTRAP configuration |
||||
|
## |
||||
|
## This file is a TEMPLATE. It is copied to /config/configuration.yaml on first |
||||
|
## boot ONLY if that file does not already exist (see home-assistant-init.service). |
||||
|
## After first boot, /config/configuration.yaml is the LIVE copy that Home |
||||
|
## Assistant owns and edits from its web interface; this template becomes inert. |
||||
|
## |
||||
|
## Site-specific values (external URL, trusted proxy addresses, time zone, ...) |
||||
|
## are meant to be injected downstream by the operator overlay, not hard-coded |
||||
|
## here. The values below are only enough for an unattended first start. |
||||
|
## |
||||
|
|
||||
|
# Loads the default set of integrations (frontend, config UI, backup, ...). |
||||
|
# Do not remove. |
||||
|
default_config: |
||||
|
|
||||
|
# Front-end themes (kept so themes dropped in /config/themes are picked up). |
||||
|
frontend: |
||||
|
themes: !include_dir_merge_named themes |
||||
|
|
||||
|
# Home Assistant runs behind the Traefik reverse proxy. Without the two settings |
||||
|
# below it answers "400 Bad Request" to every proxied request. `trusted_proxies` |
||||
|
# must list the address Traefik connects FROM; here Traefik shares the host |
||||
|
# network and forwards to 127.0.0.1, so the loopback addresses are correct. |
||||
|
# Adjust if your proxy connects from another address. |
||||
|
http: |
||||
|
use_x_forwarded_for: true |
||||
|
trusted_proxies: |
||||
|
- 127.0.0.1 |
||||
|
- ::1 |
||||
|
|
||||
|
# Long-term history is stored in PostgreSQL (the `postgresql` cookbook). The |
||||
|
# connection string (with its password) is kept out of this file via !secret. |
||||
|
recorder: |
||||
|
db_url: !secret recorder_db_url |
||||
|
|
||||
|
# UI-managed automations, scripts and scenes (edited from the web interface). |
||||
|
automation ui: !include automations.yaml |
||||
|
script: !include scripts.yaml |
||||
|
scene: !include scenes.yaml |
||||
|
|
||||
|
# Weekly 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. It is |
||||
|
# written to /config/backups, i.e. inside the virtiofs perimeter. |
||||
|
automation backup: |
||||
|
- alias: "Weekly native backup" |
||||
|
trigger: |
||||
|
- platform: time |
||||
|
at: "04:30:00" |
||||
|
condition: |
||||
|
- condition: time |
||||
|
weekday: |
||||
|
- sun |
||||
|
action: |
||||
|
- service: backup.create |
||||
@ -0,0 +1,15 @@ |
|||||
|
## |
||||
|
## Home Assistant BOOTSTRAP secrets |
||||
|
## |
||||
|
## This file is a TEMPLATE. It is copied to /config/secrets.yaml on first boot |
||||
|
## ONLY if that file does not already exist (see home-assistant-init.service). |
||||
|
## Values referenced from configuration.yaml with the !secret tag are looked up |
||||
|
## here. |
||||
|
## |
||||
|
## The value below matches the development password created by the `postgresql` |
||||
|
## hook (other/postgresql/home-assistant.sql). In production, the operator |
||||
|
## overlay provides this file with the real database password, so no site secret |
||||
|
## ships in the cookbook package. |
||||
|
## |
||||
|
|
||||
|
recorder_db_url: postgresql://home_assistant:home_assistant@127.0.0.1:5432/home_assistant |
||||
@ -0,0 +1,41 @@ |
|||||
|
#!/bin/sh |
||||
|
# |
||||
|
# Bootstrap Home Assistant's /config on first start. |
||||
|
# |
||||
|
# Home Assistant owns /config once it has started: after first boot the live |
||||
|
# copies win and nothing here is touched again. This script: |
||||
|
# - copies the operator's bootstrap configuration.yaml / secrets.yaml from |
||||
|
# /etc/quadlets/home-assistant into /config only if they are absent; |
||||
|
# - creates the empty include targets configuration.yaml references |
||||
|
# (automations.yaml / scenes.yaml / scripts.yaml) so Home Assistant does not |
||||
|
# fall back to recovery mode on an otherwise-empty /config. |
||||
|
# |
||||
|
set -eu |
||||
|
|
||||
|
SRC=/etc/quadlets/home-assistant |
||||
|
DST=/var/lib/virtiofs/data/home-assistant |
||||
|
HA_UID=10034 |
||||
|
HA_GID=10000 |
||||
|
|
||||
|
install_if_absent() { |
||||
|
if [ -f "$SRC/$1" ] && [ ! -e "$DST/$1" ]; then |
||||
|
echo "Bootstrapping $DST/$1 from $SRC/$1" |
||||
|
install -m "$2" -o "$HA_UID" -g "$HA_GID" "$SRC/$1" "$DST/$1" |
||||
|
else |
||||
|
echo "Keeping existing $DST/$1 (Home Assistant owns it) or no bootstrap provided" |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
stub_if_absent() { |
||||
|
if [ ! -e "$DST/$1" ]; then |
||||
|
echo "Creating empty $DST/$1" |
||||
|
echo "$2" > "$DST/$1" |
||||
|
chown "$HA_UID:$HA_GID" "$DST/$1" |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
install_if_absent configuration.yaml 0644 |
||||
|
install_if_absent secrets.yaml 0600 |
||||
|
stub_if_absent automations.yaml "[]" |
||||
|
stub_if_absent scenes.yaml "[]" |
||||
|
stub_if_absent scripts.yaml "{}" |
||||
@ -0,0 +1,24 @@ |
|||||
|
[Unit] |
||||
|
Description=Home Assistant - Bootstrap /config from the operator-provided templates |
||||
|
Documentation=https://www.home-assistant.io/docs/configuration/ |
||||
|
After=var-lib-virtiofs-data.mount |
||||
|
Requires=var-lib-virtiofs-data.mount |
||||
|
|
||||
|
# Only run if the operator provided a bootstrap configuration |
||||
|
ConditionPathExists=/etc/quadlets/home-assistant/configuration.yaml |
||||
|
|
||||
|
# Start/stop this unit when the target is started/stopped, before the service |
||||
|
PartOf=home-assistant.target |
||||
|
Before=home-assistant.service |
||||
|
|
||||
|
[Service] |
||||
|
Type=oneshot |
||||
|
RemainAfterExit=yes |
||||
|
|
||||
|
# Bootstrap /config from the operator's templates (see init.sh for details). The |
||||
|
# script only ever creates files that are absent, so Home Assistant's live copies |
||||
|
# are never overwritten. |
||||
|
ExecStart=/etc/quadlets/home-assistant/init.sh |
||||
|
|
||||
|
[Install] |
||||
|
WantedBy=home-assistant.target |
||||
@ -0,0 +1,57 @@ |
|||||
|
[Unit] |
||||
|
Description=Home Assistant |
||||
|
Documentation=https://www.home-assistant.io/ |
||||
|
After=network.target var-lib-virtiofs-data.mount home-assistant-init.service |
||||
|
Requires=var-lib-virtiofs-data.mount home-assistant-init.service |
||||
|
|
||||
|
# Only start once Home Assistant has been bootstrapped: the live configuration |
||||
|
# lives in /config (populated by home-assistant-init.service on first boot, or |
||||
|
# already present if Home Assistant was configured before). Past that point the |
||||
|
# bootstrap files in /etc/quadlets are no longer needed. |
||||
|
ConditionPathExists=/var/lib/virtiofs/data/home-assistant/configuration.yaml |
||||
|
|
||||
|
# Start/stop this unit when the target is started/stopped |
||||
|
PartOf=home-assistant.target |
||||
|
|
||||
|
[Container] |
||||
|
ContainerName=home-assistant |
||||
|
Image=home-assistant.image |
||||
|
AutoUpdate=registry |
||||
|
|
||||
|
# No need for root privileges: the s6-overlay v3 entrypoint detects the non-root |
||||
|
# UID, fixes up /run itself, then runs Home Assistant as this user. Verified on |
||||
|
# ghcr.io/home-assistant/home-assistant:stable (2026.9.3): the process runs as |
||||
|
# host UID 10034 and owns everything it writes under /config. |
||||
|
User=10034 |
||||
|
Group=10000 |
||||
|
|
||||
|
# Host networking, as everywhere in this repository. Home Assistant also needs it |
||||
|
# for local discovery (mDNS/SSDP) of devices on the LAN. |
||||
|
Network=host |
||||
|
|
||||
|
# Precious data: Home Assistant owns /config (configuration.yaml, .storage/, |
||||
|
# native backups, ...). It lives on the virtiofs mount so it inherits the |
||||
|
# hypervisor's ZFS snapshot and backup levels. |
||||
|
Volume=/var/lib/virtiofs/data/home-assistant:/config:z |
||||
|
|
||||
|
# Health check: /manifest.json is served without authentication. |
||||
|
HealthCmd=curl -sSf http://127.0.0.1:8123/manifest.json |
||||
|
HealthInterval=30s |
||||
|
HealthTimeout=10s |
||||
|
# Cold start (dependency install + recorder schema migration) takes one to three |
||||
|
# minutes, so probe generously before declaring the container unhealthy. |
||||
|
HealthStartPeriod=180s |
||||
|
HealthRetries=10 |
||||
|
|
||||
|
[Service] |
||||
|
Restart=always |
||||
|
RestartSec=10 |
||||
|
# First boot may pull the image and migrate the recorder schema; give it room. |
||||
|
TimeoutStartSec=300 |
||||
|
TimeoutStopSec=60 |
||||
|
|
||||
|
# Wait for PostgreSQL to be ready on localhost (recorder backend). |
||||
|
ExecStartPre=/bin/sh -c 'exec 2>/dev/null; for try in $(seq 0 12); do if ! /bin/true 5<> /dev/tcp/127.0.0.1/5432; then echo "Waiting for PostgreSQL to be available..."; sleep 5; else exit 0; fi; done; exit 1' |
||||
|
|
||||
|
[Install] |
||||
|
WantedBy=home-assistant.target |
||||
@ -0,0 +1,7 @@ |
|||||
|
[Unit] |
||||
|
Description=podman pull ghcr.io/home-assistant/home-assistant |
||||
|
Documentation=https://www.home-assistant.io/installation/ |
||||
|
|
||||
|
[Image] |
||||
|
# Multi-architecture image (amd64 + arm64), so it runs on the aarch64 target too. |
||||
|
Image=ghcr.io/home-assistant/home-assistant:stable |
||||
@ -0,0 +1,11 @@ |
|||||
|
[Unit] |
||||
|
Description=Home Assistant Service Target |
||||
|
Documentation=man:systemd.target(5) |
||||
|
Requires=postgresql.target home-assistant-init.service home-assistant.service |
||||
|
After=postgresql.target home-assistant-init.service home-assistant.service |
||||
|
|
||||
|
# Allow isolation - can stop/start this target independently |
||||
|
AllowIsolate=yes |
||||
|
|
||||
|
[Install] |
||||
|
WantedBy=multi-user.target |
||||
@ -0,0 +1,5 @@ |
|||||
|
-- Initialization script for Home Assistant database and user (recorder backend) |
||||
|
CREATE USER home_assistant WITH PASSWORD 'home_assistant'; |
||||
|
CREATE DATABASE home_assistant OWNER home_assistant; |
||||
|
GRANT ALL PRIVILEGES ON DATABASE home_assistant TO home_assistant; |
||||
|
ALTER ROLE home_assistant SET client_encoding TO 'utf8'; |
||||
@ -0,0 +1,16 @@ |
|||||
|
http: |
||||
|
routers: |
||||
|
home-assistant: |
||||
|
rule: "Host(`home-assistant`)" |
||||
|
entryPoints: |
||||
|
- http |
||||
|
#- https |
||||
|
middlewares: |
||||
|
service: "home-assistant" |
||||
|
#tls: |
||||
|
# certResolver: le |
||||
|
services: |
||||
|
home-assistant: |
||||
|
loadBalancer: |
||||
|
servers: |
||||
|
- url: "http://127.0.0.1:8123" |
||||
@ -0,0 +1,9 @@ |
|||||
|
variant: fcos |
||||
|
version: 1.4.0 |
||||
|
passwd: |
||||
|
users: |
||||
|
- name: home-assistant |
||||
|
uid: 10034 |
||||
|
gecos: Home Assistant |
||||
|
home_dir: /var/lib/quadlets/home-assistant |
||||
|
primary_group: itix-svc |
||||
@ -0,0 +1,3 @@ |
|||||
|
# Precious data: Home Assistant's /config lives on the virtiofs mount. |
||||
|
# The "$" marks it for removal on `systemd-tmpfiles --purge` (i.e. `make uninstall`). |
||||
|
d$ /var/lib/virtiofs/data/home-assistant 0700 10034 10000 - |
||||
Loading…
Reference in new issue