Продвинутый

Home Assistant и Docker: сервер умного дома с нуля

Алексей Кузнецов
Алексей Кузнецов
Системный администратор22 января 2026 г.23 мин чтения

Пошаговое руководство по развертыванию Home Assistant в Docker: выбор оборудования, настройка сети, интеграции, мониторинг и резервное копирование для надёжн...

Home Assistant и Docker: сервер умного дома с нуля

Пошаговое руководство по развертыванию Home Assistant в Docker: выбор оборудования, настройка сети, интеграции, мониторинг и резервное копирование для надёжного умного дома.

Введение

Почему Docker для Home Assistant

Если мы посмотрим на варианты запуска Home Assistant, то их четыре: HA OS (ранее HassOS), HA Supervised, HA Container и HA Core. Первые два — это управляемые образы, где система решает за вас, что и как обновлять. Последние два — это чистый Docker-образ и установка в виртуальное окружение Python соответственно.

С практической точки зрения, для домашнего сервера, где уже крутится что-то ещё — тот же Plex, Nextcloud, мониторинг в Prometheus — вариант с Docker Container (официальный образ ghcr.io/home-assistant/home-assistant:stable) даёт максимальную предсказуемость. Вы контролируете версию, знаете, когда и что обновляется, и можете откатиться одной командой, если релиз сломал интеграцию с Zigbee-координатором.

Во-первых, изоляция. Home Assistant в контейнере не тронет системный Python, не потянет за собой systemd-юниты из пакетного менеджера дистрибутива и не конфликтует с библиотеками, которые нужны вашим кастомным скриптам. Во-вторых, воспроизводимость. docker compose up -d на новом железе поднимет идентичное окружение за минуту — достаточно примонтировать том с конфигурацией. В-третьих, сеть. Режим network_mode: host (обязателен для автообнаружения mDNS, UPnP и работы с локальными устройствами вроде Shelly или ESPHome) в Docker работает предсказуемо, в отличие от HA Supervised, где сеть управляет NetworkManager внутри контейнера-супервизора.

Есть нюанс: аддоны (Add-ons) в чистом Docker не работают. Но Mosquitto, Zigbee2MQTT, ESPHome, File Editor, MariaDB, PostgreSQL, Grafana — всё это отдельные контейнеры, которые вы описываете в том же docker-compose.yml. Это не ограничение, а архитектурная гигиена: каждый сервис в своём контейнере, со своими лимитами ресурсов, логами и политикой рестарта.

Сравнение с IKEA уместно: HA OS — это купленная готовая кухня, HA Supervised — кухня-гарнитур, которую собрали за вас, а Docker Compose — это набор модулей, из которых вы собираете именно то, что нужно, с теми фасадами и петлями, которые выбрали сами. Свои нюансы есть, но результат — ваш.

Что понадобится

Железо. Home Assistant не требователен к CPU, но чувствителен к задержкам диска и объёму RAM при параллельной работе базы данных, логгера и интеграций. Минимум для комфортной работы с 50+ устройствами, историей за год и парой камер через Frigate:

  • CPU: 2 vCPU (x86_64 или ARM64). Raspberry Pi 4/5 — работает, но на Pi 4 с 4 ГБ RAM уже тесно, если поднимаете PostgreSQL и Frigate локально. Бывший в употреблении Thin Client (Dell Wyse 5070, HP t640) или Mini PC (Beelink, Minisforum) на N100/N305 — оптимальное соотношение ватт/производительность/цена на 2026 год.
  • RAM: 4 ГБ — абсолютный минимум, 8 ГБ — комфортно, 16 ГБ — с запасом на Frigate, PostgreSQL, Grafana Loki и будущие эксперименты.
  • Диск: 32 ГБ eMMC/SD — для системы, но базу данных (home-assistant_v2.db) и медиа лучше вынести на отдельный SSD/NVMe. SD-карты умирают предсказуемо — обычно в самый неподходящий момент. ZFS-пул с сжатием zstd и atime=off на отдельном накопителе решит вопрос надёжности раз и навсегда.
  • Сеть: проводной Ethernet 1 Гбит/с. Wi-Fi для сервера умного дома — плохая идея: mDNS, SSDP и Zigbee2MQTT/Thread Border Router требуют стабильного L2-сегмента.

Программная база. Предполагаю, что на хосте уже стоит Debian 12 (bookworm) / Ubuntu 24.04 LTS / Alpine Linux и настроен Docker Engine + Docker Compose v2 (плагин docker compose, а не устаревший docker-compose на Python). Проверьте:

bash
docker version --format '{{.Server.Version}}'
docker compose version

Ожидаемый вывод — Docker Engine 27.x и Compose v2.29+. Если Compose ставился через apt install docker-compose-plugin — всё верно.

Сеть. Зафиксируйте статический IP для хоста (через DHCP reservation на роутере или systemd-networkd / Netplan на самом хосте). Home Assistant должен быть доступен по предсказуемому адресу, например 192.168.10.10. DNS-имя ha.local (или homeassistant.local — дефолт mDNS) настроится автоматически при включении network_mode: host, но для обратного прокси и TLS удобнее иметь запись в локальном DNS (AdGuard Home, Pi-hole, Unbound) или в /etc/hosts клиентов.

