Telegram-бот на Linux VPS: systemd или Docker, логи, автозапуск и резервное копирование

31.08.26
Telegram-бот на Linux VPS: схема запуска через systemd или Docker, автозапуск, логи и резервное копирование, рядом фирменная механическая птица IPWAY.

Telegram-бот может нормально работать на ноутбуке разработчика во время тестов, но для постоянной эксплуатации этого недостаточно. Ноутбук выключается, соединение пропадает, процесс завершается после закрытия терминала — и бот перестает отвечать.

На Linux VPS приложение можно запустить как обычный сервис: оно будет стартовать вместе с сервером, автоматически восстанавливаться после части сбоев, писать логи и хранить рабочие данные независимо от компьютера разработчика.

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

В этой инструкции не будем писать Telegram-бота с нуля. Будем считать, что приложение уже готово и локально запускается. Задача — превратить его в сервис, рассчитанный на работу 24/7.

Что подготовить перед запуском Telegram-бота на VPS

Для примеров будем использовать условного Python-бота, расположенного в каталоге /opt/telegram-bot.

Точка запуска:

/opt/telegram-bot/bot.py

Если бот написан на Node.js, Go или другом языке, общая схема не меняется: отличаются только runtime, зависимости и команда запуска.

Перед настройкой должны быть готовы:

  • Linux VPS;
  • SSH-доступ;
  • отдельный пользователь для приложения;
  • runtime нужной версии;
  • код бота;
  • зависимости;
  • токен Telegram-бота;
  • место для постоянных данных;
  • понимание, использует бот long polling или webhook.
Что такое Telegram Bot API: HTTP-интерфейс Telegram, через который приложение получает обновления и выполняет действия от имени бота. Для авторизации используется токен конкретного бота, поэтому его нужно считать полноценным секретом.

Рабочий токен нельзя публиковать в Git, вставлять в статьи, скриншоты или оставлять в общедоступных логах.

Также заранее определите, какие данные существуют только на VPS. Например:

  • SQLite-база;
  • файлы пользователей;
  • локальные документы;
  • настройки;
  • очередь задач;
  • данные о заказах или статусах;
  • другое состояние, которое приложение создает уже во время работы.

Именно эти данные впоследствии определят схему резервного копирования.

Long polling или webhook: что выбрать для VPS

Telegram поддерживает два основных способа получать новые события:

  • long polling через getUpdates;
  • webhook.

Для одного бота одновременно использовать оба варианта нельзя. Если установлен webhook, получение обновлений через getUpdates недоступно.

Long polling

При long polling приложение само обращается к Telegram и ожидает новые обновления.

Telegram API
     ▲
     │ getUpdates
     │
Telegram-бот на VPS
Как читать схему: бот сам инициирует соединение с Telegram API и регулярно получает новые события. Публичный HTTP endpoint на самом VPS для этого не требуется.

Для небольшого бота на одном VPS этот вариант часто проще:

  • не нужен публичный HTTP endpoint;
  • не требуется отдельный домен только ради Telegram;
  • не нужно настраивать reverse proxy специально для webhook;
  • процесс удобно контролировать через systemd или Docker.

Именно long polling будем считать основным сценарием этой статьи.

Webhook

При webhook направление меняется: Telegram отправляет HTTPS-запросы на адрес приложения.

Telegram
    │ HTTPS POST
    ▼
домен / reverse proxy
    │
    ▼
Telegram-бот

Webhook удобен, если у проекта уже есть HTTP-приложение, домен, HTTPS и reverse proxy.

Для дополнительной проверки запросов можно использовать секрет webhook, который Telegram передает в специальном HTTP-заголовке.

Важно: long polling и webhook — не два слоя надежности, которые нужно включать одновременно. Выберите один способ получения обновлений и стройте эксплуатацию вокруг него.

Есть еще один важный нюанс для работы 24/7: Telegram не хранит неполученные обновления бесконечно. Если бот долго был выключен, нельзя рассчитывать, что после запуска он обязательно обработает всю накопившуюся очередь.

Поэтому автоматический перезапуск и контроль состояния нужны не только ради удобства администратора.

Запуск Telegram-бота через systemd

