Telegram-бот падает после перезапуска: причины и решение
Бот месяц работал, сервер перезагрузили — и тишина: команды не отвечают, апдейты копятся. Ситуация «telegram бот падает после перезапуска» сводится к одной из пяти причин, и каждая различается по логам за десять минут. Ниже — тексты ошибок, рабочий юнит systemd и проверка ребутом.
Содержание
- Три сценария «падает» и как их различить
- Бот не стартует сам: tmux, nohup и забытый enable
- Юнит есть, но бот умирает за секунду
- Conflict 409: два бота на один токен и застрявший вебхук
- Гонка при загрузке: сеть, DNS, база и сбитые часы
- Тихая смерть: OOM-killer, диск и зависания
- Какой сервер нужен под живучий бот и как заказать в MAATRIX
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Три сценария «падает» и как их различить
Слово «падает» скрывает три поломки. Начните с трёх команд:
systemctl is-enabled tgbot; systemctl is-active tgbot
systemctl status tgbot --no-pager -l
journalctl -u tgbot -b --no-pager -n 100
disabled/inactive (dead)— бота никто не запускал: дело в автозапуске, а не в коде.failed/activating (auto-restart)— стартует и умирает: в журнале трейсбек илиStart request repeated too quickly.active (running), но бот молчит — процесс жив, но апдейты не разбирает:Conflictили зависание.
Ловушка, из-за которой не видно причины: в Debian и Ubuntu журнал systemd лежит в tmpfs /run/log/journal и стирается при перезагрузке. Логи прошлой загрузки:
$ journalctl -u tgbot -b -1
Specifying boot ID or boot offset has no effect, no persistent journal was found.
Включите постоянный журнал до экспериментов:
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
В /etc/systemd/journald.conf поставьте Storage=persistent и SystemMaxUse=200M. И посмотрите last -x reboot | head -5: если там ребуты, которых вы не делали, дело в хосте, а не в боте.
Бот не стартует сам: tmux, nohup и забытый enable
Чаще всего бот не оформлен как сервис: его запустили руками в tmux, screen или через nohup python3 bot.py &. Всё это живёт до перезагрузки — после ребута pgrep -af bot.py пуст, хотя вручную бот стартует нормально.
Второй вариант — выполнили только systemctl start, забыв enable: симлинк в /etc/systemd/system/multi-user.target.wants/ не создан, при загрузке сервис никто не поднимет. Третий ловят реже: юнит положили в ~/.config/systemd/user/, а такие сервисы не стартуют при загрузке без linger (loginctl enable-linger bot). Проще системный /etc/systemd/system/tgbot.service:
[Unit]
Description=Telegram bot (aiogram)
Wants=network-online.target
After=network-online.target postgresql.service redis-server.service
StartLimitIntervalSec=300
StartLimitBurst=10
[Service]
Type=simple
User=bot
WorkingDirectory=/opt/tgbot
EnvironmentFile=/etc/tgbot/env
ExecStart=/opt/tgbot/.venv/bin/python -u /opt/tgbot/bot.py
Restart=always
RestartSec=5
KillSignal=SIGINT
MemoryMax=1G
[Install]
WantedBy=multi-user.target
Неочевидное: -u отключает буферизацию вывода Python, иначе логи идут в журнал пачками и трейсбек обрывается. KillSignal=SIGINT даёт боту поймать KeyboardInterrupt и закрыть сессию. StartLimitIntervalSec и StartLimitBurst обязаны быть в [Unit] — в [Service] systemd их молча проигнорирует. Дальше daemon-reload и systemctl enable --now tgbot. Для сервера с нуля есть настройка VPS под телеграм-ботов.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть бот-стекЮнит есть, но бот умирает за секунду
systemctl status показывает failed, а journalctl -u tgbot -b -n 50 — трейсбек. Четыре ошибки покрывают почти всё.
ModuleNotFoundError: No module named 'aiogram'. Библиотеки в venv, а в ExecStart системный /usr/bin/python3. source .venv/bin/activate в юните не сработает: активация — шелловская функция, systemd шелл не запускает. Указывайте интерпретатор напрямую: /opt/tgbot/.venv/bin/python.
error: externally-managed-environment. На Ubuntu 24.04 и Debian 13 системный pip защищён по PEP 668, а --break-system-packages ломает системный Python. Делайте venv и закрепляйте версии жёстко: aiogram==3.15.0, а не aiogram>=3 — иначе переустановка подтянет мажор с изменённым API.
FileNotFoundError: [Errno 2] No such file or directory: 'config.yaml'. У systemd рабочий каталог по умолчанию /, а не каталог проекта. Лечит строка WorkingDirectory=/opt/tgbot; надёжнее — абсолютные пути в коде.
KeyError: 'BOT_TOKEN'. Токен экспортирован в ~/.bashrc, а systemd эти файлы не читает. Выносите переменные в /etc/tgbot/env с правами 640 и владельцем root:bot. Деталь: это не shell-скрипт — export BOT_TOKEN=... не сработает, systemd примет export BOT_TOKEN за имя переменной и потеряет её. И не пишите Environment=BOT_TOKEN=... в юните: значение видно в systemctl show tgbot.
И про базу в /tmp: если SQLite лежит по пути /tmp/bot.db, после ребута будет sqlite3.OperationalError: unable to open database file или, хуже, чистая база — /tmp очищается при загрузке. Штатное место /var/lib/tgbot/ даёт StateDirectory=tgbot. После починки: systemctl reset-failed tgbot.
Conflict 409: два бота на один токен и застрявший вебхук
Странный случай: сервис active (running), процесс жив, а бот отвечает через раз. В журнале:
aiogram.exceptions.TelegramConflictError: Telegram server says - Conflict: terminated by
other getUpdates request; make sure that only one bot instance is running
Telegram отдаёт апдейты одному потребителю. Два процесса с getUpdates выбивают друг друга по очереди — снаружи это «одно сообщение бот увидел, второе нет». После ребута вылезает, когда старый экземпляр не остановился, а рядом стартовал новый. Ищите дубли везде:
pgrep -af "bot.py"
systemctl list-units --state=running | grep -i bot
sudo crontab -l | grep -i reboot
docker ps --format '{{.Names}}\t{{.Status}}'
Классика — юнит systemd плюс забытый @reboot python3 /opt/tgbot/bot.py в кроне: стартуют оба. Вторая — невыключенный старый VPS после переезда.
Разновидность 409 — застрявший вебхук: Conflict: can't use getUpdates method while webhook is active. Спросите Telegram: curl -s "https://api.telegram.org/bot$BOT_TOKEN/getWebhookInfo" | python3 -m json.tool. Ответ:
{"ok": true, "result": {
"url": "https://old.example.com/hook",
"pending_update_count": 1874,
"last_error_message": "Connection refused"}}
Вебхук смотрит на мёртвый адрес, апдейты копятся, поллинг не работает. Снимаем вебхук вместе с очередью, чтобы бот не разгребал две тысячи старых сообщений: deleteWebhook?drop_pending_updates=true. Честное ограничение: Telegram сообщает факт конфликта, но не говорит, кто второй. Если дубль не находится, выход один — /revoke в @BotFather: старый экземпляр отвалится с Unauthorized.
Гонка при загрузке: сеть, DNS, база и сбитые часы
Бот стартует раньше, чем готова инфраструктура, падает и без Restart не поднимается. Признак: руками сервис стартует чисто, а после ребута — сетевой трейсбек.
DNS ещё не поднят: socket.gaierror: [Errno -3] Temporary failure in name resolution. After=network.target означает «сетевая подсистема инициализирована», а не «адрес получен и резолвер работает». Нужен network-online.target с обязательным Wants= плюс включённый systemd-networkd-wait-online.service (или NetworkManager-wait-online.service) — иначе target достигается мгновенно.
База не готова: connection to server at "127.0.0.1", port 5432 failed: Connection refused или отказ Redis на 6379. After=postgresql.service задаёт порядок запуска, но не гарантирует, что PostgreSQL принимает соединения. Ждать нужно явно:
ExecStartPre=/usr/bin/timeout 60 sh -c 'until pg_isready -h 127.0.0.1 -p 5432 -q; do sleep 2; done'
И After= работает только для сервисов этой же машины: про базу на соседнем сервере systemd не знает — спасают ретраи в коде и Restart=always.
Сбитые часы: ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: certificate is not yet valid. Выглядит как проблема сертификата, а на деле у виртуалки после разворота из снапшота уехало время. В выводе timedatectl нужны System clock synchronized: yes и NTP service: active; если no и inactive — лечит timedatectl set-ntp true. Порядок старта покажет systemd-analyze critical-chain tgbot.service.
Тихая смерть: OOM-killer, диск и зависания
Отдельный класс — бот поднимается, работает час-другой и исчезает. Сначала память: journalctl -k -b -1 | grep -iE "out of memory|oom". Диагноз подтверждают:
Out of memory: Killed process 812 (python3) total-vm:1284412kB, anon-rss:412300kB
tgbot.service: Main process exited, code=killed, status=9/KILL
tgbot.service: Failed with result 'oom-kill'
Замерьте потребление вместо догадок: systemctl show tgbot -p MemoryCurrent вернёт что-то вроде MemoryCurrent=78643200, то есть 75 МБ. Пустой aiogram-бот на Python 3.12 в простое держит 60–90 МБ RSS; с pandas или обработкой фото счёт идёт на сотни мегабайт. На VPS с 512 МБ без swap такой бот вместе с PostgreSQL уезжает в OOM за часы — расчёт есть в статье про то, сколько ресурсов нужно VPS для телеграм-ботов. Страховка на минимум:
sudo fallocate -l 2G /swapfile && sudo chmod 600 /swapfile
sudo mkswap /swapfile && sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
Честно: swap не лечит утечку, а оттягивает развязку и замедляет бота, живущего в свопе. Если RSS растёт линейно час за часом — это баг в коде. Зато MemoryMax=1G полезен всегда: ядро убьёт бота, а не sshd, и доступ к серверу останется.
Второй сценарий — забитый диск: OSError: [Errno 28] No space left on device, обычно из-за логов без ротации. Смотрите journalctl --disk-usage, чистите journalctl --vacuum-size=200M.
Третий — процесс жив, но ничего не делает: повисло соединение, зациклился воркер. Restart=always бесполезен, падения нет. Помогает watchdog: Type=notify и WatchdogSec=90 плюс sdnotify с вызовом notify("WATCHDOG=1") в главном цикле — минус честный, это правка кода. Дешевле проверка по таймеру: дёргает getMe, перезапускает юнит и шлёт алерт в Telegram.
В Docker политика перезапуска по умолчанию no, и после ребута контейнер не поднимется: docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' tgbot, затем docker update --restart always tgbot. При unless-stopped контейнер, остановленный вручную до ребута, потом не стартует — by design. И проверяйте настоящим ребутом: systemctl is-enabled tgbot и systemctl is-active tgbot должны вернуть enabled и active, а journalctl -u tgbot -b — быть без трейсбеков.
Какой сервер нужен под живучий бот и как заказать в MAATRIX
Половина этих падений — не ошибки конфигурации, а нехватка ресурсов: OOM на 512 МБ, забитый диск, база и бот на одном ядре. Конфигурацию берите с запасом.
| Профиль бота | Минимум | Комфортно |
|---|---|---|
| Поллинг, без БД, до ~1000 пользователей | 1 vCPU / 1 ГБ / 20 ГБ NVMe | 2 vCPU / 2 ГБ / 40 ГБ NVMe |
| Бот + PostgreSQL + Redis, вебхук через nginx | 2 vCPU / 2 ГБ / 40 ГБ | 2 vCPU / 4 ГБ / 60–80 ГБ NVMe |
| Медиа, ffmpeg, очереди, обращения к ИИ-API | 2 vCPU / 4 ГБ | 4 vCPU / 8 ГБ / 100 ГБ NVMe |
1 ГБ — минимум только для поллинг-бота без базы и медиа; добавьте PostgreSQL, и попадёте ровно в тот OOM, из-за которого читаете эту статью. 4 ГБ — точка, где бот, база, Redis и nginx живут спокойно, а swap остаётся страховкой. Диск берите не 20, а 40–80 ГБ: журнал, логи и бэкапы съедают место незаметно.
По локации для бот-стека советуем UK, Лондон: короткий и стабильный путь до api.telegram.org через европейскую точку — обычно десятки миллисекунд, чистые адреса без наследства прошлых арендаторов и привычная платёжным и ИИ-API юрисдикция. Российские провайдеры дают до Telegram API менее предсказуемое качество, а таймауты при поллинге снаружи выглядят ровно как «бот падает». RU оправдан при персональных данных россиян и 152-ФЗ: это осознанный размен на стабильность связи с API. Подробнее — про VPS в Великобритании для хостинга Telegram-бота.
Развернуть стек можно из панели MAATRIX за несколько минут: Ubuntu 24.04 LTS или Debian 13 и снапшот перед экспериментами с юнитом — чтобы откатиться, если ребут пойдёт не по плану. Оплата картами российских банков, по СБП, криптой или токеном MAAT.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть бот-стекОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Руками бот запускается, а после ребута нет?
Сервис не в автозагрузке: проверьте systemctl is-enabled tgbot. Если disabled, выполните sudo systemctl enable --now tgbot: start без enable автозапуск не создаёт.
Что означает Conflict: terminated by other getUpdates request?
Апдейты по одному токену опрашивают два процесса. Ищите дубль через pgrep -af bot.py, crontab -l | grep reboot и docker ps, а вебхук снимайте через deleteWebhook?drop_pending_updates=true.
Почему после перезагрузки нет логов за прошлую загрузку?
Журнал лежит в tmpfs и стирается при ребуте, поэтому journalctl -b -1 отвечает «no persistent journal was found». Создайте /var/log/journal, выполните systemd-tmpfiles --create --prefix /var/log/journal, перезапустите journald.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.