Порты. На хосте не должно висеть ничего на 8123/tcp (веб-интерфейс HA), 5353/udp (mDNS), 1900/udp (SSDP). Проверьте:

bash
ss -tulpn | grep -E ':8123|:5353|:1900'

Если порт занят — разберитесь, чем, перед деплоем.

Резервное копирование. Планируйте стратегию до первого запуска. Минимум: ежедневный снапшот конфигурации (/config) на отдельный носитель/сетевую шара. Идеально: бэкап в S3-совместимое хранилище (MinIO на TrueNAS, Backblaze B2, R2) через restic или borgbackup с шифрованием и проверкой целостности. Про «как настроить бэкап правильно» — отдельная глава, но закладывайте том /backup в compose-файл сразу.

Структура каталогов на хосте (пример для /opt/ha):

text
/opt/ha/
├── docker-compose.yml
├── .env                    # переменные окружения: TZ, PUID, PGID, версии образов
├── config/                 # том конфигурации HA (configuration.yaml, automations, .storage)
├── addons/                 # конфиги аддонов: mosquitto, zigbee2mqtt, esphome, etc.
├── backup/                 # локальные снапшоты перед выгрузкой в S3
├── media/                  # медиа-файлы камер, TTS, звуки уведомлений
└── ssl/                    # сертификаты для reverse proxy (если терминируете TLS на хосте)

Права доступа. Контейнер Home Assistant запускается от пользователя с UID/GID 1000 (дефолт в образе). Если на хосте ваш пользователь — тоже 1000, проблем нет. Если нет — задайте PUID=1000 PGID=1000 в .env и убедитесь, что каталоги config/, addons/, backup/, media/ принадлежат этому UID:GID. Иначе HA не сможет писать в .storage, обновлять интеграции и сохранять бэкапы.

bash
# пример подготовки на хосте
sudo mkdir -p /opt/ha/{config,addons,backup,media,ssl}
sudo chown -R 1000:1000 /opt/ha

Всё, база готова. Дальше — docker-compose.yml, настройка configuration.yaml, интеграция Zigbee/Thread/Matter, мониторинг и алертинг.

Развёртывание Home Assistant в Docker

Создание docker-compose.yml

Начнём с главного: Home Assistant в Docker запускается через официальный образ ghcr.io/home-assistant/home-assistant:stable. Не тяните latest — в продакшене (даже домашнем) важна предсказуемость. Тег stable обновляется раз в две недели, после выхода патч-релиза. Если хотите жить на острие — есть beta и dev, но за ломаные интеграции отвечаете сами.

Минимальный рабочий docker-compose.yml дляamd64/arm64 выглядит так:

yaml
version: '3.8'

services:
  homeassistant:
    image: ghcr.io/home-assistant/home-assistant:stable
    container_name: homeassistant
    restart: unless-stopped
    network_mode: host
    volumes:
      - /opt/homeassistant/config:/config
      - /etc/localtime:/etc/localtime:ro
      - /run/dbus:/run/dbus:ro
    environment:
      - TZ=Europe/Moscow
    # healthcheck нужен, чтобы Docker знал: жив ли контейнер
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8123/"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 40s

Разберём по пунктам.

network_mode: host — это не опционально. Home Assistant должен видеть локальную сеть «как есть»: mDNS, SSDP, broadcast-рассылки от Zigbee-шлюзов, Bluetooth-прокси, ESPHome-устройств. В bridge-сети это работает через дополнительные костыли (avahi-reflector, macvlan), которые ломаются при обновлении ядра. Host-сеть убирает класс проблем целиком. Порт 8123 будет занят на хосте — учитывайте это, если на той же машине висит Nginx или Caddy.

/run/dbus:/run/dbus:ro — нужен для работы с Bluetooth (BlueZ), ModemManager, NetworkManager. Без этого не поднимете Bluetooth-прокси для ESPHome или не заведёте Zigbee-стик через ZHA, если он требует доступ к системной шине.

Healthcheck — не декор. Если контейнер завис в состоянии «запускается» (часто бывает после некорректного обновления или поломки БД), Docker не перезапустит его без healthcheck. start_period: 40s даёт время на первую инициализацию и миграции БД.

Положите файл в /opt/homeassistant/docker-compose.yml. Директорию для конфига создайте заранее:

bash
mkdir -p /opt/homeassistant/config
chown -R 1000:1000 /opt/homeassistant/config

UID/GID 1000 — дефолт внутри контейнера. Если на хосте другой пользователь — подставьте свои. Запуск:

bash
cd /opt/homeassistant
docker compose up -d
docker compose logs -f

Первый запуск тянет образ (~400 МБ), создаёт структуру конфига, генерирует configuration.yaml и поднимает веб-интерфейс на http://<IP-хоста>:8123. Настройка через UI — создание владельца, выбор имени дома, часового пояса — занимает пару минут.


Настройка volumes и сетей