Для одного небольшого бота без контейнерной инфраструктуры systemd обычно самый прямой вариант.

Telegram
   │
   ▼
приложение бота
   │
   ▼
systemd
   ├─ запуск при старте VPS
   ├─ перезапуск после сбоя
   └─ логи через journald
Как читать схему: systemd не участвует в работе с Telegram API. Его задача — управлять самим процессом бота: запускать его, перезапускать после сбоя и собирать журнал.

Создаем отдельного пользователя

Постоянно запускать приложение от root не нужно.

Например, создадим системного пользователя:

Терминал Linux
sudo useradd --system --home /opt/telegram-bot --shell /usr/sbin/nologin telegrambot

Если каталог приложения уже существует, передадим его этому пользователю:

Терминал Linux
sudo chown -R telegrambot:telegrambot /opt/telegram-bot
Важно: перед рекурсивным chown убедитесь, что указанный каталог действительно принадлежит приложению. Не применяйте такую команду к системным каталогам или чужим данным.

Подготавливаем виртуальное окружение

Для Python-приложения можно использовать отдельное virtual environment:

Терминал Linux
cd /opt/telegram-bot
python3 -m venv .venv

Затем установим зависимости:

Терминал Linux
/opt/telegram-bot/.venv/bin/pip install -r requirements.txt

После установки полезно проверить приложение вручную под тем же пользователем, от которого впоследствии будет работать сервис:

Терминал Linux
sudo -u telegrambot /opt/telegram-bot/.venv/bin/python /opt/telegram-bot/bot.py

Если бот уже на этом этапе завершается с ошибкой, автоматический перезапуск пока не нужен. Сначала добейтесь нормального ручного запуска.

Где хранить токен

Плохой вариант — записать рабочий токен непосредственно в исходный код:

TOKEN = "123456789:REAL_BOT_TOKEN"

После попадания такого файла в Git секрет может сохраниться в истории даже после удаления строки из актуальной версии.

Для простого systemd-сервиса токен можно вынести в отдельный файл, который не хранится в репозитории.

Например:

/etc/telegram-bot.env

Содержимое файла:

BOT_TOKEN=replace_with_real_token

Ограничим права:

Терминал Linux
sudo chown root:root /etc/telegram-bot.env
sudo chmod 600 /etc/telegram-bot.env

Приложение при этом должно получать токен из переменной окружения, а не из исходного файла проекта.

Важно: EnvironmentFile удобен для небольшого сервиса, но это не полноценный менеджер секретов. Для инфраструктуры с более строгими требованиями лучше использовать специализированный механизм хранения credentials.

Создаем systemd unit

Создадим файл:

/etc/systemd/system/telegram-bot.service

Пример содержимого:

[Unit]
Description=Telegram Bot
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=telegrambot
Group=telegrambot
WorkingDirectory=/opt/telegram-bot
EnvironmentFile=/etc/telegram-bot.env
ExecStart=/opt/telegram-bot/.venv/bin/python /opt/telegram-bot/bot.py
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Основные параметры:

  • User= — пользователь, от которого работает процесс;
  • WorkingDirectory= — рабочий каталог;
  • EnvironmentFile= — файл с переменными;
  • ExecStart= — команда запуска;
  • Restart=on-failure — перезапуск после аварийного завершения;
  • RestartSec=5 — пауза перед новой попыткой запуска.

Путь в ExecStart нельзя копировать вслепую. Если виртуальное окружение находится в другом каталоге или файл запуска называется иначе, unit нужно изменить.

После создания unit перечитаем конфигурацию systemd:

Терминал Linux
sudo systemctl daemon-reload

Запустим бота:

Терминал Linux
sudo systemctl start telegram-bot

Проверим состояние:

Терминал Linux
sudo systemctl status telegram-bot

Если сервис работает правильно, включим запуск вместе с системой:

Терминал Linux
sudo systemctl enable telegram-bot

Или сразу включим автозапуск и запустим сервис:

Терминал Linux
sudo systemctl enable --now telegram-bot
Что важно запомнить: автоматический restart полезен при кратковременном сбое процесса, но не исправляет неверный токен, ошибку в коде, поврежденную БД или несовместимую библиотеку. Если приложение падает сразу после запуска, systemd просто будет повторять попытки.

