跳到主要内容

Webhook

Webhook 让面板主动把发生的事情告知外部系统: 创建了用户、节点宕机、流量耗尽。面板会向你 的地址发送带有 JSON 请求体的 POST 请求,因此接收方可以是脚本、CRM、 监控系统或聊天机器人。

启用​

Webhook 默认关闭。设置位于面板的 .env 中:

变量默认值说明
WEBHOOK_ENABLEDfalse启用 Webhook 发送
WEBHOOK_URL—接收方地址;多个地址用逗号分隔
WEBHOOK_SECRET_HEADER—payload 签名密钥,正好 64 个 [a-zA-Z0-9] 字符
WEBHOOK_ENABLED=true
WEBHOOK_URL=https://example.com/xlada/webhook
WEBHOOK_SECRET_HEADER=vsmu67Kmg6R8FjIOF1WUY8LWBHie4scdEqrfsKmyf4IAf8dY3nFS0wwYHkhh6ZvQ
注意

当 WEBHOOK_ENABLED=true 时,两个变量都是必填的。WEBHOOK_URL 必须 以 http:// 或 https:// 开头,否则容器无法启动。签名 密钥只保存在 .env 中——接收方用它校验请求的 真实性。

发送哪些事件由容器内的 /var/lib/remnawave/configs/notifications/notifications-config.yml 文件决定。默认情况下, 镜像中两个通道的所有事件都已启用。 文件中没有的事件视为已关闭。为了让修改 得以保留,请把你的文件挂载到 /var/lib/remnawave/configs/notifications 目录之上。

events:
user.created:
telegram: true
webhook: true
user.expired:
telegram: false
webhook: true
# 仅用于该事件的附加地址
additionalWebhookUrls:
- https://example.com/xlada/critical

payload 签名​

每个请求都会带上服务请求头:

请求头值
X-XLADA-Signature请求体的 HMAC-SHA256,十六进制
X-XLADA-Timestamp事件的 ISO 8601 时间
Content-Typeapplication/json
User-AgentXLADA

签名按 HMAC-SHA256(secret, request_body) 计算,并与 请求头比较。必须比较原始请求体,而不是解析后的 JSON。

import { createHmac, timingSafeEqual } from 'node:crypto';

function isValidSignature(rawBody, secret, signature) {
const expected = createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(signature ?? '');
return a.length === b.length && timingSafeEqual(a, b);
}

payload 格式​

请求体中始终有四个字段:scope、event、timestamp 和 data。 用户事件还额外带有 meta。

{
"scope": "service",
"event": "service.panel_started",
"timestamp": "2026-01-07T11:57:29.426Z",
"data": {
"panelVersion": "1.1.1"
}
}

meta 字段只在提醒类事件中填充:

字段事件值
notConnectedAfterHoursuser.not_connected用户已有多少小时未连接
expirationuser.expiration相对于 expireAt 的小时数:负值表示到期前,正值表示到期后

其他所有事件的 meta 都为 null。

事件列表​

范围(scope)事件
useruser.created, user.modified, user.deleted, user.revoked, user.disabled, user.enabled, user.limited, user.expired, user.traffic_reset, user.first_connected, user.bandwidth_usage_threshold_reached, user.not_connected, user.expiration
user_hwid_devicesuser_hwid_devices.added, user_hwid_devices.deleted
nodenode.created, node.modified, node.disabled, node.enabled, node.deleted, node.connection_lost, node.connection_restored, node.traffic_notify
serviceservice.panel_started, service.login_attempt_failed, service.login_attempt_success, service.subpage_config_changed, service.api_token_created, service.api_token_deleted
errorserrors.bandwidth_usage_threshold_reached_max_notifications
crmcrm.infra_billing_node_payment_in_7_days, crm.infra_billing_node_payment_in_48hrs, crm.infra_billing_node_payment_in_24hrs, crm.infra_billing_node_payment_due_today, crm.infra_billing_node_payment_overdue_24hrs, crm.infra_billing_node_payment_overdue_48hrs, crm.infra_billing_node_payment_overdue_7_days
torrent_blockertorrent_blocker.report
说明

事件 user.not_connected 和 user.expiration 仅在启用 NOT_CONNECTED_USERS_NOTIFICATIONS_ENABLED 和 EXPIRATION_NOTIFICATIONS_ENABLED 时到达。 事件 user_hwid_devices.* 仅在启用设备限制时出现, 并且只发送到 Webhook——不会重复发送到 Telegram。

重试​

投递通过队列进行:每个地址创建一个独立任务, 并发发送上限为 100。如果接收方未响应,请求会 重试 3 次,间隔 5 秒——总共最多四次尝试。之后 错误会写入面板日志,任务则留在队列中并受限于 有限的保留时间。

在 notifications-config.yml 中可以为具体事件指定附加地址 (additionalWebhookUrls)。它们会追加到 WEBHOOK_URL 中的地址, 而不是替换它们。

提示

请立即向 Webhook 返回 2xx,把处理放到后台。在接收方 响应之前,面板会保持连接,而缓慢的响应会堆积队列。

接下来​