С базовым запуском разобрались. Теперь — про то, как не потерять данные при обновлении контейнера и как выставить наружу только то, что нужно.

Volumes: разделяйте конфиг и данные

Официальный образ кладёт всё в /config. Но внутри там смешаны: YAML-конфиги, база данных SQLite (home-assistant_v2.db), логи, кэш интеграций, SSL-сертификаты, медиа-файлы. При бэкапе и миграции удобнее, когда это разделено.

Мой вариант для продакшена:

yaml
volumes:
  # Конфигурация — читается часто, пишется редко
  - /opt/homeassistant/config:/config:rw
  # База данных — интенсивный I/O, выносим на отдельный том/диск
  - ha_db:/config/home-assistant_v2.db
  # Медиа и бэкапы — большой объём, не нужен на быстром SSD
  - /mnt/storage/homeassistant/media:/config/media:rw
  - /mnt/storage/homeassistant/backups:/config/backup:rw
  # SSL — если терминируете TLS внутри HA (не рекомендую, см. ниже)
  - /opt/homeassistant/ssl:/config/ssl:ro

Создайте именованный том для БД:

bash
docker volume create ha_db

Почему так: SQLite на ZFS/btrfs с sync=always или на HDD даёт зависания UI на запись. Вынося БД в отдельный том, можете положить его на NVMe с sync=disabled (риск потери последних секунд при отключении питания — приемлем для телеметрии), а медиа и бэкапы — на медленный RAID. Конфиг остаётся на системном диске — он мелкий, читается при старте, пишется только при правке через UI.

Сеть: не пробрасывайте 8123 наружу напрямую

network_mode: host удобен внутри LAN, но если вы пробросите порт 8123 на роутере — получите брутфорс за сутки. Правильный путь: reverse proxy на том же хосте (Caddy, Nginx, Traefik) + TLS + базовая авторизация или Authelia/Keycloak.

Пример для Caddy (ставится отдельно, тоже в Docker):

caddy
# /opt/caddy/Caddyfile
ha.example.com {
    reverse_proxy 127.0.0.1:8123 {
        header_up X-Forwarded-Proto https
        header_up X-Forwarded-Host {host}
    }
    # Базовая защита от ботов
    @bots {
        header User-Agent *bot*
        header User-Agent *crawler*
        header User-Agent *spider*
    }
    respond @bots 403
}

В docker-compose.yml Home Assistant добавляем зависимость от Caddy (чтобы стартовал после) и убираем порт из хоста — он и так на 127.0.0.1:8123 доступен только локально:

yaml
services:
  homeassistant:
    # ... остальное без изменений
    depends_on:
      caddy:
        condition: service_healthy

Caddy сам выдаст и продлит Let's Encrypt сертификаты. Никаких certbot-кронов, никаких ручных действий.

Дополнительные сети для изоляции

Если у вас несколько контейнеров (Mosquitto, Zigbee2MQTT, Frigate, PostgreSQL для recorder), не сваливайте всё в host-сеть. Создайте пользовательскую bridge-сеть:

yaml
networks:
  ha_internal:
    driver: bridge
    ipam:
      config:
        - subnet: 172.28.0.0/24

И подключайте к ней сопутствующие сервисы. Home Assistant в network_mode: host всё равно видит их по 172.28.0.x, а они не видят друг друга без необходимости. Mosquitto не должен быть доступен из интернета — ни в коем случае.

Пример для Mosquitto в той же compose-стеке:

yaml
  mosquitto:
    image: eclipse-mosquitto:2
    container_name: mosquitto
    restart: unless-stopped
    networks:
      - ha_internal
    volumes:
      - /opt/mosquitto/config:/mosquitto/config:ro
      - /opt/mosquitto/data:/mosquitto/data
      - /opt/mosquitto/log:/mosquitto/log
    healthcheck:
      test: ["CMD", "mosquitto_sub", "-t", "$$SYS/broker/uptime", "-C", "1", "-i", "healthcheck"]
      interval: 30s
      timeout: 10s
      retries: 3

В Home Assistant (Settings → Devices & Services → MQTT) указываете хост 172.28.0.2 (или имя сервиса mosquitto, если HA тоже в этой сети — но у нас host mode, поэтому IP).


Итог: рабочий docker-compose.yml — это не про «запустилось», а про «переживёт обновление, падение питания и переезд на другое железо». Вынесли БД в отдельный том, закрыли веб-морду за reverse proxy, изолировали MQTT и периферию в свою сеть. Дальше — интеграции, но это уже тема для следующего раздела.

Интеграции и периферия

Zigbee2MQTT и Bluetooth

С практической точки зрения, Zigbee — это единственный протокол, который в домашних условиях даёт предсказуемость. Wi-Fi датчики съедают адреса в DHCP, зависают при перезагрузке роутера и требуют отдельного VLAN, если вы параноик. Z-Wave — дорог и умирает. Thread/Matter — перспективно, но в 2026 году экосистема ещё не зрела для «поставил и забыл».

