# CrowdSec + MikroTik. Часть 5 (бонус): алерты в телефон через ntfy

**URL:** <https://forum.samohosting.ru/t/crowdsec-mikrotik-chast-5-bonus-alerty-v-telefon-cherez-ntfy/2609>\
**Category:** Безопасность\
**Tags:** docker, mikrotik, crowdsec, homelab\
**Created:** [01.Июль.2026 07:11:36 UTC](https://forum.samohosting.ru/t/crowdsec-mikrotik-chast-5-bonus-alerty-v-telefon-cherez-ntfy/2609 "2026-07-01T07:11:36Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![RaineDev](https://forum.samohosting.ru/user_avatar/forum.samohosting.ru/rainedev/32/1979_2.png) [@RaineDev](https://forum.samohosting.ru/u/RaineDev)\
**Post date:** [01.Июль.2026 07:11:37 UTC](https://forum.samohosting.ru/t/crowdsec-mikrotik-chast-5-bonus-alerty-v-telefon-cherez-ntfy/2609/1 "2026-07-01T07:11:37Z")

</div>

# CrowdSec + MikroTik. Часть 5 (бонус): алерты в телефон через ntfy

> Предыдущие части: [Часть 1 — локальный детект и бан на роутере](https://forum.samohosting.ru/t/crowdsec-mikrotik-avtomaticheskij-ban-skanerov-pryamo-na-routere/2553), [Часть 2 — community-блоклист](https://forum.samohosting.ru/t/crowdsec-mikrotik-chast-2-podklyuchaem-community-bloklist-i-ne-lomaem-lokalnyj-detekt/2565), [Часть 3 — веб-детект через Traefik](https://forum.samohosting.ru/t/crowdsec-mikrotik-chast-3-lovim-veb-ataki-cherez-traefik/2573), [Часть 4 — Prometheus + Grafana](https://forum.samohosting.ru/t/crowdsec-mikrotik-chast-4-nablyudaemost-prometheus-grafana/2597). Здесь — как сделать так, чтобы важное **само прилетало в телефон** , а не ждало, пока вы откроете дашборд.

Графики из Части 4 — это прекрасно, но у них есть один изъян: в них надо **смотреть**. А самые неприятные вещи случаются ровно тогда, когда вы в дашборд не глядите: ночью молча умер детект (отвалился syslog-поток), CrowdSec забанил ваш же VPN-выход, роутер ушёл в ребут и потерял `address-list`. Хочется, чтобы про такое сообщали — пушем на телефон.

Я для этого использую **ntfy** — простой self-hosted сервис пуш-уведомлений: POST на топик → мгновенный пуш в приложение на телефоне. Здесь покажу, как навесить его на наш CrowdSec-конвейер.

> 🎁 Это бонус-часть: схема из Частей 1–4 работает и без неё. Но один раз настроив, ловить «детект умер» вы будете за минуты, а не наутро.  
> Также прикладываю ссылку на GitHub-репозиторий со всем кодом из цикла — для тех, кто хочет поднять всё быстро, без копипасты из статей: [GitHub - fenixvd/crowdsec-mikrotik-bouncer: Bounce CrowdSec decisions onto a MikroTik router — ban scanners & web attackers at the WAN edge via address-list (local + community + Traefik web detect) · GitHub](https://github.com/fenixvd/crowdsec-mikrotik-bouncer)

* * *

## Есть ли у вас уже ntfy?

### Да, ntfy уже крутится

Тогда из этой статьи вам нужны только **URL сервера, токен и имя топика** — и можно сразу прыгать в раздел «Хелпер для отправки». Свой топик под этот проект (напр. `security`) заведите, если хочется отделить безопасность от остальных уведомлений.

### Нет, ntfy ещё нет — два пути

**Путь 1. Публичный ntfy.sh (за 30 секунд, без своего сервера).** Просто шлёте на `https://ntfy.sh/любой-случайный-топик` и подписываетесь на него в приложении. Минус один, но важный: **топик = пароль**. Любой, кто его знает (или угадает), читает ваши уведомления. Для алертов про безопасность лучше:

- взять **длинное случайное** имя топика (`security-7f3k9x2m-…`), а не `myhomelab`;
- не писать в текст алерта чувствительного (IP своей инфры, токены) — в публичном канале это лишнее.

**Путь 2. Свой ntfy в Docker (рекомендую).** Полный контроль, приватность, авторизация. Минимальный `docker-compose.yml`:

```yaml
services:
  ntfy:
    image: binwiederhier/ntfy:latest
    container_name: ntfy
    command: serve
    restart: unless-stopped
    environment:
      NTFY_BASE_URL: "https://ntfy.example.com" # или http://SERVER_IP:8090 для LAN-only
      NTFY_AUTH_DEFAULT_ACCESS: "deny-all" # анонимам — 403, только по токену
      NTFY_BEHIND_PROXY: "true" # если за реверс-прокси
    volumes:
      - ./data:/var/lib/ntfy
    ports:
      - "SERVER_IP:8090:80" # в мир — только через реверс-прокси (Traefik из Части 3)

```

Заводим пользователя и токен для скриптов:

```bash
docker exec -it ntfy ntfy user add --role=admin myuser
docker exec -it ntfy ntfy token add myuser # -> tk_xxxxxxxx, его положим в скрипт

```

> Наружу ntfy лучше выставлять **через реверс-прокси** (тот же Traefik + CrowdSec из Части 3), а не публиковать порт напрямую. Тогда пуши приходят из любой сети, а на edge стоит защита. Кто не хочет светить наружу вообще — держите ntfy LAN/VPN-only, пуши будут приходить дома и под VPN.

* * *

## Хелпер для отправки

Чтобы не плодить длинные `curl` по скриптам, заведём один маленький хелпер. `ntfy-notify.sh`:

```bash
#!/usr/bin/env bash
# ntfy-notify.sh "Заголовок" "Текст" [приоритет] [теги]
# приоритет: min|low|default|high|urgent ; теги: warning,skull,rotating_light ...
set -euo pipefail

NTFY_URL="${NTFY_URL:-http://SERVER_IP:8090}" # ВАЖНО: см. грабли про hairpin-NAT
NTFY_TOPIC="${NTFY_TOPIC:-security}"
NTFY_TOKEN="${NTFY_TOKEN:-tk_ВСТАВЬТЕ_ТОКЕН}"

title="${1:?title}"; body="${2:?body}"; prio="${3:-default}"; tags="${4:-}"

curl -sf -X POST "${NTFY_URL}/${NTFY_TOPIC}" \
  -H "Authorization: Bearer ${NTFY_TOKEN}" \
  -H "Title: ${title}" \
  -H "Priority: ${prio}" \
  ${tags:+-H "Tags: ${tags}"} \
  --data-binary "${body}" >/dev/null

```

Секреты (`NTFY_TOKEN` и др.) держим **не в самом скрипте** , а в отдельном `notify.env` рядом (и в git его не коммитим / шифруем git-crypt). Проверка:

```bash
NTFY_TOKEN=tk_... ./ntfy-notify.sh "Тест" "CrowdSec на связи" default tada

```

* * *

## Что именно слать (триггеры по нашему конвейеру)

Не «всё подряд» — иначе уведомления превратятся в шум, который вы замьютите. Слать стоит то, что значит **«схема сломалась или происходит плохое»**. Вот мой набор по частям 1–4:

| Событие | Почему важно | Приоритет |
| --- | --- | --- |
| Поток syslog от роутера упал в 0 на N минут | Детект **умер** (отвалился лог/ротация/роутер) — баны перестали появляться, а атаки идут | `urgent` |
| Забанен IP **своей** инфры | CrowdSec прихлопнул ваш VPN-выход/CDN/пир — вы сами себе отрубили доступ | `urgent` |
| Резкий всплеск новых банов | Идёт активная атака/скан — полезно знать, что началось | `high` |
| Роутер недоступен по API | Баунсер не может разложить баны — `address-list` не обновляется | `high` |
| Память CrowdSec выше порога | На слабой машинке после community-листа можно словить OOM | `default` |
| CrowdSec/баунсер контейнер упал | Очевидно | `urgent` |

Ниже — две стратегии доставки. Выбирайте по тому, что у вас уже есть.

* * *

## Стратегия A: скрипт по таймеру (без Alertmanager)

Если городить Prometheus Alertmanager не хочется — простой скрипт + systemd-таймер. Он спрашивает `cscli`/PromQL и дёргает наш хелпер. Пример проверки «детект жив» и «не забанили ли своих»:

```bash
#!/usr/bin/env bash
# crowdsec-watch.sh — гоняется systemd-таймером раз в ~5 мин
set -euo pipefail
NOTIFY=/path/to/ntfy-notify.sh
STATE=/var/lib/crowdsec-watch ; mkdir -p "$STATE"

# 1) Детект жив? Спрашиваем Prometheus: были ли строки syslog за 10 минут.
# (если Prometheus нет — можно считать строки в /var/log/mikrotik.log за период)
q='sum(increase(cs_syslogsource_hits_total[10m]))'
hits=$(curl -sf "http://SERVER_IP:9090/api/v1/query?query=${q}" \
        | grep -oE '"value":\[[0-9.]+,"[0-9.]+"' | grep -oE '"[0-9.]+"$' | tr -d '"' || echo 0)
if awk "BEGIN{exit !($hits==0)}"; then
  # шлём только при СМЕНЕ состояния (см. дедуп ниже)
  [-f "$STATE/syslog_dead"] || "$NOTIFY" "CrowdSec: детект умер" \
     "Нет строк syslog от роутера за 10 мин. Проверь rsyslog/ротацию/роутер." urgent rotating_light
  touch "$STATE/syslog_dead"
else
  [-f "$STATE/syslog_dead"] && "$NOTIFY" "CrowdSec: детект восстановлен" "syslog снова идёт" default white_check_mark
  rm -f "$STATE/syslog_dead"
fi

# 2) Не забанили ли СВОИХ? known-IP берём динамически из вайтлиста (Часть 1, грабли №3)
known=$(grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' /path/to/cfg/parsers/s02-enrich/my-whitelist.yaml || true)
banned=$(docker exec crowdsec cscli decisions list -o json --limit 0 \
         | grep -oE '"value":"[0-9.]+"' | grep -oE '[0-9.]+' || true)
for ip in $known; do
  if grep -qx "$ip" <<<"$banned"; then
    "$NOTIFY" "CrowdSec: самобан!" "Своя инфра в бане: $ip — снимай: cscli decisions delete --ip $ip" urgent skull
  fi
done

```

systemd-таймер:

```ini
# /etc/systemd/system/crowdsec-watch.timer
[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
[Install]
WantedBy=timers.target

```

И ещё один бесплатный приём: **уведомление при падении любого юнита** через `OnFailure`. Вешаете на CrowdSec/баунсер/таймеры drop-in:

```ini
# ~/.config/systemd/.../override или системный drop-in
[Unit]
OnFailure=ntfy-failure@%n.service

```

где `ntfy-failure@.service` просто зовёт хелпер с именем упавшего юнита (`%i`). Тогда любой краш сам стучится в телефон без отдельной логики.

* * *

## Стратегия B: через Grafana (если она у вас из Части 4)

Подняли Grafana — у неё есть встроенный **Alerting** , и ntfy подключается как **contact point** типа Webhook. Это удобно: правила живут рядом с графиками.

1. **Contact point** (Alerting → Contact points → Add):

2. **Alert rule** — например на тот же «детект умер»:

Аналогично заводятся правила на `cs_active_decisions` (всплеск), `process_resident_memory_bytes{job="crowdsec"}` (память), отсутствие таргета (`up{job="crowdsec"} == 0`).

> Что выбрать? Нет Grafana или хотите минимум зависимостей — **Стратегия A** (скрипт + таймер). Уже живёте в Grafana и любите правила в UI — **Стратегия B**. Я у себя совмещаю: критичное про инфру шлёт самописный монитор по таймеру (стратегия A — он же проверяет вещи вне Prometheus), а пороговые графики — Grafana.

* * *

## Грабли и заметки

1. **Hairpin-NAT: с самого сервера шлите по ЛОКАЛЬНОМУ адресу.** Классическая засада: ntfy наружу живёт на `https://ntfy.example.com`, но скрипт на том же сервере, дёргая этот FQDN, упирается в собственный WAN — а NAT-hairpin на роутере часто выключен, и пуш молча не уходит. Решение: в `notify.env` для серверных скриптов укажите **внутренний** адрес (`http://SERVER_IP:8090`). Токен работает и по HTTP в LAN.

2. **Шлите только при СМЕНЕ состояния + «восстановлено».** Если слать алерт каждые 5 минут, пока проблема жива, — вы его замьютите и пропустите следующий. Храните флажок в `/var/lib/...` и пушите один раз на вход в проблему и один раз на выход (как в скрипте выше).

3. **Приоритеты и теги — не для красоты.** `urgent` на Android пробивает Do-Not-Disturb, `min` приходит тихо. Самобан своей инфры и смерть детекта — `urgent`; «началась атака» — `high`; рутина — `default`/`low`. Теги (`rotating_light`, `skull`, `white_check_mark`) превращаются в эмодзи — мгновенно видно глазами, что прилетело.

4. **Не кладите токен в скрипт/в git.** Только `notify.env` рядом, зашифрованный (git-crypt/SOPS) или просто в `.gitignore`. В публичный топик ntfy.sh не пишите IP своей инфры.

5. **Проверьте доставку «вживую».** Один раз искусственно уроните условие (остановите rsyslog на минуту) и убедитесь, что пуш дошёл. Молчащий алертинг хуже отсутствующего — он создаёт ложное чувство защищённости.

* * *

## Вместо эпилога

Вот и всё. За пять частей мы прошли путь от одной строчки в логе файрвола до системы, которая сама ловит, банит и докладывает:

```auto
лог на краю сети → детект → бан на роутере → глобальная репутация
        → веб-атаки → графики → пуш в телефон

```

Красота ведь в том, что хорошая защита — это тишина.

Но самое ценное — это не конкретные конфиги, а **подход**. CrowdSec детектит, баунсер исполняет, роутер режет, ntfy будит — каждый кубик заменяем и до-страиваем. Захотите добавить новый источник логов, ещё один список, свой сценарий, второй роутер, алерт в Telegram вместо ntfy — каркас выдержит. Это не готовая «коробка», которую страшно трогать, а конструктор, который растёт вместе с вами. Так что дальше — только ваша фантазия и руки)

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

---

<div class="post-metadata">

**Author:** ![Mysurik](https://forum.samohosting.ru/letter_avatar_proxy/v4/letter/m/258eb7/32.png) [@Mysurik](https://forum.samohosting.ru/u/Mysurik)\
**Post date:** [01.Июль.2026 14:15:21 UTC](https://forum.samohosting.ru/t/crowdsec-mikrotik-chast-5-bonus-alerty-v-telefon-cherez-ntfy/2609/2 "2026-07-01T14:15:21Z")

</div>

Спасибо за подробную статью! Я тоже через ntfy забираю алерты из Grafana — самое то для домашнего сервера, где нет круглосуточного дежурного. С вебхуками дружит из коробки, настройка контакт-поинта занимает минуту.

Интересно, кто-то пробовал гонять через ntfy не только критические алерты, но и ежедневные отчёты — состояние zpool, нагрузку CPU, лог ротацию? У меня пока только важное летит, но думаю расширить. Не превратится ли в спам?

---

<div class="post-metadata">

**Author:** ![RaineDev](https://forum.samohosting.ru/user_avatar/forum.samohosting.ru/rainedev/32/1979_2.png) [@RaineDev](https://forum.samohosting.ru/u/RaineDev)\
**Post date:** [02.Июль.2026 06:49:12 UTC](https://forum.samohosting.ru/t/crowdsec-mikrotik-chast-5-bonus-alerty-v-telefon-cherez-ntfy/2609/3 "2026-07-02T06:49:12Z")

</div>

> [@Mysurik](#):
>
> Не превратится ли в спам?

Если использовать в уведомлениях state файлик как я писал в статье то не должно спамить, по крайней мере у меня не спамит, присылает исключительно то что меняет свой статус)
