Сообщество / Боты

Обсуждение — VPS для бота ВКонтакте: деплой и работа 24/7

Источник:
VPS для бота ВКонтакте: vk_api, Long Poll и systemd 24/7

Бот для сообщества ВКонтакте отвечает подписчикам, принимает заявки и рассылает уведомления. Чтобы он работал без выходных, его размещают на VPS. Развернём бота на vkbottle или vk_api с Bots Long Poll и автозапуском через systemd. Бот ВК работает от имени сообщества через Bots Long Poll API: он держит открытое соединение с серверами ВКонтакте и получает события — новые сообщения, вступления, реакции. В отличие от Callback API, Long Poll не требует внешнего домена и белого IP, что упрощает запуск на любом VPS.

Подробнее →
kirill_nsk
Middle
Сообщения: 184
Репутация: 129
Дата регистрации:
26.08.2026
АВТОР ТЕМЫ02 нояб. 2026 г., 12:01 (GMT+3)
знакомая держит маленькую мастерскую по ремонту велосипедов, и у неё группа вк, где одни и те же вопросы по кругу: «сколько стоит переборка втулки», «вы в субботу работаете?». прикидываю бота с кнопками. фронт у меня в голове уже нарисован, а вот серверная часть пока только по статье.

зацепился за одно место в разделе про systemd:

Restart=always
RestartSec=5


и там же ниже, в частых ошибках, пункт про токен без прав на сообщения.

вот как я это понимаю, поправьте, если не туда полез. если бот падает не из-за случайной ошибки в обработчике, а сразу на старте (токен кривой, прав нет, опечатка в bot.env), то systemd будет честно поднимать его каждые пять секунд. бесконечно, или пока я не загляну в journalctl. снаружи это выглядит как «бот молчит», а в status, может быть, вообще мелькает active, если я попаду между перезапусками.

вопрос такой: как такое ловят по-нормальному? ставят ограничение на число перезапусков, чтобы сервис в итоге честно ушёл в failed? или проверяют токен отдельным шагом до bot.run_forever(), чтобы скрипт сразу внятно падал с понятной строкой в логе?

мне второе ближе по-фронтендерски: сначала валидация, потом запуск. но не знаю, принято ли так у ботов или я усложняю.
0
V
vlad_dv
Junior
Сообщения: 14
Репутация: 12
Дата регистрации:
26.09.2026
02 нояб. 2026 г., 14:03 (GMT+3)
Ты всё правильно понял, и там есть ещё один подвох. По умолчанию у systemd лимит пять запусков за десять секунд. С RestartSec=5 в это окно больше двух попыток не влезет, поэтому лимит не сработает никогда, и сервис будет крутиться бесконечно.

Я бы делал оба варианта, они не спорят:

[Unit]
StartLimitIntervalSec=300
StartLimitBurst=5

[Service]
Restart=always
RestartSec=5
RestartPreventExitStatus=78


В скрипте до run_forever делаешь один лёгкий запрос к API от имени группы. Если токен не прошёл, печатаешь понятную строку и выходишь с кодом 78. Это код «ошибка конфигурации» из sysexits. systemd его увидит, перезапускать не станет, и status честно покажет failed вместе с твоей строкой. А случайные падения в обработчике пусть дальше ловит Restart. Лимит в [Unit] страхует от того, что ты не предусмотрел.

И раз у тебя вопрос «вы в субботу работаете?», загляни в timedatectl на сервере. Я во Владивостоке, у меня UTC+10, и сколько раз видел ботов, которые жили по UTC или по часовому поясу дата-центра. Человек пишет в субботу в девять утра, а бот по своему времени отвечает «сейчас закрыто, приходите завтра». Лучше хранить часы мастерской с явной зоной в конфиге и не полагаться на системное время машины.
0
L
leo_msk
Junior
Сообщения: 27
Репутация: 13
Дата регистрации:
12.09.2026
02 нояб. 2026 г., 18:05 (GMT+3)

vlad_dv писал:
Лучше хранить часы мастерской с явной зоной в конфиге


Про зону согласен. Добавлю ещё один сценарий, который systemd не поймает вообще, даже с exit 78 и лимитами.

Процесс жив, status показывает active, в журнале пусто. При этом бот уже полчаса ничего не получает: long poll где-то повис, соединение не закрылось, исключения нет. Restart не сработает, потому что падать нечему. Владелица мастерской узнаёт об этом, когда клиент пишет ей в личку: «у вас бот сломался?»

Поэтому я разделяю две вещи: «процесс запущен» и «бот работает». Первое проверяет systemd, второе нужно проверять снаружи. У меня это сделано в n8n, примерно так:

1. Бот после каждого успешного цикла получения событий пишет текущее время в маленький файл или в одну строку в базе. Это пульс, и больше он ничего не делает.
2. В n8n стоит Cron-нода, раз в пять минут.
3. Дальше нода, которая читает этот пульс.
4. IF: пульс старше, скажем, десяти минут.
5. Если да, уведомление человеку, которому не всё равно. Не в ту же группу ВК, а в отдельный канал, чтобы сообщение не зависело от сломанного бота.
6. Если нет, ничего. Тишина тоже результат.

Порог подбирается под реальный трафик. У велосипедной мастерской ночью может не быть ни одного сообщения, поэтому пульс должен обновляться на каждом цикле опроса, а не на каждом входящем сообщении. Иначе в три ночи придёт ложная тревога, и через неделю её начнут игнорировать.

Теперь про «вы в субботу работаете?», раз уж это главный вопрос в группе. Тут легко соблазниться и отдать всё модели: пусть сама поймёт и ответит. Я бы так не делал. Ответ про часы работы должен браться из таблицы: дни, время, явная зона, отдельный список исключений вроде праздников или «уехали на склад». Модель может уверенно сказать «да, до 18:00», и проверить это будет нечем.

Если кнопок мало и люди всё равно пишут свободным текстом, локальная модель через ollama пригодится на одном шаге: определить, о чём вопрос. Часы, цена переборки, запись, что-то другое. Это классификация, а не генерация ответа. Дальше обычный Switch, и каждая ветка берёт ответ из конфига. Если модель не уверена или выбрала «другое», бот пишет «передам мастеру» и пересылает вопрос человеку. Такой бот честно ответит на свои пять вопросов и не будет сочинять расценки.

kirill_nsk, твоя идея «сначала валидация, потом запуск» хорошо сюда ложится. Только валидацию стоит делать не один раз на старте, а держать постоянно, хотя бы в таком упрощённом виде.
0
A
asya_subs
Junior
Сообщения: 12
Репутация: 7
Дата регистрации:
25.10.2026
02 нояб. 2026 г., 19:01 (GMT+3)
Про пятый пункт. Уведомление будет читать владелица мастерской, а не тот, кто собирал n8n. «heartbeat stale: 612s» она смахнёт, как спам. С рендером субтитров у меня то же самое: пока сообщение звучит как лог, его никто не открывает.

Я бы писала по-человечески: «Бот в группе молчит с 18:40. Клиентам никто не отвечает. Позвони Кириллу». Время последнего пульса прямо в тексте, чтобы не пришлось ничего высчитывать.
0