Уведомления о падении сайта в ВКонтакте и на почту: пошаговая инструкция (HetrixTools + Lovable)

Пошаговая инструкция «под ключ»: как настроить мгновенные уведомления о падении сайта в беседу ВКонтакте и на почту через HetrixTools и вебхук на Lovable — с кодом, типичными ошибками и чеклистом.

Александр Лаврищев
Хотите сайт с воронкой продаж на WordPress?
Напишите мне в личку — обсудим вашу задачу.
Написать мне ВКонтакте

Если сайт упал — из-за хостинга, неудачной правки или ошибки в коде — об этом нужно узнать сразу, а не от клиента. В этой статье разберём рабочую схему мониторинга «под ключ»: бесплатный сервис HetrixTools следит за сайтом, а при падении дёргает вебхук, который отправляет уведомление в беседу ВКонтакте. Параллельно письмо уходит на почту. Всю связку можно настроить за час, не имея своего сервера.

Архитектура решения

┌──────────────┐   сайт упал   ┌───────────────┐   POST-вебхук   ┌──────────────────┐
│ HetrixTools  │ ────────────► │  обнаружил    │ ──────────────► │ Lovable-проект   │
│ (мониторинг) │               │  падение      │                 │ (приёмник)       │
└──────────────┘               └───────────────┘                 └────────┬─────────┘
        │                                                                 │
        │ email                                                           │ VK API
        ▼                                                                 ▼
   Почта (profbuh@…)                                              Беседа ВКонтакте

Почему именно так:

  • HetrixTools — один из немногих бесплатных мониторов, где вебхук с произвольным URL доступен на бесплатном тарифе. В UptimeRobot обычный Webhook теперь за платным планом, а интеграции Slack/Splunk валидируют домен и не дают вставить свой URL.
  • Lovable-проект — это приёмник вебхука, живущий независимо от вашего хостинга. Если упал сам сайт вместе с хостингом, приёмник продолжает работать и сигнал дойдёт. На бесплатного тарифа Lovable (≈20 Cloud-кредитов в месяц) хватает с запасом: вебхук почти не расходует ресурсы.
  • ВКонтакте — уведомления приходят в беседу команды через бота сообщества. Callback API при этом настраивать не нужно — мы только отправляем сообщения.

Шаг 1. Проект-приёмник на Lovable

Создайте проект на lovable.dev и попросите агента сделать публичный вебхук-эндпоинт. Проект должен содержать два файла.

1.1. Эндпоинт src/routes/api/public/uptime.ts

Принимает GET и POST, понимает и JSON, и form-urlencoded, приводит разные форматы интеграций к единому виду и проверяет секретный токен в URL:

import { createFileRoute } from "@tanstack/react-router";
import { dispatchAlert, type AlertPayload } from "@/lib/alerts.server";

function timingSafeEqual(a: string, b: string): boolean {
  if (a.length !== b.length) return false;
  let diff = 0;
  for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
  return diff === 0;
}

function normalizeStatus(raw: string | null): AlertPayload["status"] {
  const value = (raw ?? "").toLowerCase();
  if (value === "1" || value.includes("down") || value.includes("offline") || value.includes("critical"))
    return "down";
  if (value === "2" || value.includes("up") || value.includes("online") || value.includes("recover") || value.includes("resolve"))
    return "up";
  return "unknown";
}

/** Разворачиваем вложенный JSON в плоские параметры — разные сервисы шлют разные ключи. */
function flatten(obj: unknown, params: URLSearchParams, prefix = ""): void {
  if (obj == null || typeof obj !== "object") return;
  for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {
    const name = prefix ? `${prefix}.${key}` : key;
    if (value != null && typeof value === "object") flatten(value, params, name);
    else if (value != null) params.set(name, String(value));
  }
}

async function handle(request: Request): Promise<Response> {
  const url = new URL(request.url);
  const params = new URLSearchParams(url.search);

  if (request.method === "POST") {
    const body = await request.text();
    if (body) {
      const t = body.trimStart();
      if (t.startsWith("{") || t.startsWith("[")) {
        try { flatten(JSON.parse(body), params); } catch { /* пропускаем битый JSON */ }
      } else {
        for (const [k, v] of new URLSearchParams(body)) params.set(k, v);
      }
    }
  }

  // Проверка токена — без него эндпоинт публично доступен всем.
  const expected = process.env["UPTIME_WEBHOOK_TOKEN"];
  const provided = params.get("token") ?? request.headers.get("x-webhook-token") ?? "";
  if (!expected || !timingSafeEqual(provided, expected)) {
    return new Response("Invalid token", { status: 401 });
  }

  const result = await dispatchAlert(buildPayload(params));
  return Response.json({ ok: true, ...result });
}