Zigbee2MQTT запускается как отдельный контейнер рядом с Home Assistant. Не ставьте его аддоном внутри HA — при обновлении ядра вы потеряете управление сетью, а пересборка координатора — удовольствие на час.

Железо. Берём Sonoff Zigbee 3.0 USB Dongle Plus (на чипе EFR32MG21) или Home Assistant SkyConnect. Оба прошиваются официальными прошивками, оба поддерживают Zigbee 3.0 и Thread. У Sonoff лучше антенна, у SkyConnect — нативная поддержка в HA. Я держу Sonoff на винни-пухе (мой основной Proxmox-хост), SkyConnect — в резерве.

Подключение через USB-проброс в Docker Compose:

yaml
services:
  zigbee2mqtt:
    image: koenkk/zigbee2mqtt:2.3.0
    container_name: zigbee2mqtt
    restart: unless-stopped
    network_mode: host
    volumes:
      - /opt/zigbee2mqtt/data:/app/data
      - /run/udev:/run/udev:ro
    devices:
      - /dev/serial/by-id/usb-ITead_Sonoff_Zigbee_3.0_USB_Dongle_Plus_00d4b1faa612ec11879723c7bd930c07-if00-port0:/dev/ttyUSB0
    environment:
      - TZ=Europe/Moscow
    # healthcheck важен: если координатор завис, рестартим контейнер
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

Важно: используйте /dev/serial/by-id/..., а не /dev/ttyUSB0. При перезагрузке хоста нумерация ttyUSB* может прыгать, by-id — стабилен. Узнать путь:

bash
ls -la /dev/serial/by-id/

Конфигурация /opt/zigbee2mqtt/data/configuration.yaml — минимально необходимая:

yaml
homeassistant: true
permit_join: false
mqtt:
  base_topic: zigbee2mqtt
  server: mqtt://mqtt:1883
  user: zigbee
  password: ${MQTT_ZIGBEE_PASSWORD}
serial:
  port: /dev/ttyUSB0
  adapter: ezsp
advanced:
  network_key: GENERATE_YOUR_OWN_32_HEX_CHARS
  pan_id: 0x1a62
  channel: 15
  # канал 15 не пересекается с Wi-Fi 1, 6, 11
  # pan_id фиксируем — при пересоздании контейнера сеть не развалится
frontend:
  port: 8080
  auth_token: ${Z2M_FRONTEND_TOKEN}
experimental:
  output: json

Сгенерируйте network_key один раз: openssl rand -hex 16. Сохраните в 1Password / Bitwarden / keepass. Потеря ключа = пересборка всей Zigbee-сети с нуля.

MQTT-брокер — отдельный контейнер (Mosquitto или EMQX). Не используйте встроенный в HA — он не умеет ACL и персистентность на уровне, нужном для продакшена. У меня mqtt — это отдельный сервис в том же docker-compose, с данными на ZFS-датасете.

Bluetooth. Для Xiaomi/Aqara кнопок, датчиков температуры LYWSD03MMC, смарт-замков — нужен Bluetooth-прокси. В 2026 году два варианта:

  1. ESPHome Bluetooth Proxy на ESP32-C3 (например, ESP32-C3-DevKitM-1). Стоит ~400 ₽, прошивается за 5 минут, работает по Wi-Fi, отдаёт рекламные пакеты в HA через ESPHome API.
  2. USB Bluetooth 5.0+ донгл (CSR8510 или на базе Realtek RTL8761B) — воткнут прямо в хост, проброшен в контейнер bluetooth (официальный образ homeassistant/bluetooth).

Второй вариант проще, если сервер стоит в центре квартиры. Первый — если нужно покрыть дальние комнаты. Я использую оба: донгл на сервере для ближней зоны, три ESP32-C3 — в спальне, на кухне, в ванной.

docker-compose.yml для Bluetooth-донгла:

yaml
  bluetooth:
    image: homeassistant/bluetooth:2024.12.0
    container_name: bluetooth
    restart: unless-stopped
    network_mode: host
    privileged: true
    devices:
      - /dev/bus/usb:/dev/bus/usb
    volumes:
      - /run/dbus:/run/dbus
    environment:
      - DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket

В Home Assistant: Настройки → Устройства и службы → Bluetooth → «Настроить» → выбираем bluetooth контейнер. После этого HA начинает видеть BLE-объявления.


Подключение датчиков и устройств

Во-первых, парьтесь. В Zigbee2MQTT веб-интерфейс (порт 8080) — кнопка «Permit join (all)». Нажимаете, держите 3 минуты, вставляете батарейку в датчик / зажимаете кнопку на 5 секунд — устройство появляется в списке. Переименовываете сразу: 0x00158d000xxxxxxx → sensor_temperature_bedroom. Не ленитесь — через полгода не вспомните, что за 0x00158d0002a1b3c4.

Пример автоматизации переименования через MQTT (если устройств десятки):

bash
# Получить список
mosquitto_sub -h mqtt -u zigbee -P "$MQTT_ZIGBEE_PASSWORD" -t 'zigbee2mqtt/bridge/devices' -C 1 | jq .

