Эта статья — не пересказ документации Docker на 800 страниц. Это конкретное руководство: как поставить Docker на домашний сервер, как запустить первые контейнеры, как описать инфраструктуру умного дома в одном файле и как не потерять данные при обновлении. Минимум теории, максимум практики.
Если вы никогда не работали с Docker — начните здесь. Если уже запускали пару контейнеров — переходите к разделу про Docker Compose.
Docker работает на Linux, macOS и Windows. Для домашнего сервера умного дома — Linux. Рекомендуемые дистрибутивы: Debian 12, Ubuntu 22.04/24.04. Подойдёт и любой другой с ядром 4.x и выше.
Минимальное железо: 1 ГБ оперативной памяти (для Docker + пара контейнеров), 10 ГБ свободного места на диске. На практике — 2–4 ГБ RAM и SSD дадут комфортную работу.
Откройте терминал (SSH или локально) и выполните команды:
bash# Обновляем систему
sudo apt update && sudo apt upgrade -y
# Устанавливаем необходимые пакеты
sudo apt install -y ca-certificates curl gnupg
# Добавляем GPG-ключ Docker
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
Для Debian:
bashecho "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian $(. /etc/os-release && echo $VERSION_CODENAME) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
Для Ubuntu — замените debian на ubuntu в URL.
Теперь ставим Docker:
bashsudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
bashsudo docker run hello-world
Если увидели сообщение «Hello from Docker!» — всё работает.
По умолчанию Docker требует sudo для каждой команды. Чтобы не писать sudo каждый раз:
bashsudo usermod -aG docker $USER
Выйдите из терминала и зайдите снова (или перезагрузите сервер). После этого docker будет работать без sudo.
Проверьте:
bashdocker ps
Если команда выполнилась без ошибок и показала пустую таблицу — готово.
bashdocker run -d --name mosquitto eclipse-mosquitto:2
Разберём по частям:
docker run — создать и запустить контейнер-d — в фоне (detached), без привязки к терминалу--name mosquitto — имя контейнера (для удобства обращения)eclipse-mosquitto:2 — образ и тег (версия)Docker скачает образ (если его ещё нет локально), создаст контейнер и запустит его.
bashdocker ps
Покажет все работающие контейнеры: имя, образ, порты, время работы.
bashdocker ps -a
Покажет все контейнеры, включая остановленные.
bashdocker stop mosquitto # остановить
docker start mosquitto # запустить снова
docker restart mosquitto # перезапустить
bashdocker logs mosquitto # показать все логи
docker logs -f mosquitto # следить за логами в реальном времени (Ctrl+C для выхода)
docker logs --tail 50 mosquitto # последние 50 строк
bashdocker stop mosquitto # сначала остановить
docker rm mosquitto # потом удалить
Или одной командой:
bashdocker rm -f mosquitto # принудительно остановить и удалить
Удаление контейнера не удаляет образ. Образ остаётся на диске.
bashdocker images # список образов
docker rmi eclipse-mosquitto:2 # удалить конкретный образ
docker image prune # удалить неиспользуемые образы
Контейнер изолирован от хоста. Чтобы сервис внутри контейнера был доступен снаружи, нужно пробросить порт:
bashdocker run -d --name mosquitto -p 1883:1883 eclipse-mosquitto:2
-p 1883:1883 означает: порт 1883 на хосте → порт 1883 в контейнере. Теперь Mosquitto доступен по адресу IP-сервера:1883.
Формат: -p <порт-хоста>:<порт-контейнера>. Порты не обязаны совпадать: -p 9883:1883 откроет Mosquitto на порту 9883 хоста.
Данные внутри контейнера исчезают при его удалении. Чтобы сохранить конфигурацию и данные, монтируем директорию хоста внутрь контейнера:
bashmkdir -p /opt/mosquitto/config
mkdir -p /opt/mosquitto/data
docker run -d --name mosquitto \
-p 1883:1883 \
-v /opt/mosquitto/config:/mosquitto/config \
-v /opt/mosquitto/data:/mosquitto/data \
eclipse-mosquitto:2
-v /opt/mosquitto/config:/mosquitto/config — директория /opt/mosquitto/config на хосте доступна внутри контейнера как /mosquitto/config. Всё, что контейнер пишет в /mosquitto/config, на самом деле сохраняется на хосте. Удалили контейнер, создали заново — данные на месте.
Многие контейнеры настраиваются через переменные окружения:
bashdocker run -d --name influxdb \
-p 8086:8086 \
-e DOCKER_INFLUXDB_INIT_MODE=setup \
-e DOCKER_INFLUXDB_INIT_USERNAME=admin \
-e DOCKER_INFLUXDB_INIT_PASSWORD=supersecret \
-e DOCKER_INFLUXDB_INIT_ORG=home \
-e DOCKER_INFLUXDB_INIT_BUCKET=homeassistant \
-v /opt/influxdb/data:/var/lib/influxdb2 \
influxdb:2
-e задаёт переменную. Какие переменные поддерживает конкретный образ — описано в его документации на Docker Hub или GitHub.
bashdocker run -d --name mosquitto --restart unless-stopped eclipse-mosquitto:2
--restart unless-stopped — контейнер перезапускается автоматически при падении и при перезагрузке сервера. Не перезапускается, только если вы его остановили вручную командой docker stop.
Другие варианты: --restart always (перезапускать всегда), --restart on-failure (только при ошибке), --restart no (никогда).
Запускать каждый контейнер отдельной командой docker run с десятком параметров — неудобно. Docker Compose позволяет описать все контейнеры в одном YAML-файле и управлять ими одной командой.
Создайте директорию для проекта:
bashmkdir -p /opt/smarthome
cd /opt/smarthome
Создайте файл docker-compose.yml:
bashnano docker-compose.yml
Минимальный пример — Mosquitto:
yamlservices:
mosquitto:
image: eclipse-mosquitto:2
container_name: mosquitto
restart: unless-stopped
ports:
- "1883:1883"
volumes:
- ./mosquitto/config:/mosquitto/config
- ./mosquitto/data:/mosquitto/data
- ./mosquitto/log:/mosquitto/log
Сохраните (Ctrl+O, Enter, Ctrl+X в nano).
bashdocker compose up -d
Docker Compose скачает образ, создаст контейнер с указанными параметрами и запустит его. Флаг -d — в фоне.
Все команды выполняются из директории, где лежит docker-compose.yml.
bashdocker compose up -d # запустить все сервисы
docker compose down # остановить и удалить все контейнеры
docker compose stop # остановить (без удаления)
docker compose start # запустить остановленные
docker compose restart # перезапустить все
docker compose restart mosquitto # перезапустить один сервис
docker compose logs -f # логи всех сервисов
docker compose logs -f mosquitto # логи одного сервиса
docker compose ps # статус контейнеров
docker compose pull # скачать обновлённые образы
bashdocker compose pull # скачать новые версии образов
docker compose up -d # пересоздать контейнеры из новых образов
Данные в примонтированных директориях сохраняются. Обновляется только сам контейнер (код приложения, библиотеки). Конфигурация и данные — на месте.
Для отката на предыдущую версию — укажите конкретный тег в docker-compose.yml:
yamlimage: eclipse-mosquitto:2.0.18 # конкретная версия вместо "2" (последняя)
И выполните docker compose up -d.
Теперь — реальный пример. Файл docker-compose.yml, который поднимает базовую инфраструктуру: Mosquitto, Zigbee2MQTT и Home Assistant.
bashmkdir -p /opt/smarthome
cd /opt/smarthome
mkdir -p mosquitto/config mosquitto/data mosquitto/log
mkdir -p zigbee2mqtt/data
mkdir -p homeassistant/config
Создайте файл конфигурации:
bashnano mosquitto/config/mosquitto.conf
Содержимое:
listener 1883
persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log
allow_anonymous false
password_file /mosquitto/config/passwd
Сохраните. Теперь создайте файл паролей (пока пустой — заполним после первого запуска).
yamlservices:
mosquitto:
image: eclipse-mosquitto:2
container_name: mosquitto
restart: unless-stopped
ports:
- "1883:1883"
volumes:
- ./mosquitto/config:/mosquitto/config
- ./mosquitto/data:/mosquitto/data
- ./mosquitto/log:/mosquitto/log
zigbee2mqtt:
image: koenkk/zigbee2mqtt
container_name: zigbee2mqtt
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ./zigbee2mqtt/data:/app/data
devices:
- /dev/ttyUSB0:/dev/ttyUSB0
depends_on:
- mosquitto
homeassistant:
image: ghcr.io/home-assistant/home-assistant:stable
container_name: homeassistant
restart: unless-stopped
network_mode: host
volumes:
- ./homeassistant/config:/config
privileged: true
depends_on:
- mosquitto
mosquitto:
image: eclipse-mosquitto:2 — образ Mosquitto, последняя версия ветки 2.x.ports: "1883:1883" — MQTT-порт доступен из локальной сети.volumes — конфигурация, данные и логи хранятся на хосте.zigbee2mqtt:
image: koenkk/zigbee2mqtt — образ Zigbee2MQTT (latest).ports: "8080:8080" — веб-интерфейс Zigbee2MQTT.devices: /dev/ttyUSB0:/dev/ttyUSB0 — проброс USB-координатора (Sonoff ZBDongle, SMLIGHT и т.д.) внутрь контейнера. Путь может отличаться — проверьте командой ls /dev/ttyUSB* или ls /dev/ttyACM*.depends_on: mosquitto — Zigbee2MQTT стартует после Mosquitto.homeassistant:
image: ghcr.io/home-assistant/home-assistant:stable — стабильная версия Home Assistant.network_mode: host — контейнер использует сеть хоста напрямую. Нужно для mDNS-обнаружения устройств. При host-режиме ports не указывают — все порты контейнера и так доступны на хосте. Home Assistant будет на порту 8123.privileged: true — расширенные права. Нужно для доступа к оборудованию (Bluetooth, USB). Для продвинутых пользователей — можно ограничить конкретными capabilities, но для начала privileged работает.depends_on: mosquitto — стартует после Mosquitto.bashdocker compose up -d
Первый запуск — Docker скачает три образа (может занять несколько минут, зависит от скорости интернета). Затем создаст и запустит контейнеры.
После первого запуска Mosquitto создайте пользователя:
bashdocker exec -it mosquitto mosquitto_passwd -c /mosquitto/config/passwd homeassistant
Введите пароль. Добавьте ещё пользователей (без флага -c, чтобы не перезаписать файл):
bashdocker exec -it mosquitto mosquitto_passwd /mosquitto/config/passwd zigbee2mqtt
Перезапустите Mosquitto:
bashdocker compose restart mosquitto
http://IP-сервера:8123http://IP-сервера:8080Если всё открывается — поздравляю, базовая инфраструктура работает.
Инфраструктура растёт — добавляем сервисы в тот же docker-compose.yml.
Добавьте в раздел services::
yaml influxdb:
image: influxdb:2
container_name: influxdb
restart: unless-stopped
ports:
- "8086:8086"
volumes:
- ./influxdb/data:/var/lib/influxdb2
- ./influxdb/config:/etc/influxdb2
environment:
- DOCKER_INFLUXDB_INIT_MODE=setup
- DOCKER_INFLUXDB_INIT_USERNAME=admin
- DOCKER_INFLUXDB_INIT_PASSWORD=changeme123
- DOCKER_INFLUXDB_INIT_ORG=home
- DOCKER_INFLUXDB_INIT_BUCKET=homeassistant
grafana:
image: grafana/grafana
container_name: grafana
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- ./grafana/data:/var/lib/grafana
depends_on:
- influxdb
Создайте директории:
bashmkdir -p influxdb/data influxdb/config grafana/data
Запустите:
bashdocker compose up -d
Docker создаст только новые контейнеры — уже работающие не тронет.
http://IP-сервера:8086http://IP-сервера:3000 (логин: admin, пароль: admin — поменяйте при первом входе)yaml adguardhome:
image: adguard/adguardhome
container_name: adguardhome
restart: unless-stopped
ports:
- "53:53/tcp"
- "53:53/udp"
- "3003:3000/tcp"
volumes:
- ./adguardhome/work:/opt/adguardhome/work
- ./adguardhome/conf:/opt/adguardhome/conf
Порт 3003 на хосте (потому что 3000 уже занят Grafana) → порт 3000 внутри контейнера (веб-интерфейс AdGuard Home).
yaml npm:
image: jc21/nginx-proxy-manager:latest
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "81:81"
volumes:
- ./npm/data:/data
- ./npm/letsencrypt:/etc/letsencrypt
Веб-интерфейс: http://IP-сервера:81 (логин: admin@example.com, пароль: changeme — поменяйте сразу).
yaml portainer:
image: portainer/portainer-ce
container_name: portainer
restart: unless-stopped
ports:
- "9000:9000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./portainer/data:/data
/var/run/docker.sock — Docker-сокет, через который Portainer управляет контейнерами. Веб-интерфейс: http://IP-сервера:9000.
bashdocker compose ps
bashdocker stats
Реалтайм-таблица с CPU, RAM, сетевым трафиком. Ctrl+C для выхода.
Иногда нужно выполнить команду внутри контейнера — проверить файлы, запустить утилиту:
bashdocker exec -it mosquitto sh
Вы окажетесь внутри контейнера, в его файловой системе. exit — выход обратно на хост.
Для контейнеров на базе Debian/Ubuntu — вместо sh используйте bash.
Для Zigbee-координатора важно знать правильный путь:
bashls -la /dev/ttyUSB*
ls -la /dev/ttyACM*
Если координатор — единственное USB-устройство, обычно это /dev/ttyUSB0 или /dev/ttyACM0.
Для стабильности рекомендуется использовать путь по ID:
bashls -la /dev/serial/by-id/
Вывод будет вроде usb-Silicon_Labs_Sonoff_Zigbee_3.0_USB_Dongle_Plus_xxxx-if00-port0. Используйте этот путь в docker-compose.yml:
yamldevices:
- /dev/serial/by-id/usb-Silicon_Labs_Sonoff_Zigbee_3.0_USB_Dongle_Plus_xxxx-if00-port0:/dev/ttyACM0
Так координатор будет найден даже если порядок USB-устройств изменится после перезагрузки.
Со временем на диске накапливаются старые версии образов:
bashdocker image prune -a
Удалит все образы, которые не используются ни одним контейнером. Освобождает гигабайты.
bashdocker system prune -a
Более агрессивная очистка: неиспользуемые образы, остановленные контейнеры, неиспользуемые сети и кэш сборки.
С Docker резервное копирование — это два элемента.
docker-compose.yml — описание всей инфраструктуры.volumes.В нашем примере — это вся директория /opt/smarthome:
/opt/smarthome/
├── docker-compose.yml
├── mosquitto/
│ ├── config/
│ ├── data/
│ └── log/
├── zigbee2mqtt/
│ └── data/
├── homeassistant/
│ └── config/
├── influxdb/
│ ├── data/
│ └── config/
├── grafana/
│ └── data/
└── ...
bash# Остановить контейнеры (для консистентности)
cd /opt/smarthome
docker compose stop
# Создать архив
tar czf /backup/smarthome-$(date +%Y%m%d).tar.gz /opt/smarthome/
# Запустить обратно
docker compose start
Для InfluxDB и других баз данных остановка перед бэкапом — рекомендуется, чтобы не получить повреждённую копию. Для файлов конфигурации (Home Assistant, Zigbee2MQTT, Mosquitto) — можно копировать на ходу, но остановка надёжнее.
bashcrontab -e
Добавьте строку:
0 3 * * * cd /opt/smarthome && docker compose stop && tar czf /backup/smarthome-$(date +\%Y\%m\%d).tar.gz /opt/smarthome/ && docker compose start
Каждую ночь в 3:00 — остановка, бэкап, запуск. Контейнеры недоступны 1–5 минут.
tar xzf smarthome-20260305.tar.gz -C /cd /opt/smarthomedocker compose up -dВсё. Весь умный дом восстановлен на новом сервере.
Got permission denied while trying to connect to the Docker daemon socket
Вы не добавили пользователя в группу docker. Выполните sudo usermod -aG docker $USER и перелогиньтесь.
Смотрите логи:
bashdocker compose logs имя-сервиса
Частые причины: неверная конфигурация, отсутствующий файл, занятый порт.
Bind for 0.0.0.0:1883 failed: port is already allocated
Порт уже занят другим процессом или контейнером. Проверьте:
bashsudo lsof -i :1883
Или смените порт хоста в docker-compose.yml: "1884:1883".
Координатор не найден по указанному пути. Проверьте ls /dev/serial/by-id/, убедитесь что устройство подключено, и обновите путь в docker-compose.yml.
Все контейнеры в одном docker-compose.yml автоматически в одной сети. Обращайтесь по имени сервиса (не container_name, а имени из YAML). Исключение: контейнер с network_mode: host (Home Assistant) — он в сети хоста и обращается к другим контейнерам через localhost:порт или IP-хоста:порт.
Вы не примонтировали директорию. Всё, что не в volumes, живёт только внутри контейнера и исчезает при его удалении. Добавьте volumes для всех данных, которые должны сохраняться.
Откатитесь на предыдущую версию. В docker-compose.yml укажите конкретный тег:
yamlimage: koenkk/zigbee2mqtt:1.40.0 # вместо latest
И выполните docker compose up -d.
yaml# Плохо — непредсказуемо
image: koenkk/zigbee2mqtt
# Хорошо — предсказуемо
image: koenkk/zigbee2mqtt:1.42.0
Тег latest (используется по умолчанию, когда тег не указан) означает «последняя версия». Сегодня это 1.42.0, завтра — 1.43.0 с возможными несовместимостями. Для стабильности указывайте конкретную версию. Обновляйтесь осознанно, проверив changelog.
Исключение: Home Assistant (:stable) и Mosquitto (:2) — здесь мажорные версии стабильны, и тег ветки безопасен.
bashcd /opt/smarthome
git init
git add docker-compose.yml
git commit -m "Initial setup"
Каждое изменение — коммит. История изменений, возможность отката, понимание, что и когда менялось. Не добавляйте в Git файлы с паролями и токенами — используйте .gitignore или переменные окружения через файл .env.
Создайте файл .env рядом с docker-compose.yml:
MQTT_PASSWORD=supersecretpassword
INFLUXDB_PASSWORD=anothersecret
В docker-compose.yml:
yamlenvironment:
- DOCKER_INFLUXDB_INIT_PASSWORD=${INFLUXDB_PASSWORD}
Docker Compose автоматически подставит значения из .env. Добавьте .env в .gitignore, чтобы секреты не попали в Git.
Для домашнего сервера один файл — проще. Все сервисы в одной сети, одна команда для управления, один бэкап.
Если сервисов много (15+) и хочется группировать — можно разделить на несколько файлов в разных директориях. Но для начала — один файл на всё.
Docker установлен, базовая инфраструктура работает. Дальше — по потребностям:
docker-compose.yml с пробросом GPU/Coral.Каждый новый сервис — это ещё один блок в docker-compose.yml. Десять строк — и он работает. В этом сила Docker: вся инфраструктура умного дома описана в одном текстовом файле, который помещается на экран.
Статья подготовлена на основе официальной документации Docker и Docker Compose, а также практического опыта сообщества Home Assistant. Все команды проверены на Debian 12 и Ubuntu 24.04. Материал носит информационный характер и не является рекламой.