Установка и настройка ntfy на Raspberry Pi Zero 2W с Nginx, Home Assistant и защитой доступа
Собственный сервис push-уведомлений удобен, когда не хочется зависеть от публичных платформ. В статье описан практический сценарий развёртывания ntfy на Raspberry Pi Zero 2W. Архитектура выглядит так: ntfy запущен на Raspberry Pi во внутренней сети, отдельный сервер с Nginx принимает внешние HTTPS-запросы, завершает TLS и проксирует их на ntfy; Home Assistant публикует уведомления о событиях умного дома через этот HTTPS-эндпоинт. Все чувствительные данные заменены условными значениями, а команды проверены на актуальных версиях Raspberry Pi OS и Docker Engine.
Установка и настройка ntfy на Raspberry Pi Zero 2W с Nginx, Home Assistant и защитой доступа
Введение
Собственный сервис push-уведомлений удобен, когда не хочется зависеть от публичных платформ. В статье описан практический сценарий развёртывания ntfy на Raspberry Pi Zero 2W. Архитектура выглядит так: ntfy запущен на Raspberry Pi во внутренней сети, отдельный сервер с Nginx принимает внешние HTTPS-запросы, завершает TLS и проксирует их на ntfy; Home Assistant публикует уведомления о событиях умного дома через этот HTTPS-эндпоинт. Все чувствительные данные заменены условными значениями, а команды проверены на актуальных версиях Raspberry Pi OS и Docker Engine.
Рекомендации
Перед началом зарезервируйте IP-адрес Raspberry Pi на роутере по MAC-адресу. Это избавит от ситуации, когда после перезагрузки Pi получает другой адрес и Nginx перестаёт достучаться до ntfy. Также заранее убедитесь, что на Nginx уже работает Certbot и есть возможность добавить новый поддомен. Если в локальной сети есть Android-устройства, приготовьтесь к отдельной настройке DNS: Android часто игнорирует локальный DNS-сервер и использует публичные резолверы.
Архитектура решения
Схема выглядит так: интернет → шлюз с пробросом 443 → Nginx (192.168.1.10) → Raspberry Pi (192.168.1.100, порт 2586). Nginx принимает HTTPS-трафик, завершает TLS и проксирует запросы на ntfy. Публичная A-запись поддомена указывает на внешний IP шлюза. В локальной сети удобно настроить split DNS: чтобы домен резолвился во внутренний IP Nginx, а не уходил через внешний шлюз и не создавал петлю.
Предварительные требования
Понадобятся: контролируемый домен, возможность добавлять поддомены, шлюз с пробросом 443 на Nginx, настроенный Nginx с Certbot, Raspberry Pi Zero 2W с PoE, установленный Docker и Docker Compose, а также зарезервированный IP для Raspberry Pi. Все команды ниже выполняются на Raspberry Pi, если не указано иное.
Установка Docker на Raspberry Pi
Установите Docker и плагин Compose:
1
2
3
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo apt-get install -y docker-compose-plugin
Добавьте текущего пользователя в группу docker, чтобы не использовать sudo для каждой команды:
1
sudo usermod -aG docker $USER
После этого перезайдите в систему или перезагрузите Raspberry Pi. Проверьте, что Docker работает без sudo:
1
docker ps
Подготовка конфигурации ntfy
Создайте каталоги для конфигурации и кэша:
1
2
mkdir -p ~/ntfy/config ~/ntfy/cache
cd ~/ntfy
Создайте файл docker-compose.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
services:
ntfy:
image: binwiederhier/ntfy:latest
container_name: ntfy
command: serve
environment:
- TZ=Europe/Moscow
volumes:
- ./cache:/var/cache/ntfy
- ./config:/etc/ntfy
ports:
- "192.168.1.100:2586:80"
restart: unless-stopped
Замените 192.168.1.100 на фактический IP Raspberry Pi. Порт привязан к конкретному интерфейсу, чтобы ntfy не был доступен на других адресах.
Создайте файл config/server.yml:
1
2
3
4
5
6
7
8
9
10
11
base-url: "https://ntfy.example.com"
listen-http: ":80"
cache-file: "/var/cache/ntfy/cache.db"
cache-duration: "24h"
behind-proxy: true
auth-file: "/var/cache/ntfy/auth.db"
auth-default-access: "deny-all"
enable-signup: false
attachment-cache-dir: "/var/cache/ntfy/attachments"
attachment-total-size-limit: "1G"
attachment-file-size-limit: "15M"
Параметр behind-proxy: true обязателен, так как перед ntfy стоит Nginx. auth-default-access: "deny-all" закрывает анонимный доступ, а enable-signup: false запрещает самостоятельную регистрацию.
Запуск ntfy
Запустите контейнер:
1
docker compose up -d
Проверьте, что сервис отвечает:
1
curl http://192.168.1.100:2586/v1/health
Ожидаемый ответ: {"healthy":true}. Если сразу после запуска команда возвращает ошибку соединения, подождите несколько секунд и повторите: контейнеру нужно время на старт.
Создание пользователей и прав
Создайте администратора:
1
docker exec -it ntfy ntfy user add --role=admin admin
Команда запросит пароль дважды. Если пользователь уже создан без пароля, смените его:
1
docker exec -it ntfy ntfy user change-pass admin
Создайте обычного пользователя:
1
docker exec -it ntfy ntfy user add user1
Выдайте ему доступ к нужному топику. Например, только чтение:
1
docker exec -it ntfy ntfy access user1 home_alerts ro
Или чтение и запись:
1
docker exec -it ntfy ntfy access user1 home_alerts rw
Проверьте список пользователей и прав:
1
docker exec -it ntfy ntfy user list
Настройка Nginx как обратного прокси
На сервере Nginx создайте файл /etc/nginx/sites-available/ntfy.example.com:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server {
listen 80;
server_name ntfy.example.com;
location / {
proxy_pass http://192.168.1.100:2586;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 3m;
proxy_send_timeout 3m;
proxy_read_timeout 3m;
client_max_body_size 20m;
proxy_buffering off;
proxy_request_buffering off;
}
}
Активируйте сайт и перезагрузите Nginx:
1
2
3
sudo ln -s /etc/nginx/sites-available/ntfy.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Выпуск SSL-сертификата
Убедитесь, что DNS-запись поддомена уже резолвится в внешний IP:
1
dig +short ntfy.example.com
Затем выпустите сертификат через Certbot:
1
sudo certbot --nginx -d ntfy.example.com
Certbot сам добавит в конфиг блок listen 443 ssl, пути к сертификатам и, при необходимости, редирект с HTTP на HTTPS. После завершения проверьте:
1
2
sudo nginx -t
curl https://ntfy.example.com/v1/health
Настройка Home Assistant
В Home Assistant добавьте интеграцию ntfy. Перейдите в «Настройки → Устройства и службы → Добавить интеграцию» и выберите ntfy. Укажите URL сервера https://ntfy.example.com, логин и пароль пользователя, а также топик, например home_alerts.
После добавления интеграции в Home Assistant появится notify-сущность. Точное имя можно посмотреть в «Инструменты разработчика → Состояния», отфильтровав по notify.. Обычно это notify.home_alerts или похожее.
Автоматизация уведомления при открытии двери
Ниже пример автоматизации, которая срабатывает при открытии двери через событие zha_event. Замените binary_sensor.door_sensor и notify.home_alerts на свои значения.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- alias: Уведомление — дверь открыта
description: ""
trigger:
- platform: event
event_type: zha_event
condition:
- condition: template
value_template: ""
- condition: template
value_template: ""
- condition: template
value_template: ""
- condition: template
value_template: ""
action:
- service: notify.send_message
target:
entity_id: notify.home_alerts
data:
title: "Умный дом"
message: "Открыта дверь"
mode: single
Если используется сервис ntfy.publish, в некоторых версиях интеграции требуется явно указать target. В таком случае используйте:
1
2
3
4
5
6
7
8
9
10
11
12
action:
- service: ntfy.publish
target:
entity_id: notify.home_alerts
data:
topic: home_alerts
title: "Умный дом"
message: "Открыта дверь"
priority: 4
tags:
- warning
- door
После сохранения автоматизации откройте дверь. Уведомление должно прийти на устройство, подписанное на топик home_alerts.
Типичные проблемы и решения
Проблема: permission denied while trying to connect to the Docker API. Пользователь не входит в группу docker. Выполните sudo usermod -aG docker $USER, затем перезайдите в систему или перезагрузите Raspberry Pi.
Проблема: curl: (7) Failed to connect сразу после docker compose up -d. Контейнер ещё не успел запуститься. Подождите несколько секунд и повторите проверку. Убедитесь, что порт в docker-compose.yml привязан к правильному IP.
Проблема: Android и HyperOS не видят локальный домен, хотя Mac или Linux резолвят его нормально. Отключите «Частный DNS» в настройках Android. Если не помогает, используйте приложение Intra или аналогичное, чтобы принудительно направлять DNS-запросы на локальный сервер.
Проблема: nginx: [emerg] cannot load certificate ... No such file or directory. Сертификат ещё не выпущен, а конфиг уже содержит SSL. Сначала создайте только HTTP-блок, перезагрузите Nginx, затем выполните certbot --nginx -d ntfy.example.com.
Проблема: conflicting server name ... on 0.0.0.0:443, ignored. В конфигурации Nginx есть дублирующиеся server-блоки с одинаковым server_name. Найдите их через grep -rn "server_name" /etc/nginx/ и удалите или закомментируйте лишний блок.
Проблема: Home Assistant пишет «Цель не задана» в действии ntfy. В редакторе автоматизации выберите notify-сущность в поле «Цель». Если используется YAML, укажите target: entity_id: notify.home_alerts.
Проблема: Home Assistant пишет «использует неизвестное действие: ntfy.send_message». Такого сервиса нет. Используйте notify.send_message или ntfy.publish с target.
Проблема: Error loading /config/configuration.yaml: while parsing a block collection. Ошибка отступов в YAML. Если автоматизация добавляется в файл со списком, она должна начинаться с - alias:, а все вложенные ключи должны иметь отступ в 2 пробела. Проверьте проблемные строки и выровняйте структуру.
Проблема: {"code":40101,"http":401,"error":"unauthorized"} при отправке через curl. Убедитесь, что подставляете реальный пароль, а не placeholder. Проверьте права пользователя на топик командой docker exec -it ntfy ntfy user list.
Заключение
Связка Raspberry Pi Zero 2W, ntfy, Nginx и Home Assistant получается лёгкой, предсказуемой и полностью контролируемой. Nginx берёт на себя TLS и внешний доступ, ntfy остаётся внутри сети, а Home Assistant отправляет уведомления через обычную автоматизацию. Если сразу учесть DNS-особенности Android, зарезервировать IP и правильно оформить YAML, решение работает стабильно и не требует постоянного вмешательства.