В Home Assistant устройства появляются автоматически благодаря homeassistant: true в конфиге Z2M. Но — важный нюанс — сущности создаются с техническими именами. Исправляйте в UI: Настройки → Устройства и службы → Zigbee2MQTT → Устройство → сущность → шестерёнка → «Имя сущности». Делайте это сразу, иначе в YAML-автоматизациях будете писать sensor.temperature_23_45 вместо sensor.temperature_bedroom.

Типовые проблемы и решения из практики:

СимптомПричинаРешение
Датчик не парьетсяКанал 15 занят Wi-FiСмените канал на 20 или 25 в configuration.yaml, перезапустите Z2M, репарьте
Устройство «unavailable» через деньСлабый сигнал / нет репитеровДобавьте розетку с питанием (Sonoff S26, IKEA Tradfri) — они работают как роутеры
Кнопка Aqara двойное нажатие не работаетНе включен legacy_action_triggersВ настройках устройства в Z2M UI: legacy_action_triggers: true
Bluetooth датчик теряетсяДонгл забит другими устройствамиbluetoothctl → power off → power on в cron каждые 6 часов, или ставьте ESPHome proxy

Репитеры. Любое Zigbee-устройство с постоянным питанием (розетка, реле, лампочка) — репитер. Планируйте размещение: максимум 10–15 метров между узлами через стены. У меня в каждой комнате минимум одна розетка Sonoff S26R2ZB — дешёвы, компактны, не глючат.

Бэкап Zigbee-сети. Файл /opt/zigbee2mqtt/data/coordinator_backup.json создаётся автоматически при грамотной прошивке координатора (Sonoff/SkyConnect поддерживают). Настройте его копирование в ваш бэкап-скрипт (Borg/Restic на TrueNAS). Восстановление: останавливаете Z2M, кладёте файл на место, запускаете — сеть поднимается без репайринга всех устройств.

Файрвол. Если у вас разные VLAN для IoT и управления — пробросьте порт 1883 (MQTT) и 8080 (Z2M UI) только от хоста с HA. Не открывайте наружу. Zigbee2MQTT не имеет встроенной аутентификации веб-интерфейса — auth_token в конфиге защищает только API, не UI.

С Bluetooth проще: после настройки прокси/донгла устройства обнаруживаются в HA автоматически. Добавляете через UI: Настройки → Устройства и службы → Bluetooth → «Добавить устройство». Имя даёте человеческое сразу.


Итог: Zigbee2MQTT в Docker + MQTT-брокер + правильный канал/ключ/репитеры — фундамент, который работает годами. Bluetooth — дополнение для того, что не зашло в Zigbee (Xiaomi, смарт-замки). Не смешивайте протоколы без нужды: каждый дополнительный радиомодуль — точка отказа и поверхность атаки.

Мониторинг и резервное копирование

Настройка Prometheus и Grafana

Home Assistant «из коробки» отдаёт метрики в формате Prometheus по эндпоинту /api/prometheus. Доступ к нему защищён long-lived токеном — это удобнее, чем возиться с basic auth или отдельным sidecar-экспортером.

Создаём токен: профиль → Длинноожидающие токены доступа → «Создать токен». Назовём его prometheus-scraper, срок действия — неограниченный (или год, если политика требует ротации). Токен скопируйте сразу — второй раз не покажет.

Теперь конфиг Prometheus. Добавляем джобу в prometheus.yml:

yaml
scrape_configs:
  - job_name: 'home-assistant'
    static_configs:
      - targets: ['homeassistant:8123']
    metrics_path: '/api/prometheus'
    scheme: http
    authorization:
      credentials: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...'  # ваш токен
    scrape_interval: 30s
    scrape_timeout: 10s

Обратите внимание: homeassistant — это имя сервиса в той же Docker-сети, что и Prometheus. Если Prometheus крутится на отдельной ноде — подставьте IP или DNS-имя ноды с HA.

Проверяем: curl -H "Authorization: Bearer <token>" http://homeassistant:8123/api/prometheus | head -20. Должен вернуть текст с метриками вроде python_info{version="3.11.9"} 1.0.

Что реально полезно мониторить:

  • hass_entities_total — общее число сущностей. Резкий скачок = кто-то подключил интеграцию без спроса или сломался MQTT-брокер.
  • hass_state_changes_total — частота смены состояний. Аномальный рост = зацикленная автоматизация или глючный датчик.
  • hass_automation_triggered_total — счетчик срабатываний автоматизаций. Полезно для алерта «автоматика не сработала за 24 часа».
  • process_resident_memory_bytes / process_cpu_seconds_total — ресурсы контейнера. HA любит память, особенно с большим количеством интеграций.

Графану не буду учить настраивать — импорт дашборда делается за минуту. Рекомендую дашборд Home Assistant Overview (ID 10734 на grafana.com) — он уже разбит по панелям: сущности, автоматизации, скрипты, системные метрики. Добавляете datasource Prometheus, импортируете JSON — готово.

Алерты кладите в alerts.yml и подключаете через rule_files в prometheus.yml. Минимальный набор:

