Skip to content

Runbook — Home Assistant backup & restore

Home Assistant is deployed (when it is) as a Docker container on vps-apps, tracked in the repo (vps-apps/homeassistant/compose.yml, image pinned ghcr.io/home-assistant/home-assistant:2024.8), with config on the data root at /opt/homelab-data/homeassistant/config.

Current state: Home Assistant is not running — the compose is tracked but no container exists and /opt/homelab-data/homeassistant has not been created. Anything below assumes it is brought up; the commands are the same whenever it is. It is treated as a sensitive, mesh-only app (house rule 2) with no public path.

How HA stores state

Home Assistant keeps everything under its config directory (/opt/homelab-data/homeassistant/config on vps-apps):

  • configuration.yaml — the main config
  • .storage/state, entities, dashboards, automations, Lovelace (JSON)
  • secrets.yaml — (gitignored) private values — never surfaced to the repo
  • home-assistant.db / home-assistant_v2.db — history/recorder DB (large)
  • custom_components/, themes/, tts/, media/

Because it's under /opt/homelab-data, it is covered by the Backrest nightly plan once the directory exists (/backup/opt-homelab-data). That is the primary backup.

Backup

Standard — rely on the nightly restic (config dir)

/opt/homelab-data/homeassistant/config is under the /backup/opt-homelab-data plan, so a nightly restic snapshot covers it. Verify:

# vps-apps
restic -r /repos/dietpi-nfs snapshots --latest 3 | grep -i homeassistant
recent snapshot present + config size sane.

Ad-hoc / before an upgrade

Capture a consistent copy before a config change or HA major upgrade:

docker stop homeassistant
cp -a /opt/homelab-data/homeassistant/config /var/tmp/ha-config-pre-<date>
docker start homeassistant
(Stopping avoids mid-write DB/rescate. <date> = the HA version you're coming from, e.g. 2024.8.)

Restore

  1. Stop HA:
    docker compose -f /opt/homelab/vps-apps/homeassistant/compose.yml down
    
  2. Preserve the current tree, then restore the good one:
    mv /opt/homelab-data/homeassistant/config \
       /opt/homelab-data/homeassistant/config.pre-restore
    cp -a /var/tmp/ha-config-<date> /opt/homelab-data/homeassistant/config
    # or from restic:
    # restic -r /repos/dietpi-nfs restore --target /var/tmp/restore \
    #   --include 'opt/homelab-data/homeassistant/config/**' latest
    
  3. Fix ownership — HA runs as root in the official image; if you copy as jmrdez, correct it:
    chown -R 0:0 /opt/homelab-data/homeassistant/config
    
  4. Bring it up:
    docker compose -f /opt/homelab/vps-apps/homeassistant/compose.yml up -d
    docker compose ... logs --tail 100   # healthy, no config errors
    
  5. Verify the UI loads, dashboards/automations are present, and (if you restored the DB) history exists.
  6. Keep config.pre-restore until confirmed, then remove it.

Notes

  • Mesh-only / sensitive: no published port; reach HA over the mesh IP (100.64.0.100). Never add a public listener (house rule 2).
  • secrets.yaml is not in git; it is restored with the config dir, so the restic snapshot or your ad-hoc copy is the only source. Do not lose it.
  • The recorder DB (home-assistant.db) can be large and is low value to restore; it's fine to let HA re-build history if it's missing.