Смотрим логи systemd

Последние записи сервиса:

Терминал Linux
sudo journalctl -u telegram-bot -n 100

Просмотр в реальном времени:

Терминал Linux
sudo journalctl -u telegram-bot -f

Только записи после текущей загрузки VPS:

Терминал Linux
sudo journalctl -u telegram-bot -b

В журнале обычно можно увидеть:

  • ошибку импорта модуля;
  • неверный путь в ExecStart;
  • отсутствие файла конфигурации;
  • ошибку подключения к БД;
  • проблему доступа к Telegram API;
  • исключение приложения;
  • отказ в доступе к файлу.

Важно различать два состояния:

systemd показывает failed
        │
        └─ процесс завершился или не запустился

systemd показывает active
        │
        └─ процесс жив, но бот все равно может не отвечать

Во втором случае нужно диагностировать уже само приложение, сеть, Telegram API и способ получения обновлений.

Запуск Telegram-бота через Docker Compose

Если приложение уже контейнеризировано или вместе с ботом работают PostgreSQL, Redis и другие сервисы, Docker Compose часто удобнее отдельного systemd-unit для каждого процесса.

Docker Compose
     │
     ├─ bot
     ├─ база / Redis при необходимости
     ├─ persistent data
     └─ secrets

Полный production-процесс Docker мы уже разбирали отдельно, поэтому здесь сосредоточимся только на особенностях Telegram-бота.

Минимальный Dockerfile

Для условного Python-приложения:

FROM python:3.13-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["python", "bot.py"]

Версию Python нужно выбирать по требованиям конкретного проекта, а не по примеру в статье.

Compose-файл

services:
  bot:
    build: .
    restart: unless-stopped
    secrets:
      - bot_token
    volumes:
      - ./data:/app/data

secrets:
  bot_token:
    file: ./secrets/bot_token

Для постоянно работающего бота политика unless-stopped дает понятную логику: контейнер должен запускаться автоматически, пока администратор явно не остановил его вручную.

Как приложение получает secret

Compose secrets предоставляются контейнеру как файлы в каталоге:

/run/secrets/

В нашем примере токен будет доступен по пути:

/run/secrets/bot_token

Приложение должно уметь прочитать значение из этого файла.

Сам файл секрета на VPS тоже нужно защитить:

Терминал Linux
chmod 600 ./secrets/bot_token

И исключить секреты из Git. Например:

secrets/
.env
data/

Последнюю строку нужно применять осознанно. Если внутри data/ находятся шаблонные файлы или структура каталогов, которая должна храниться в репозитории, правило лучше сделать точнее.

Запускаем контейнер

Терминал Linux
docker compose up -d

Проверяем состояние:

Терминал Linux
docker compose ps

Смотрим логи:

Терминал Linux
docker compose logs bot

Или в реальном времени:

Терминал Linux
docker compose logs -f bot

Если контейнер имеет статус Up, это означает только, что основной процесс пока не завершился. Сам бот все равно может потерять доступ к базе, внешнему API или перестать корректно обрабатывать updates.

Диагностика, безопасность и обновление Telegram-бота

Что делать после утечки токена

Независимо от способа запуска не стоит:

  • записывать рабочий токен прямо в исходный код;
  • коммитить .env или файл секрета в Git;
  • вставлять токен в compose.yaml;
  • публиковать его на скриншотах;
  • выводить токен целиком в debug-логи;
  • отправлять его вместе с открытым архивом проекта.
Типичная ошибка: разработчик случайно коммитит токен, затем удаляет строку из последнего commit и считает проблему решенной. Секрет мог остаться в истории Git, fork, CI-логах или уже быть скопирован.

Если рабочий токен оказался раскрыт, безопаснее считать его скомпрометированным и заменить через BotFather. Простого удаления из текущего файла недостаточно.

Почему бот перестал отвечать

Когда пользователь сообщает, что «бот не работает», сначала нужно определить уровень проблемы.

VPS доступен?
    │
    ▼
процесс бота запущен?
    │
    ▼
есть ли ошибки в логах?
    │
    ▼
доступен Telegram API?
    │
    ▼
получает ли бот updates?
    │
    ▼