yaml
groups:
  - name: home-assistant
    rules:
      - alert: HomeAssistantDown
        expr: up{job="home-assistant"} == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Home Assistant недоступен"
          description: "Скрапинг фейлится уже 2 минуты"

      - alert: HomeAssistantHighMemory
        expr: (process_resident_memory_bytes{job="home-assistant"} / 1024 / 1024) > 2048
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "HA потребляет более 2 ГБ RAM"
          description: "Текущее потребление: {{ $value }} MB. Проверьте интеграции."

      - alert: HomeAssistantNoStateChanges
        expr: rate(hass_state_changes_total[15m]) == 0
        for: 30m
        labels:
          severity: warning
        annotations:
          summary: "Нет смены состояний 30 минут"
          description: "Возможно, HA завис или отвалился MQTT/Zigbee координатор"

Порог 2 ГБ под мою конфигурацию (около 150 сущностей, Zigbee2MQTT, Frigate, несколько камер). Подбирайте под себя — top внутри контейнера покажет реальную картину.


Автоматизация бэкапов

Резервное копирование в HA — тема, где «сделал и забыл» приводит к потере истории за год. Официальный аддон «Backup» работает только в supervised-установке. В Docker мы собираем бэкап сами: конфиг (/config), медиа (/media), SSL-сертификаты (если терминируете TLS на HA) и дамп БД (если используете внешний PostgreSQL — отдельно, через pg_dump).

Скрипт бэкапа кладу в /opt/scripts/ha-backup.sh на хосте (не в контейнере — хост имеет доступ к томам и к удалённому хранилищу):

bash
#!/usr/bin/env bash
set -euo pipefail

# === Конфигурация ===
HA_CONFIG_DIR="/srv/homeassistant/config"
HA_MEDIA_DIR="/srv/homeassistant/media"
BACKUP_ROOT="/srv/backups/homeassistant"
RETENTION_DAYS=30
RCLONE_REMOTE="nas:backups/homeassistant"  # настроенный rclone remote
DATE=$(date +%Y-%m-%d_%H-%M-%S)
BACKUP_NAME="ha-backup-${DATE}.tar.gz"
TMP_DIR=$(mktemp -d)

# === Логирование ===
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }

log "Начинаю бэкап Home Assistant"

# Останавливаем HA для консистентного снапшота БД (SQLite)
log "Останавливаю контейнер homeassistant..."
docker stop homeassistant

# Архивируем
log "Создаю архив..."
tar -czf "${TMP_DIR}/${BACKUP_NAME}" \
    -C "${HA_CONFIG_DIR}" . \
    -C "${HA_MEDIA_DIR}" . 2>/dev/null

# Запускаем HA обратно
log "Запускаю контейнер homeassistant..."
docker start homeassistant

# Перемещаем в локальное хранилище
mv "${TMP_DIR}/${BACKUP_NAME}" "${BACKUP_ROOT}/"
log "Локальный бэкап сохранён: ${BACKUP_ROOT}/${BACKUP_NAME}"

# Загружаем на NAS/облако через rclone
if command -v rclone >/dev/null 2>&1; then
    log "Синхронизирую с удалённым хранилищем..."
    rclone copy "${BACKUP_ROOT}/${BACKUP_NAME}" "${RCLONE_REMOTE}" --progress
    log "Удалённый бэкап завершён"
else
    log "rclone не найден, пропускаю удалённую копию"
fi

# Ротация локальных бэкапов
log "Удаляю бэкапы старше ${RETENTION_DAYS} дней..."
find "${BACKUP_ROOT}" -name 'ha-backup-*.tar.gz' -mtime +${RETENTION_DAYS} -delete

# Ротация на удалёнке (rclone delete с --min-age)
if command -v rclone >/dev/null 2>&1; then
    rclone delete "${RCLONE_REMOTE}" --min-age ${RETENTION_DAYS}d --include 'ha-backup-*.tar.gz'
fi

log "Бэкап завершён успешно"
rm -rf "${TMP_DIR}"

Делаем исполняемым: chmod +x /opt/scripts/ha-backup.sh.

Почему останавливаю контейнер: SQLite не любит горячие копии. tar читает файлы последовательно — если HA в этот момент пишет в БД, получите коррупцию. Остановка на 10–15 секунд приемлема для домашнего сервера. Если нужен нулевой даунтайм — мигрируйте на PostgreSQL и делайте pg_dump без остановки.

Systemd-таймер для запуска каждую ночь в 03:15:

/etc/systemd/system/ha-backup.service:

ini
[Unit]
Description=Home Assistant Backup
After=docker.service
Requires=docker.service

[Service]
Type=oneshot
ExecStart=/opt/scripts/ha-backup.sh
StandardOutput=journal
StandardError=journal

/etc/systemd/system/ha-backup.timer:

ini
[Unit]
Description=Daily Home Assistant Backup at 03:15

[Timer]
OnCalendar=*-*-* 03:15:00
Persistent=true
RandomizedDelaySec=15m

[Install]
WantedBy=timers.target

Включаем: systemctl daemon-reload && systemctl enable --now ha-backup.timer.