export const Route = createFileRoute("/api/public/uptime")({
  server: { handlers: { GET: ({ request }) => handle(request), POST: ({ request }) => handle(request) } },
});

Обратите внимание на префикс /api/public/ — такие маршруты в Lovable доступны снаружи без авторизации, поэтому проверка токена обязательна.

1.2. Отправка в ВК — src/lib/alerts.server.ts

export async function sendVkAlert(p: AlertPayload): Promise<{ ok: boolean; error?: string }> {
  const token = process.env["VK_BOT_TOKEN"];
  const peerId = process.env["VK_PEER_ID"];
  if (!token || !peerId) return { ok: false, error: "VK_BOT_TOKEN или VK_PEER_ID не заданы" };

  const params = new URLSearchParams({
    peer_id: peerId,
    random_id: String(Date.now() % 2_000_000_000),
    message: formatMessage(p), // "🔴 САЙТ НЕ РАБОТАЕТ" + монитор, URL, причина, время
    access_token: token,
    v: "5.199",
  });

  const res = await fetch("https://api.vk.com/method/messages.send", {
    method: "POST",
    headers: { "content-type": "application/x-www-form-urlencoded" },
    body: params.toString(),
  });
  const json = await res.json();
  if (json.error) return { ok: false, error: json.error.error_msg };
  return { ok: true };
}

1.3. Секреты проекта

В Lovable добавьте три секрета (они доступны только серверному коду, в браузер не попадают):

  • UPTIME_WEBHOOK_TOKEN — случайная строка, например из openssl rand -hex 16. Она же будет частью URL вебхука.
  • VK_BOT_TOKEN — токен сообщества ВК (см. шаг 2).
  • VK_PEER_ID — id беседы, куда писать (см. важный подводный камень в шаге 2).

1.4. Публикация

Нажмите Publish в редакторе Lovable. Проект получит постоянный адрес вида https://имя-проекта.lovable.app. Ваш рабочий вебхук:

https://имя-проекта.lovable.app/api/public/uptime?token=ВАШ_ТОКЕН

Важно про аккаунты: проект и его лимиты привязаны к воркспейсу Lovable, а не к URL. Работайте из одного основного аккаунта; если проект создан под другим — пригласите основной email в воркспейс через Share / Workspace Settings. Опубликованный сайт работает независимо от того, залогинены вы или нет; бесплатного тарифа для такого приёмника достаточно.

Шаг 2. Бот ВКонтакте

  1. В сообществе ВК: Управление → Работа с API → Ключи доступа → Создать ключ. Разрешите права на сообщения сообщества. Это и есть VK_BOT_TOKEN.
  2. Там же: Сообщения → Настройки для бота — включите «Возможности ботов», добавьте бота в нужную беседу и выдайте ему доступ ко всей переписке (или сделайте администратором беседы).
  3. Определите VK_PEER_ID.

Подводный камень №1: peer_id из ссылки — не настоящий

Это главная ошибка, на которой всё встаёт. Ссылка вида vk.com/im?sel=2000000119 или ключ беседы с peer2000000119 показывает id вашего чата, но бот видит беседу под своим номером. На практике: в ссылке было 2000000119, а реальный peer_id оказался 2000000001 — и API отвечал «You don’t have access to this chat».

Решение — диагностический режим в вебхуке. Откройте в браузере:

https://имя-проекта.lovable.app/api/public/uptime?token=ВАШ_ТОКЕН&diag=1

Обработчик вызовет messages.getConversations от имени бота и вернёт список чатов, которые бот реально видит, с их настоящими peer_id:

if (params.get("diag") === "1") {
  const list = await call("messages.getConversations", { count: "50" });
  const chats = list.response?.items?.map((i) => ({
    type: i.conversation?.peer?.type,
    peer_id: i.conversation?.peer?.id,
  }));
  return Response.json({ chats });
}

Берёте peer_id нужной беседы (тип chat), обновляете секрет VK_PEER_ID — и всё работает.

Подводный камень №2: Callback API не нужен

В настройках сообщества есть раздел «Callback API» с сервером и строкой подтверждения. Для нашей схемы он не используется: мы не принимаем события от ВК, а только отправляем сообщения методом messages.send с токеном сообщества. Ничего там настраивать и подтверждать не требуется.