работает ли БД / внешние API?
Как читать схему: диагностику лучше вести сверху вниз. Нет смысла разбирать обработчики сообщений, если сам процесс остановлен или VPS не имеет сетевого доступа.

Для systemd:

Терминал Linux
sudo systemctl status telegram-bot
sudo journalctl -u telegram-bot -n 100

Для Docker:

Терминал Linux
docker compose ps
docker compose logs --tail=100 bot

Проверяем, не остался ли webhook

Если приложение перевели на long polling, а для этого же бота ранее был установлен webhook, получение обновлений через getUpdates работать не будет.

Текущее состояние webhook можно проверить штатным методом getWebhookInfo. При переводе обратно на long polling webhook удаляется методом deleteWebhook.

Важно: параметр удаления ожидающих updates нужно использовать только осознанно. Если очередь отбросить, Telegram уже не передаст эти события приложению.

Проверяем, не запущены ли два экземпляра

После миграции иногда получается такая схема:

старый VPS ──┐
             ├── один Telegram-бот
новый VPS ───┘

Оба процесса используют один токен и пытаются работать с одной очередью updates.

При переносе недостаточно запустить приложение на новом VPS — нужно также убедиться, что старый экземпляр действительно остановлен.

Проверяем место на диске

Терминал Linux
df -h

Если файловая система заполнена, приложение может перестать писать SQLite, создавать временные файлы или сохранять логи.

Также стоит проверить inode:

Терминал Linux
df -i

Свободные гигабайты не помогут, если приложение создало огромное количество мелких файлов и исчерпало доступные inode.

Как безопасно обновлять Telegram-бота

Обновление production-бота лучше воспринимать как небольшой runbook, а не как одну команду git pull.

Перед обновлением:

  1. Проверьте текущее состояние.
  2. Убедитесь, что резервная копия рабочих данных актуальна.
  3. Зафиксируйте текущую рабочую версию.
  4. Получите новую версию кода или образа.
  5. Обновите зависимости.
  6. Перезапустите сервис.
  7. Посмотрите логи.
  8. Отправьте тестовую команду боту.
  9. Проверьте критичные сценарии.
  10. При ошибке верните предыдущую рабочую версию.

Обновление systemd-варианта

После обновления кода и зависимостей:

Терминал Linux
sudo systemctl restart telegram-bot

Сразу после перезапуска:

Терминал Linux
sudo systemctl status telegram-bot
sudo journalctl -u telegram-bot -n 100

Если изменялся сам unit-файл:

Терминал Linux
sudo systemctl daemon-reload
sudo systemctl restart telegram-bot

Обновление Docker-варианта

Если образ собирается локально:

Терминал Linux
docker compose build
docker compose up -d

Если образ приходит из registry:

Терминал Linux
docker compose pull
docker compose up -d

После обновления:

Терминал Linux
docker compose ps
docker compose logs --tail=100 bot

Важно отличать это от простой команды:

Терминал Linux
docker compose restart

docker compose restart только перезапускает существующий контейнер. Если изменился compose.yaml, конфигурацию обычно нужно применить через docker compose up -d, чтобы Compose при необходимости пересоздал контейнер.

Практика IPWAY: после любого обновления проверяйте не только статус процесса. Отправьте боту реальную тестовую команду, которая проходит через основные зависимости — Telegram API, базу данных и хотя бы один внешний сервис, если он используется.

Резервное копирование и проверка после перезагрузки

Git-репозиторий с исходным кодом не является полной резервной копией рабочего бота.

Нужно определить, какое состояние создается уже после запуска приложения.

SQLite

Если бот хранит данные в SQLite, база может находиться, например, в:

/opt/telegram-bot/data/bot.db

Простое копирование активно изменяемого файла не всегда дает согласованную резервную копию. Лучше использовать штатный механизм backup конкретной СУБД или корректно остановить запись на время операции.

PostgreSQL или MySQL

Для отдельной серверной СУБД нужны собственные дампы или другая согласованная схема резервного копирования.

Копия исходного кода и резервная копия базы решают разные задачи.

Пользовательские и рабочие файлы

