Мониторинг доменов в Telegram: бот и скрипт для Keitaro
Мониторинг доменов в Telegram: бот для Keitaro следит за сроками регистрации, SSL, доступностью и блокировками РКН. Плюс скрипт на PHP для своего сервера…

Мониторинг доменов в арбитраже нужен, чтобы связка не умерла посреди открутки: не истекла регистрация, не кончился SSL-сертификат, сервер не перестал отвечать, домен не попал в блокировку. Проще всего поручить это Telegram-боту. Он берёт список доменов из Keitaro по API, проверяет их каждый день и пишет, когда пора продлевать или чинить.
Ниже: почему мы сделали своего бота, как подключить @keboostclicksru_bot, как проверить домен вручную и готовый скрипт на PHP, если хотите держать мониторинг на своём сервере.

- Зачем мониторить домены
- Бот @keboostclicksru_bot: как подключить
- Что проверяет бот
- Как проверить домен вручную
- Срок регистрации
- SSL-сертификат
- Блокировки
- Свой мониторинг доменов: скрипт на PHP
- Как запустить
- Встроенный мониторинг в Keitaro
- Частые вопросы
- Как проверить, заблокирован ли домен?
- Где взять API-ключ Keitaro для бота?
- Можно ли мониторить домены без Keitaro?
- Почему не определяется срок регистрации домена .ru?
- Как часто бот присылает уведомления?
- Чем мониторинг доменов отличается от мониторинга потоков Keitaro?
Зачем мониторить домены
История из нашей практики. Льём трафик, вечером открываем статистику, а лиды подорожали в пять раз. Причина нашлась быстро: истёк домен, к которому была привязана кампания в Кейтаро. Через месяц ситуация повторилась уже у всей команды. Итог: несколько кабинетов после перезапуска ушли на полиси. Продлевать старые домены владелец команды считал невыгодным, а следить за сроками вручную никто не успевал. Так появился бот.
Что обычно ломается и как это заметить:
| Что случилось | Чем грозит | Как заметить |
|---|---|---|
| Истекла регистрация | Домен перестаёт открываться, клики уходят в пустоту | Дата окончания в RDAP или WHOIS |
| Истёк SSL-сертификат | Браузер показывает предупреждение вместо лендинга | Дата окончания сертификата |
| Сервер не отвечает | Трафик оплачен, а страницы нет | Регулярный HTTP-запрос |
| Блокировка в России | Пользователи из РФ не откроют сайт | Реестр Роскомнадзора |
| Бан домена в Facebook | Ссылки с доменом блокируются или открываются с предупреждением | Проверка домена в Facebook |
Keitaro сам выписывает SSL-сертификат после правильной парковки домена (документация по доменам). Но если DNS домена поменяли или регистрация истекла, сертификат может перестать обновляться, поэтому его дату тоже стоит проверять.
Бот @keboostclicksru_bot: как подключить
Бот написан на PHP с базой MariaDB и работает на нашем сервере. Домены в него можно загрузить двумя путями: из трекера по API или списком вручную. Второй путь работает с любым трекером и без трекера вообще.
- Откройте бота и нажмите «Запустить».
- Выберите «Вставить домены списком» или «Подключить трекер».
- Для Keitaro укажите адрес, по которому открываете админку (домен или IP сервера), и ключ Admin API.
- Бот загрузит домены, проверит их и дальше будет сам синхронизировать список с трекером.
Где взять ключ: в Keitaro откройте «Пользователи», нажмите «Править» напротив нужного логина и выберите «Создать новый ключ». Второй путь: значок аккаунта в правом верхнем углу, «Профиль → API ключи» (инструкция Keitaro). Учтите, что Admin API есть только на тарифах Expert, Team и Enterprise. На Starter и Advanced загружайте домены списком. Чем тарифы Keitaro отличаются по цене и возможностям, мы разбирали в сравнении трекеров для арбитража.
Что проверяет бот
| Проверка | Когда бот напишет |
|---|---|
| Срок регистрации (RDAP, для зон без RDAP: WHOIS) | За 30, 14, 7, 3 и 1 день до окончания |
| Домен пропал из реестра | После трёх проверок подряд с одним результатом |
| SSL-сертификат | За 14, 7, 3 и 1 день и после истечения |
| Доступность сайта | После трёх неудачных проверок подряд и при восстановлении |
| Смена IP-адреса в DNS | При изменении |
| Блокировка Роскомнадзора | При попадании в реестр и при снятии |
Чтобы не превращаться в спам, бот по умолчанию присылает одну сводку в день. Срочные события он отправляет сразу, но не чаще раза в четыре часа, ночью молчит и пишет не больше шести сообщений в сутки. Частоту можно поменять в /settings. Остальные команды: /domains (список), /check (проверить сейчас), /sync (синхронизировать с трекером), /add (добавить домены), /help.
Как проверить домен вручную
Иногда нужно быстро проверить один домен, не подключая бота. Вот что для этого есть.
Срок регистрации
Большинство доменных зон отвечают по протоколу RDAP. Адрес сервера для каждой зоны публикует IANA в файле dns.json, а сервис rdap.org сам перенаправляет запрос нужному реестру:
curl -sL https://rdap.org/domain/ВАШ_ДОМЕН.com | grep -o '"eventAction": *"expiration", *"eventDate": *"[^"]*"'У зон .ru, .su и .рф RDAP в списке IANA нет. Для них работает обычный WHOIS, дата окончания стоит в строке paid-till:
whois -h whois.tcinet.ru ВАШ_ДОМЕН.ru | grep paid-tillSSL-сертификат
echo | openssl s_client -connect ВАШ_ДОМЕН:443 -servername ВАШ_ДОМЕН 2>/dev/null | openssl x509 -noout -enddateБлокировки
- Роскомнадзор. В FAQ Keitaro по доменам для проверки бана РКН указан официальный сервис blocklist.rkn.gov.ru.
- Facebook. Наша проверка домена в Facebook показывает, заблокирован ли домен и что увидит пользователь при переходе.
- Google Safe Browsing. Статус сайта в базе опасных сайтов Google можно посмотреть в отчёте о прозрачности.
- Цепочка переходов. Если домен открывается, но не туда, разверните цепочку в проверке редиректов.
Свой мониторинг доменов: скрипт на PHP
Если не хотите отдавать ключ от трекера стороннему боту, поставьте скрипт на свой сервер. Он забирает домены из Keitaro через Admin API (метод GET /admin_api/v1/domains из документации Admin API, ключ передаётся в заголовке Api-Key), проверяет срок регистрации через RDAP, а для зон без RDAP через WHOIS, смотрит дату SSL-сертификата и отвечает ли сайт. Итог приходит в Telegram одним сообщением.
Нужен PHP 8 с расширениями curl, openssl и mbstring. Расширение intl необязательно: с ним скрипт понимает кириллические домены.
<?php
// domain-monitor.php: сводка по доменам Keitaro в Telegram.
// Проверяет срок регистрации (RDAP, для зон без RDAP: WHOIS),
// срок SSL-сертификата и отвечает ли домен вообще.
// Запуск: php domain-monitor.php (раз в сутки по cron).
declare(strict_types=1);
const KEITARO_URL = 'https://ВАШ_ТРЕКЕР'; // адрес, где открывается админка Keitaro
const KEITARO_KEY = 'API_KEY'; // Профиль → API ключи; пусто = без Keitaro
const EXTRA_DOMAINS = []; // домены вне трекера: ['example.com']
const TG_TOKEN = ''; // токен от @BotFather; пусто = печать в консоль
const TG_CHAT = ''; // ID чата или группы
const WARN_DOMAIN_DAYS = 30; // предупреждать за N дней до конца регистрации
const WARN_SSL_DAYS = 14; // и за N дней до конца сертификата
function http_get(string $url, array $headers = [], bool $verify = true, bool $follow = true): array
{
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => $follow,
CURLOPT_MAXREDIRS => 5,
CURLOPT_PROTOCOLS => CURLPROTO_HTTP | CURLPROTO_HTTPS,
CURLOPT_REDIR_PROTOCOLS => CURLPROTO_HTTP | CURLPROTO_HTTPS,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 20,
CURLOPT_SSL_VERIFYPEER => $verify,
CURLOPT_SSL_VERIFYHOST => $verify ? 2 : 0,
CURLOPT_USERAGENT => 'domain-monitor/1.0',
]);
$body = curl_exec($ch);
$result = [(int) curl_getinfo($ch, CURLINFO_HTTP_CODE), is_string($body) ? $body : '', curl_error($ch)];
curl_close($ch);
return $result;
}
function keitaro_domains(): array
{
$url = rtrim(KEITARO_URL, '/') . '/admin_api/v1/domains';
$parts = parse_url($url);
if (($parts['scheme'] ?? '') !== 'https' || isset($parts['user']) || isset($parts['pass'])) {
throw new RuntimeException('Admin API требует HTTPS без логина и пароля в URL');
}
// Api-Key не пересылаем вслед за редиректом; TLS всегда проверяется.
[$code, $body] = http_get($url, ['Api-Key: ' . KEITARO_KEY], true, false);
if ($code !== 200) {
throw new RuntimeException("Keitaro Admin API ответил HTTP $code");
}
$names = [];
foreach (json_decode($body, true, 512, JSON_THROW_ON_ERROR) as $domain) {
if (($domain['state'] ?? 'active') === 'active') {
$name = strtolower($domain['name']);
if (function_exists('idn_to_ascii') && preg_match('/[^\x00-\x7F]/', $name)) {
$name = idn_to_ascii($name) ?: $name; // кириллические домены в punycode
}
$names[] = $name;
}
}
return $names;
}
// land.example.com → example.com. Для зон вида co.uk допишите исключения сами.
function base_domain(string $host): string
{
return implode('.', array_slice(explode('.', $host), -2));
}
function rdap_base(string $tld): ?string
{
static $map = null;
if ($map === null) {
$map = [];
[, $body] = http_get('https://data.iana.org/rdap/dns.json');
foreach (json_decode($body, true)['services'] ?? [] as [$tlds, $urls]) {
foreach ($tlds as $t) {
$map[$t] = rtrim($urls[0], '/') . '/';
}
}
}
return $map[$tld] ?? null;
}
function whois_query(string $server, string $query): string
{
$fp = @fsockopen($server, 43, $errno, $errstr, 10);
if (!$fp) {
return '';
}
stream_set_timeout($fp, 10);
fwrite($fp, $query . "\r\n");
$out = (string) stream_get_contents($fp);
fclose($fp);
return $out;
}
// Дата окончания регистрации (unix time) или null, если узнать не удалось
function domain_expiry(string $domain): ?int
{
$tld = substr((string) strrchr($domain, '.'), 1);
$base = rdap_base($tld);
if ($base !== null) {
usleep(300000); // не частим: реестры ограничивают число запросов
[$code, $body] = http_get($base . 'domain/' . $domain, ['Accept: application/rdap+json']);
if ($code === 200) {
foreach (json_decode($body, true)['events'] ?? [] as $event) {
if (($event['eventAction'] ?? '') === 'expiration') {
return strtotime($event['eventDate']) ?: null;
}
}
}
return null;
}
// Зоны без RDAP (например .ru): спрашиваем у IANA адрес WHOIS-сервера зоны
if (!preg_match('/^whois:\s*(\S+)/mi', whois_query('whois.iana.org', $tld), $m)) {
return null;
}
$raw = whois_query($m[1], $domain);
if (preg_match('/^\s*(?:Registry Expiry Date|Registrar Registration Expiration Date|Expiration Date|Expiry Date|paid-till)\s*:\s*(\S+)/mi', $raw, $m)) {
return strtotime($m[1]) ?: null;
}
return null;
}
function ssl_expiry(string $host): ?int
{
$ctx = stream_context_create(['ssl' => [
'capture_peer_cert' => true,
'peer_name' => $host,
'verify_peer' => false, // хотим увидеть и просроченный сертификат
'verify_peer_name' => false,
]]);
$fp = @stream_socket_client("ssl://$host:443", $errno, $errstr, 10, STREAM_CLIENT_CONNECT, $ctx);
if (!$fp) {
return null;
}
$cert = stream_context_get_params($fp)['options']['ssl']['peer_certificate'] ?? null;
fclose($fp);
$info = $cert ? openssl_x509_parse($cert) : false;
return $info ? (int) $info['validTo_time_t'] : null;
}
function days_left(int $ts): int
{
return (int) floor(($ts - time()) / 86400);
}
function send_telegram(string $text): void
{
if (TG_TOKEN === '') {
echo $text, "\n\n";
return;
}
$ch = curl_init('https://api.telegram.org/bot' . TG_TOKEN . '/sendMessage');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query(['chat_id' => TG_CHAT, 'text' => $text, 'parse_mode' => 'HTML']),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
]);
$answer = json_decode((string) curl_exec($ch), true);
if (empty($answer['ok'])) {
fwrite(STDERR, 'Telegram: ' . ($answer['description'] ?? 'нет ответа') . "\n");
}
}
try {
$hosts = KEITARO_KEY === '' ? [] : keitaro_domains(); // без ключа: только EXTRA_DOMAINS
} catch (Throwable $e) {
send_telegram('⚠️ Мониторинг доменов: ' . htmlspecialchars($e->getMessage(), ENT_NOQUOTES, 'UTF-8'));
exit(1);
}
$hosts = array_values(array_unique(array_merge($hosts, EXTRA_DOMAINS)));
$problems = [];
$checkedBase = [];
foreach ($hosts as $host) {
$h = htmlspecialchars($host, ENT_NOQUOTES, 'UTF-8');
$base = base_domain($host);
if (!isset($checkedBase[$base])) {
$checkedBase[$base] = true;
$exp = domain_expiry($base);
if ($exp === null) {
$problems[] = "❔ $base: не удалось узнать срок регистрации, проверьте вручную";
} elseif (days_left($exp) <= WARN_DOMAIN_DAYS) {
$problems[] = "⏳ $base: регистрация до " . date('d.m.Y', $exp) . ' (осталось ' . days_left($exp) . ' дн.)';
}
}
$ssl = ssl_expiry($host);
if ($ssl === null) {
$problems[] = "🚫 $h: нет ответа по HTTPS";
continue;
}
if (days_left($ssl) <= WARN_SSL_DAYS) {
$problems[] = "🔒 $h: сертификат до " . date('d.m.Y', $ssl) . ' (осталось ' . days_left($ssl) . ' дн.)';
}
// 4xx не считаем ошибкой: домен Keitaro без Index-кампании может отвечать 404
[$code, , $error] = http_get("https://$host/", [], false);
if ($code === 0 || $code >= 500) {
$problems[] = "🚫 $h: сайт не открывается (" . ($code ? "HTTP $code" : htmlspecialchars($error, ENT_NOQUOTES, 'UTF-8')) . ')';
}
}
$header = '<b>Домены: ' . count($hosts) . ', проблем: ' . count($problems) . "</b>\n";
$chunk = $header;
foreach ($problems as $line) {
if (mb_strlen($chunk . $line) > 3800) { // лимит Telegram 4096 символов
send_telegram($chunk);
$chunk = '';
}
$chunk .= $line . "\n";
}
send_telegram($problems ? $chunk : $header . 'Всё в порядке ✅');Как запустить
- Создайте бота у @BotFather командой /newbot и сохраните токен.
- Напишите боту любое сообщение (или добавьте его в рабочую группу), откройте в браузере
https://api.telegram.org/botТОКЕН/getUpdatesи возьмите значениеchat.id. У групп оно отрицательное. Этот способ описан и в документации Keitaro. - Впишите в константы адрес трекера и ключ API. Для Admin API используйте доверенное доменное имя с действительным сертификатом. Не отключайте проверку TLS на постоянной основе ради доступа по IP: с этим запросом передаётся ключ трекера.
- Запустите
php domain-monitor.phpс пустым TG_TOKEN: отчёт напечатается в консоль. Когда всё устроит, впишите токен и ID чата. - Добавьте задание в cron, например каждый день в 10:00:
0 10 * * * php /opt/monitor/domain-monitor.php >> /var/log/domain-monitor.log 2>&1
Без Keitaro скрипт тоже работает: оставьте KEITARO_KEY пустым и перечислите домены в EXTRA_DOMAINS.
Храните скрипт с ключами вне публичной папки сайта. В примере запрос Admin API разрешён только по HTTPS с проверкой сертификата и без перехода по редиректам: заголовок Api-Key не уйдёт на другой адрес. При ответе 3xx задайте конечный доверенный HTTPS-адрес трекера, а не отключайте проверку. Проверка срока сертификата здесь не подтверждает правильность его цепочки и имени, а игнорирование 4xx допустимо только для выбранного технического URL, не для контроля рабочего лендинга.
Что учтено в коде:
- Ответы 4xx не считаются ошибкой: домен Keitaro без Index-кампании может отвечать 404, и это нормально. Тревога поднимается, если сайт не ответил совсем или вернул 5xx.
- Сертификат читается без проверки цепочки, иначе просроченный сертификат выглядел бы как «нет ответа», а не как «истёк».
- Поддомены проверяются по основному домену: land.example.com продлевается вместе с example.com. Для зон вида co.uk правило base_domain нужно дописать.
- Длинный отчёт режется на части: у Telegram лимит 4096 символов на сообщение (Bot API, метод sendMessage).
Встроенный мониторинг в Keitaro
У Keitaro есть свой мониторинг потоков на тарифах Expert, Team и Enterprise. Он проверяет страницы, на которые ведёт поток: лендинги и офферы по внешней ссылке или любую другую страницу. Условия: страница недоступна (ответ 4xx или 5xx), содержит или не содержит заданный текст. Действия: отключить поток, заменить домен или URL, отправить вебхук. Минимальный интервал проверки одна минута.
Этот мониторинг следит за тем, куда ведёт поток, но не за сроками регистрации и сертификатов ваших доменов. Поэтому он хорошо дополняет бота, а не заменяет его. Покупать и парковать домены прямо из трекера позволяет интеграция с Namecheap, она тоже доступна с тарифа Expert.
Пожелания по боту присылайте в наш Telegram-канал. Другой наш бот для Keitaro ищет нулевые апрувы и пишет о них в чат команды.
Если не хотите сопровождать собственный скрипт, сравните готовые сервисы мониторинга и проверку формы. Проверка HTTP и успешная отправка заявки являются разными проверками.
Частые вопросы
Как проверить, заблокирован ли домен?
Для России Keitaro советует официальный сервис Роскомнадзора blocklist.rkn.gov.ru. Бан в Facebook покажет проверка домена в Facebook, а пометку об опасном сайте в Chrome покажет отчёт Google Safe Browsing.
Где взять API-ключ Keitaro для бота?
«Пользователи» → «Править» → «Создать новый ключ» или «Профиль → API ключи». Admin API доступен на тарифах Expert, Team и Enterprise.
Можно ли мониторить домены без Keitaro?
Да. В боте выберите «Вставить домены списком», а в скрипте оставьте ключ пустым и перечислите домены в EXTRA_DOMAINS.
Почему не определяется срок регистрации домена .ru?
У зон .ru, .su и .рф нет RDAP-сервера в списке IANA. Скрипт в этом случае спрашивает WHOIS-сервер зоны и берёт дату из строки paid-till.
Как часто бот присылает уведомления?
По умолчанию одна сводка в день, срочные события сразу, но не чаще раза в четыре часа. Ночью бот молчит и пишет не больше шести сообщений в сутки. Режим меняется в /settings.
Чем мониторинг доменов отличается от мониторинга потоков Keitaro?
Мониторинг потоков проверяет страницы, на которые ведёт поток, и умеет подменить URL. Мониторинг доменов следит за регистрацией, сертификатами и доступностью самих доменов.



