Skip to content

Исходящие webhook ​

Remnawave Admin умеет отправлять свои события на любой HTTP-адрес. Подписка выбирает набор событий, подходящие уходят подписанным JSON-запросом.

Не путайте с входящим webhook от панели Remnawave — там события приходят к нам.

Понятия ​

Подписка — адрес плюс список событий плюс настройки подписи. Их может быть сколько угодно.

Доставка — одна попытка HTTP-запроса. Все попытки видны в истории доставок.

Очередь повторов — неудачные доставки повторяются автоматически, после исчерпания попыток нужен ручной повтор: у каждой доставки в истории хранится тело события, и кнопка «Повторить» отправляет его заново со свежей подписью. У доставок, записанных до 5.0.0, тела нет — их не повторить. Историю можно фильтровать по событию и результату.

Создание подписки ​

API и вебхуки → Вебхуки → Создать:

  • Имя — метка вроде slack-ops-channel
  • URL — начинается с http:// или https://; приватные и локальные адреса по умолчанию отклоняются, см. ниже
  • Секрет — не обязателен, но нужен: он служит ключом подписи
  • Версия подписи — v2 по умолчанию, с меткой времени и защитой от повторной отправки; v1 оставлен для совместимости
  • События — одно или несколько
  • Описание — по желанию

Подписка начинает работать сразу. Кнопка Отправить тест пошлёт синтетический запрос — удобно убедиться, что адрес вообще отвечает.

Формат доставки ​

POST <ваш адрес>
Content-Type: application/json
X-Webhook-Event: <имя события>
X-Webhook-Signature: sha256=<hex>
X-Webhook-Timestamp: <unix-время>       # только v2
X-Webhook-Signature-Version: v2          # только v2
json
{
  "event": "user.created",
  "data": {
    "uuid": "...",
    "username": "alice"
  }
}

Содержимое data по каждому событию — в каталоге.

Подпись ​

Тело запроса подписывается вашим секретом по HMAC-SHA256.

ВерсияЧто подписывается
v1HMAC(секрет, тело)
v2HMAC(секрет, "<timestamp>.<тело>")

Метка времени приходит в X-Webhook-Timestamp. Принимающей стороне стоит отклонять запросы, где она отличается от текущего времени больше чем на пять минут: это защита от повторной отправки перехваченного запроса.

Примеры приёмников на Python, Node, Go и PHP — в разделе Проверка подписи.

Повторы ​

Первая попытка идёт сразу, вместе с исходным событием, с таймаутом 10 секунд. Если она не удалась — сетевая ошибка или ответ 4xx/5xx — доставка ставится в очередь.

Повторов ещё два, с нарастающей паузой: минута, пять минут, двадцать пять минут. Каждая попытка попадает в историю.

Автоотключение ​

Когда подряд накапливается 50 неудач (WEBHOOK_AUTO_DISABLE_AFTER), подписка отключается сама, и в интерфейсе появляется отметка с причиной. Обратное включение обнуляет счётчик.

Защита от SSRF ​

Адрес проверяется при создании, изменении, тесте и каждой отправке:

  • схема только http или https
  • имя хоста резолвится, и результат сверяется с приватными диапазонами: RFC-1918, 127.0.0.0/8, 169.254.0.0/16, ::1, fc00::/7, fe80::/10

Адрес, который указывает внутрь, отклоняется с 400. Обойти можно только осознанно и только для разработки:

bash
WEBHOOK_ALLOW_PRIVATE_URL=1

История доставок ​

Иконка часов рядом с подпиской показывает последние 200 попыток: код ответа (или ERR, если до ответа не дошло), событие, время, длительность, тело ответа до 5000 символов и текст ошибки. Тестовые доставки в историю не пишутся.

Переменные ​

ПеременнаяПо умолчаниюЧто задаёт
WEBHOOK_TIMEOUT_SEC10таймаут одной попытки
WEBHOOK_MAX_ATTEMPTS3попыток всего, включая первую
WEBHOOK_AUTO_DISABLE_AFTER50неудач подряд до автоотключения
WEBHOOK_RETRY_WORKER_INTERVAL10как часто просыпается фоновая отправка, секунды
WEBHOOK_ALLOW_PRIVATE_URL01 отключает проверку адреса

Меняются с перезапуском бэкенда.

Если что-то не так ​

Появилась отметка «отключён автоматически». Приёмник отвечал ошибками 50 раз подряд. Почините его и включите подписку обратно — счётчик обнулится.

История пустая. Либо подходящих событий ещё не было, либо до приёмника не доходит даже соединение — тогда запись не создаётся.

Подпись не сходится. Чаще всего причина одна из трёх: используется старый секрет; тело пересобрано перед проверкой (подписывается ровно то, что пришло); подпись проверяется по v1, а подписка на v2.

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

AGPL-3.0 с исключением для плагинов