Бот может сохранять:

  • документы;
  • фотографии;
  • CSV/XLSX;
  • счета;
  • отчеты;
  • медиаданные;
  • файлы интеграций.

Если эти данные нужны приложению позже, каталог должен попадать в backup.

Конфигурация сервиса

Полезно сохранять:

  • systemd unit;
  • compose.yaml;
  • Dockerfile;
  • версии зависимостей;
  • структуру необходимых каталогов;
  • инструкцию восстановления.

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

Что важно запомнить: Telegram не является резервной копией внутреннего состояния приложения. Сообщение может существовать в чате, а связанный заказ, статус операции или настройка пользователя — только в вашей базе данных.

Проверяем восстановление

Бэкап, который ни разу не проверяли на восстановление, дает ложное чувство безопасности.

создали backup
      │
      ▼
восстановили в тестовую среду
      │
      ▼
запустили приложение
      │
      ▼
проверили данные

Для рабочего бота такой тест особенно полезен перед крупным обновлением приложения или схемы базы данных.

Проверяем работу после перезагрузки VPS

Настроенный сервис должен переживать обычный reboot без ручного входа администратора.

Проверить это лучше намеренно в подходящее техническое окно.

Перед перезагрузкой для systemd:

Терминал Linux
sudo systemctl status telegram-bot

Для Docker:

Терминал Linux
docker compose ps

Затем перезагрузите VPS:

Терминал Linux
sudo reboot

После восстановления SSH снова проверьте сервис.

Для systemd:

Терминал Linux
sudo systemctl status telegram-bot

Для Docker:

Терминал Linux
docker compose ps

После этого:

  • отправьте тестовое сообщение;
  • проверьте базу данных;
  • посмотрите свежие логи;
  • убедитесь, что рабочие файлы на месте;
  • проверьте свободное место;
  • проверьте внешние API, если бот от них зависит.
Типичная ошибка: настроить автозапуск, увидеть active (running) или Up и считать задачу завершенной. Полезнее один раз выполнить реальный reboot и убедиться, что весь сервис вместе с зависимостями возвращается в рабочее состояние.

Systemd или Docker Compose: что выбрать

КритерийsystemdDocker Compose
Один небольшой ботОбычно прощеМожет быть избыточен
Изоляция окруженияЗависит от настройки ОСВыше за счет контейнера
Приложение уже контейнеризированоДополнительный слой обычно не нуженЕстественный выбор
Логиjournalctldocker compose logs
Автозапускsystemd unitrestart policy + Docker daemon
Несколько связанных сервисовМожно настроить отдельноОбычно удобнее описать вместе
Перенос окруженияНужно воспроизводить настройки хостаКонтейнерную среду обычно проще повторить

Если бот — один Python-процесс с небольшой SQLite-базой, systemd зачастую дает все необходимое без дополнительной контейнерной инфраструктуры.

Если приложение уже собирается в Docker или рядом работают PostgreSQL, Redis, worker и другие сервисы, Compose обычно проще поддерживать как единую конфигурацию.

Нет смысла переводить стабильный systemd-сервис в Docker только ради самого факта использования контейнеров. И наоборот, контейнеризированное приложение не стоит вручную распаковывать на хост только ради systemd.

Заключение

Разместить Telegram-бота на Linux VPS несложно: для первого запуска иногда достаточно одной команды. Гораздо важнее сделать так, чтобы спустя месяц не требовалось вспоминать, из какого каталога он запускался и почему перестал отвечать после перезагрузки.

Для одного небольшого приложения обычно достаточно systemd: отдельный пользователь, корректный ExecStart, автозапуск, restart и журнал systemd.

Docker Compose удобнее, когда приложение уже контейнеризировано или состоит из нескольких связанных сервисов. В этом случае отдельно нужно продумать volumes, secrets и порядок обновления контейнеров.

В обоих вариантах остаются общие задачи: защита токена, сохранение рабочих данных, проверка логов, резервное копирование и реальный тест восстановления после reboot.

Что почитать дальше

Когда стоит обратиться к специалистам

С одним небольшим ботом без внешних зависимостей обычно можно справиться самостоятельно.

Сложность заметно растет, если бот связан с рабочей базой данных, платежами, CRM, очередями, несколькими worker-процессами или другими сервисами. В этом случае простой автоперезапуск не заменяет нормальную схему эксплуатации.