Проверка: systemctl list-timers ha-backup.timer покажет следующее срабатывание. Логи — journalctl -u ha-backup.service -f.

Восстановление — отдельный скрипт, который я держу рядом (ha-restore.sh). Суть: останавливаем HA, распаковываем архив в /srv/homeassistant/config и /srv/homeassistant/media, фиксим владельца (chown -R 1000:1000 — UID/GID пользователя внутри контейнера), запускаем HA. Тестируйте восстановление раз в квартал. Бэкап, который не восстанавливается — не бэкап, а файл на диске.


Итог: мониторинг даёт видимость до того, как пользователи (жена, дети) начнут жаловаться «умный дом не работает». Бэкапы — страховка от потери лет истории и настроек. Оба механизма должны быть скучными, предсказуемыми и проверяемыми. Если вы не получали алерт «Home Assistant Down» за полгода — проверьте, работает ли Alertmanager.

Часто задаваемые вопросы

Как обновлять Home Assistant?

Обновление в Docker — это стандартный цикл pull → stop → remove → start. Никакой магии, просто контейнер с новым образом.

Ручной способ (рекомендую):

bash
cd /opt/homeassistant
docker compose pull
docker compose up -d --remove-orphans

Флаг --remove-orphans чистит старые контейнеры, если вы меняли имя сервиса в compose-файле. После запуска проверяйте логи:

bash
docker compose logs -f homeassistant | head -50

Ищите строку Home Assistant initialized — значит, всё подошло.

Перед обновлением — всегда бэкап конфигурации. Минимум:

bash
tar -czf /backup/ha-config-$(date +%F).tar.gz -C /opt/homeassistant/config .

Релизы выходят каждые три недели (обычно в среду). Читайте changelog — иногда ломают интеграции или меняют конфиг-схему. Если видите BREAKING CHANGES для своих интеграций — читайте миграционный гайд перед pull.

Автообновления через Watchtower — вариант для ленивых, но я не фанат. Home Assistant иногда требует ручных действий после мажорного релиза (миграция БД, правка YAML). Watchtower обновит контейнер в 3 ночи, а утром вы получите неработающий умный дом.

Если очень хочется автоматику — настройте Watchtower только на уведомления, а применение делайте руками:

yaml
# docker-compose.watchtower.yml
services:
  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - WATCHTOWER_MONITOR_ONLY=true
      - WATCHTOWER_SCHEDULE=0 0 6 * * *
      - WATCHTOWER_NOTIFICATIONS=shoutrrr
      - WATCHTOWER_NOTIFICATION_URL=telegram://<bot_token>@<chat_id>

Тогда в 6 утра придёт сообщение «есть обновление», а решите вы — ставить или подождать.


Где хранить конфигурацию?

Единственно правильный ответ: в bind-mount на хосте, под версионным контролем.

В docker-compose.yml:

yaml
services:
  homeassistant:
    image: ghcr.io/home-assistant/home-assistant:stable
    container_name: homeassistant
    volumes:
      - /opt/homeassistant/config:/config
      - /etc/localtime:/etc/localtime:ro
    # ...

Путь /opt/homeassistant/config на хосте — это ваша единственная истина. Внутри контейнера это /config, но снаружи вы видите живые файлы.

Почему не named volume? Потому что docker volume inspect и docker cp — это лишние абстракции. С bind-mount вы:

  • Редактируете configuration.yaml в любимом редакторе на хосте
  • Видите изменения сразу в git diff
  • Бэкапите одной командой tar или rsync
  • Переносите на другой сервер scp -r

Структура, которую я использую:

/opt/homeassistant/
├── config/
│   ├── configuration.yaml
│   ├── secrets.yaml
│   ├── automations.yaml
│   ├── scripts.yaml
│   ├── scenes.yaml
│   ├── dashboards/
│   │   └── lovelace.yaml
│   ├── packages/
│   │   ├── climate/
│   │   ├── lighting/
│   │   └── security/
│   └── custom_components/   # только если форкаете интеграции
├── docker-compose.yml
├── .env                     # токены, пароли — НЕ в git
└── backup/                  # локальные снапшоты

Git-воркфлоу:

bash
cd /opt/homeassistant
git init
echo ".env" > .gitignore
echo "config/.storage/" >> .gitignore   # внутреннее состояние HA
echo "config/home-assistant.log" >> .gitignore
echo "config/home-assistant_v2.db*" >> .gitignore
git add .
git commit -m "Initial HA config"

После каждого изменения конфига — коммит. Перед обновлением — тег:

bash
git tag -a pre-update-2026.09 -m "Before 2026.9 update"

Если обновление сломало что-то — git checkout pre-update-2026.09 и вы за минуту в рабочем состоянии.

Секреты — только в secrets.yaml (который в .gitignore) или в .env файле compose. Никаких паролей в configuration.yaml. Пример:

yaml
# configuration.yaml
mqtt:
  broker: !secret mqtt_broker
  username: !secret mqtt_user
  password: !secret mqtt_pass
yaml
# secrets.yaml (не в git!)
mqtt_broker: "192.168.10.5"
mqtt_user: "ha_mqtt"
mqtt_pass: "сгенерированный_длинный_пароль"

