Пост

Установка и настройка 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.

Добавление интеграции ntfy в Home Assistant

После добавления интеграции в 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, решение работает стабильно и не требует постоянного вмешательства.

Авторский пост защищен лицензией CC BY 4.0 .

© evdokimoff. Некоторые права защищены.

Использует тему Chirpy для Jekyll