Когда стоит обратиться к специалистам: если остановка бота влияет на заказы, обращения клиентов или внутренние процессы компании, заранее продумайте не только запуск приложения, но и мониторинг, резервные копии, обновление и восстановление после сбоя.

Для такого сценария можно подобрать Linux VPS IPWAY под само приложение, базу данных и рабочую нагрузку, оставив небольшой запас ресурсов для обновлений и роста.

Кратко

  • Для работы 24/7 Telegram-бот должен запускаться как сервис, а не из открытого SSH-терминала.
  • Для одного простого бота systemd обычно проще, для контейнеризированного приложения или нескольких сервисов удобнее Docker Compose.
  • Токен Telegram нельзя хранить в исходном коде и публичном Git-репозитории.
  • Long polling и webhook нельзя одновременно использовать как два способа получения updates одного бота.
  • Автоматический restart восстанавливает процесс, но не исправляет ошибки приложения.
  • Логи нужно проверять даже тогда, когда systemd или Docker показывают работающий процесс.
  • Git не заменяет резервную копию базы данных и пользовательских файлов.
  • После настройки обязательно проверьте реальный reboot VPS и функциональный ответ бота.
Headscale на VPS объединяет Linux-сервер, ноутбук, смартфон и офисную сеть в защищённую mesh-сеть.
12.10.26
Headscale на VPS: как объединить серверы и устройства в собственную mesh-сеть

Когда в частной сети несколько серверов, рабочих компьютеров и мобильных устройств, ручное управление отдельными конфигурациями WireGuard быстро усложняется. Администратору приходится самостоятельно распределять ключи, учитывать адреса узлов,…

Автор: Редакция блога
Схема удалённого доступа к домашней или офисной сети без белого IP через Linux VPS и защищённый туннель за CGNAT.
05.10.26
Как получить удалённый доступ к домашней или офисной сети без белого IP

Нужно подключиться из Интернета к домашнему роутеру, NAS, компьютеру или серверу в офисе, но провайдер не выдаёт белый IP. Внутри локальной сети устройства работают, однако открыть…

Автор: Редакция блога
Зашифрованные удалённые резервные копии на VPS с хранением ежедневных, еженедельных и ежемесячных снимков и проверкой восстановления.
28.09.26
Удалённые резервные копии на VPS: restic или Borg, шифрование и проверка восстановления

Резервная копия на том же сервере, где находятся рабочие данные, помогает не во всех случаях. Если выйдет из строя диск, сервер окажется скомпрометирован или администратор случайно…

Автор: Редакция блога
Как выбрать VPS для Telegram-бота: подбор CPU, RAM и SSD для подходящей конфигурации сервера IPWAY.
25.09.26
Как выбрать VPS для Telegram-бота: CPU, RAM, диск и запас для роста

Telegram-бот может без проблем работать на ноутбуке разработчика, но для круглосуточной эксплуатации ему нужен сервер. На этом этапе возникает практический вопрос: какую конфигурацию VPS выбрать, чтобы…

Автор: Редакция блога
Единый IP для удалённой команды: домашние, офисные и мобильные сотрудники подключаются через Linux VPS к CRM и API с IP-whitelist
22.09.26
Постоянный IP для удалённых сотрудников: VPS как единая точка выхода для IP-whitelist

Доступ к CRM, API, базе данных или административной панели нередко ограничивают списком доверенных IP-адресов. Такой список называют IP-whitelist. Пока сотрудники работают из одного офиса, в него…

Автор: Редакция блога
Nginx как reverse proxy на VPS: HTTPS, заголовки и диагностика 502
21.09.26
Nginx как reverse proxy на VPS: HTTPS, заголовки и диагностика 502

Приложение на VPS может исправно отвечать на локальном порту, например 127.0.0.1:3000, но оставаться недоступным по домену. Открывать этот порт напрямую в интернет обычно не требуется: перед…

Автор: Редакция блога

Мы используем файлы cookie и сервис веб-аналитики Яндекс Метрика для улучшения работы сайта. Оставаясь на сайте, вы соглашаетесь с Политикой конфиденциальности.