А в .env для compose:

bash
# .env
POSTGRES_PASSWORD=тоже_сложный_пароль
GRAFANA_ADMIN_PASSWORD=и_этот

Бэкап стратегия — 3-2-1:

  • Локально: /opt/homeassistant/backup/ (каждый день по крону)
  • На сторадж (TrueNAS/NFS): rsync раз в час
  • В облако (S3/B2/Rclone): раз в сутки, зашифрованный restic или borg

Скрипт для крона (/etc/cron.daily/ha-backup):

bash
#!/bin/bash
set -euo pipefail

CONFIG_DIR="/opt/homeassistant/config"
BACKUP_DIR="/opt/homeassistant/backup"
RETENTION_DAYS=30

DATE=$(date +%F-%H%M)
ARCHIVE="${BACKUP_DIR}/ha-config-${DATE}.tar.gz"

tar -czf "${ARCHIVE}" -C "${CONFIG_DIR}" . --exclude='home-assistant_v2.db*' --exclude='.storage' --exclude='*.log'

# Удаляем старые
find "${BACKUP_DIR}" -name 'ha-config-*.tar.gz' -mtime +${RETENTION_DAYS} -delete

# Пушим на удалённый (пример с rclone к S3)
rclone copy "${BACKUP_DIR}" "s3:my-bucket/ha-backups" --max-age 24h

Сделайте исполняемым: chmod +x /etc/cron.daily/ha-backup.

Предсказуемость — вот что даёт этот подход. Вы всегда знаете, где конфиг, как его вернуть, и почему он такой.

Часто задаваемые вопросы

Почему стоит выбрать Home Assistant Container, а не HA OS или Supervised?

Home Assistant Container удобен, если сервер уже работает под Linux и вы хотите управлять обновлениями, ресурсами и соседними сервисами через Docker Compose. HA OS и Supervised удобнее, когда нужны аддоны и управляемый жизненный цикл, но они требуют поддерживаемой платформы и не дают того же контроля над Docker-контейнерами. В Container аддоны не работают, поэтому Mosquitto, Zigbee2MQTT, ESPHome и базы данных запускаются отдельными контейнерами.

Зачем Home Assistant нужна сеть host и когда её можно заменить на обычную Docker-сеть?

Для обнаружения локальных устройств Home Assistant обычно нужен доступ к широковещательным и multicast-пакетам, поэтому режим network_mode: host упрощает работу mDNS, SSDP и UPnP. В режиме host контейнер использует сетевые интерфейсы узла напрямую, а не получает отдельный адрес в Docker-сети. Плата за это — отсутствие сетевой изоляции и риск конфликтов: Home Assistant слушает порты непосредственно на хосте, поэтому перед запуском проверьте, что они свободны. Если устройства находятся в другом VLAN, одного режима host недостаточно: понадобятся правила брандмауэра, маршрутизация multicast и IGMP.

Как подключить Zigbee-координатор, чтобы он не исчез после перезагрузки?

Сначала определите путь к координатору на хосте, например командой ls -l /dev/serial/by-id/, и передайте контейнеру Zigbee2MQTT именно этот стабильный путь через секцию devices в compose.yaml. Не задавайте /dev/ttyUSB0 как единственный идентификатор: после перезагрузки или отключения USB-устройства номера могут измениться. Затем укажите путь внутри контейнера в конфигурации Zigbee2MQTT и проверьте, что координатор появился в списке устройств. Если порт не появился, проверьте права доступа процесса контейнера к этому устройству.

Где хранятся настройки Home Assistant и как сделать резервную копию?

В режиме Container каталог /config должен быть смонтирован в именованный том Docker или в каталог на хосте, иначе настройки исчезнут после удаления контейнера. В compose.yaml заранее зафиксируйте путь и права доступа, а также регулярно сохраняйте копии /config: в нём находятся configuration.yaml, каталог .storage, секреты и база Recorder. Для согласованной резервной копии на уровне файлов остановите контейнер командой docker compose stop homeassistant, если сервис называется именно так, затем скопируйте каталог и запустите контейнер обратно. Конфигурации отдельных сервисов — Zigbee2MQTT, Mosquitto, Grafana и PostgreSQL — копируйте отдельно, а восстановление обязательно проверяйте на тестовом сервере.

Как обновлять Home Assistant предсказуемо и что делать при регрессии?

Для предсказуемого обновления сначала прочитайте примечания к релизу, зафиксируйте текущий тег образа и сделайте резервную копию. Тег stable удобен для первого запуска, но может смениться без изменения compose.yaml; в рабочем окружении лучше использовать конкретный релизный тег или digest. После проверки обновления выполните docker compose pull homeassistant и docker compose up -d homeassistant, затем проверьте docker compose logs --tail=200 homeassistant, состояние интеграций и доступность устройств. Если новая версия ломает сценарий, верните предыдущий тег и повторите эти команды, учитывая, что миграции конфигурации или базы данных могут сделать откат неполным.

Поделиться:TelegramX / TwitterVK