Шаг 3. Мониторинг в HetrixTools

  1. Зарегистрируйтесь на hetrixtools.com (бесплатный тариф).
  2. Uptime Monitors → Add Monitor → Website Monitor: URL — https://ваш-сайт.ru/, метод GET, интервал 1–5 минут.
  3. Contact Lists → Add Contact List. Внутри списка добавьте контакт типа Webhook: вставьте URL из шага 1.4, метод POST. Выбирать формат JSON не обязательно — наш обработчик принимает любые поля и сам находит статус.
  4. В этот же контакт-лист добавьте контакт типа Email с адресом для уведомлений. На бесплатном тарифе к монитору можно привязать только один контакт-лист — поэтому вебхук и почта должны жить в одном списке вместе.
  5. Привяжите контакт-лист к монитору в настройках монитора (поле Contact List).
  6. Если HetrixTools пришлёт письмо для подтверждения email-контакта — перейдите по ссылке из него.

Шаг 4. UptimeRobot — как второй монитор на почту

UptimeRobot оставьте как независимый запасной канал: HTTP(s)-монитор на тот же URL и родной Email-алерт. Но учтите его текущие ограничения бесплатного плана:

  • тип Alert Contact Webhook доступен только на платном тарифе («Upgrade to access»);
  • интеграции Slack, Discord, Splunk (VictorOps) валидируют домен URL — вставить произвольный адрес не получится (Splunk, например, требует, чтобы URL начинался с https://alert.victorops.com/).

Поэтому связка «вебхук → ВК» живёт на HetrixTools, а UptimeRobot дублирует падение на почту — два независимых сервиса снижают шанс пропустить инцидент.

Шаг 5. Проверка

Не ждите реального падения — пошлите тестовый алерт вручную:

curl -X POST "https://имя-проекта.lovable.app/api/public/uptime?token=ВАШ_ТОКЕН" \
  -H "content-type: application/json" \
  -d '{"monitor_status":"offline","monitor_name":"Тест","monitor_target":"https://ваш-сайт.ru/","monitor_errors":"Connection timeout"}'

Правильный ответ: {"ok":true,"vk":{"ok":true}} — и сообщение «🔴 САЙТ НЕ РАБОТАЕТ» в беседе ВК. Если в ответе vk.error — читайте текст ошибки VK API: чаще всего это неверный peer_id (шаг 2) или бот не добавлен в беседу.

Типичные ошибки и их признаки

Симптом Причина Решение
You don't have access to this chat peer_id из ссылки не совпадает с id, под которым бот видит беседу Открыть ?diag=1 и взять реальный peer_id из списка бесед бота
VK API: messages are disabled / нет прав Токен создан без прав на сообщения или бот не в беседе Пересоздать ключ с правом «сообщения», добавить бота в беседу и дать доступ к переписке
Вебхук отвечает 401 Токен в URL не совпадает с секретом UPTIME_WEBHOOK_TOKEN Сверить токен в секрете и в URL монитора
В HetrixTools привязан только вебхук, письма не приходят На бесплатном тарифе один контакт-лист на монитор, email в него не добавлен Добавить email-контакт в тот же список, что и вебхук
UptimeRobot не даёт создать Webhook-контакт Функция закрыта платным планом Использовать HetrixTools для вебхука, UptimeRobot — для email
В статьях/настройках пытаетесь подтвердить Callback API ВК Не требуется Callback API не используется — мы только отправляем сообщения
Проект «потерялся» после смены аккаунта Lovable Проекты живут в воркспейсе конкретного аккаунта Работать из одного основного аккаунта или пригласить его email в воркспейс

Чеклист «под ключ»

  1. Lovable: проект с двумя файлами (роут /api/public/uptime + отправка в ВК), три секрета, проект опубликован.
  2. ВК: токен сообщества с правом на сообщения, бот в беседе, реальный peer_id получен через ?diag=1 и сохранён в секретах.
  3. HetrixTools: Website Monitor на сайт, контакт-лист с Webhook (POST) и Email внутри одного списка, список привязан к монитору, email подтверждён.
  4. UptimeRobot (опционально): второй монитор с email-алертом.
  5. Тест: curl-запрос вернул {"ok":true}, сообщение дошло в ВК, тестовое письмо — на почту.

После этого падение сайта в течение 1–5 минут превращается в сообщение в рабочей беседе ВК и письмо на почту — без своего сервера и на полностью бесплатных тарифах.

Александр Лаврищев
Хотите сайт с воронкой продаж на WordPress?
Напишите мне в личку — обсудим вашу задачу.
Написать мне ВКонтакте

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *