> Полный список статей есть в [llms.txt](https://docs.f3cloud.com/llms.txt). Markdown-версия есть у каждой страницы, достаточно добавить .md к её адресу. Эта страница в Markdown: [https://docs.f3cloud.com/ru/docker/telegram-bot-vps.md](https://docs.f3cloud.com/ru/docker/telegram-bot-vps.md).

# Telegram-бот на VPS – запуск на Python, автозапуск через systemd и частые ошибки

Как запустить Telegram-бота на VPS. Создание бота в BotFather, Python и aiogram в виртуальном окружении, безопасное хранение токена, автозапуск через systemd, логи и частые ошибки Unauthorized и Conflict. Проверено на Debian 12 с Python 3.11 и aiogram 3.31.

Пока бот работает на домашнем компьютере, он отвечает, только когда компьютер включён. На VPS бот работает круглосуточно, переживает перезагрузки и не зависит от вашего интернета. В этой статье мы создадим бота в Telegram, запустим его на сервере на Python с библиотекой **aiogram**, настроим автозапуск через systemd и разберём ошибки, которые встречаются чаще всего. В качестве примера возьмём простого бота, который здоровается и повторяет сообщения, а свой код вы потом подставите на его место. Все шаги мы проверили на тестовом сервере с Debian 12, Python **3.11** и aiogram **3.31**.

***

## Как бот получает сообщения

Бот в Telegram – это обычная программа, которая общается с серверами Telegram через Bot API. Пользователь пишет боту, сообщение попадает на серверы Telegram и ждёт там, пока программа бота его заберёт. По документации Telegram, есть два способа получать такие сообщения, и одновременно можно использовать только один. Первый способ называется **polling**. Бот сам постоянно спрашивает у Telegram, нет ли новых сообщений. Второй способ, **webhook**, работает наоборот. Telegram сам отправляет каждое сообщение на адрес вашего сервера, и для этого нужен домен с HTTPS.

Для бота на VPS проще всего polling. Ему не нужны домен, сертификат и открытые порты, ведь соединение всегда начинает сам бот. На нашем тестовом сервере был включён брандмауэр UFW без единого правила для бота, и бот работал. Сообщения, которые пришли, пока бот был выключен, Telegram хранит до 24 часов, так что после короткого перезапуска бот их получит.

Доступ к боту даёт **токен**, длинная строка, которую выдаёт BotFather. Кто знает токен, тот полностью управляет ботом. Поэтому токен не пишут прямо в код и не выкладывают вместе с ним на GitHub, а хранят в отдельном файле, который может прочитать только root.

***

## Что понадобится

* **Сервер** с Debian 12 или Ubuntu 24.04. Простому боту хватит самого маленького тарифа, например **DE-Promo**. Если сервера ещё нет, закажите его по [инструкции](https://docs.f3cloud.com/ru/client-area/order-vps.md).
* **Подключение по SSH**, например через [Termius](https://docs.f3cloud.com/ru/vps/termius-connection.md). Команды выполняются от имени `root`.
* **Аккаунт в Telegram**, чтобы создать бота.

***

## Шаг 1. Создайте бота в BotFather

1. Откройте в Telegram бота **@BotFather** и отправьте ему команду `/newbot`.
2. Введите имя бота. Его увидят пользователи, имя может быть любым.
3. Введите адрес бота. Он должен заканчиваться на `bot`, например `my_shop_bot`.
4. BotFather пришлёт ссылку на бота и **токен** под строкой **Use this token to access the HTTP API**. Скопируйте токен и никому его не показывайте.

<figure><img src="https://docs.f3cloud.com/img/telegram-botfather-token.png" alt="Ответ BotFather после создания бота, ссылка на бота и токен, токен скрыт"><figcaption><p>Бот создан, токен скрыт</p></figcaption></figure>

> **Если токен попал в чужие руки.**
>
> Отзовите его командой `/revoke` в BotFather, а затем замените токен на сервере в файле `/etc/tgbot.env` и перезапустите бота.

***

## Шаг 2. Подготовьте сервер

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

```bash
useradd -r -m -d /opt/tgbot -s /bin/bash tgbot
apt install -y python3-venv
```

Пакет `python3-venv` нужен для виртуального окружения, отдельной папки с библиотеками только для этого бота. В нашем образе Debian 12 его по умолчанию нет.

Перейдите в пользователя бота, создайте окружение и установите aiogram.

```bash
su - tgbot
python3 -m venv venv
venv/bin/pip install aiogram
```

В конце установки появится строка **Successfully installed** со списком пакетов, среди них `aiogram`.

***

## Шаг 3. Напишите код бота

Создайте файл с кодом.

```bash
nano bot.py
```

Вставьте в него пример ниже и сохраните сочетанием <kbd>Ctrl</kbd> + <kbd>O</kbd>, затем <kbd>Enter</kbd>, а выйдите сочетанием <kbd>Ctrl</kbd> + <kbd>X</kbd>.

```python
import asyncio
import logging
import os

from aiogram import Bot, Dispatcher
from aiogram.filters import CommandStart
from aiogram.types import Message

dp = Dispatcher()

@dp.message(CommandStart())
async def start(message: Message):
    # ответ на команду /start
    await message.answer(f"Привет, {message.from_user.first_name}! Я работаю на VPS. Напишите что-нибудь, и я повторю.")

@dp.message()
async def echo(message: Message):
    # повторяем любое другое сообщение
    await message.send_copy(chat_id=message.chat.id)

async def main():
    bot = Bot(token=os.environ["BOT_TOKEN"])
    await dp.start_polling(bot)

if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO)
    asyncio.run(main())
```

Обратите внимание, что токена в коде нет. Бот берёт его из переменной окружения `BOT_TOKEN`.

***

## Шаг 4. Проверьте бота вручную

Перед тем как настраивать автозапуск, убедитесь, что бот работает. Команда `read -s` спросит токен и не покажет его на экране, поэтому он не останется в истории команд. Вставьте токен и нажмите <kbd>Enter</kbd>.

```bash
read -s -p "Токен: " BOT_TOKEN; export BOT_TOKEN
venv/bin/python bot.py
```

Если всё в порядке, появятся строки **Start polling** и **Run polling for bot** с адресом вашего бота.

<figure><img src="https://docs.f3cloud.com/img/telegram-bot-run.png" alt="Бот на aiogram запущен, строки Start polling и Run polling for bot, два обработанных сообщения"><figcaption><p>Бот запущен и обработал два сообщения</p></figcaption></figure>

Откройте бота в Telegram по ссылке от BotFather, отправьте ему `/start`, а затем любое сообщение.

<figure><img src="https://docs.f3cloud.com/img/telegram-bot-chat.png" alt="Переписка с ботом в Telegram, бот поздоровался и повторил сообщение"><figcaption><p>Бот отвечает на /start и повторяет сообщения</p></figcaption></figure>

Остановите бота сочетанием <kbd>Ctrl</kbd> + <kbd>C</kbd> и вернитесь в `root` командой `exit`.

***

## Шаг 5. Настройте автозапуск

Сейчас бот работает, только пока открыт терминал. Оформим его как службу systemd, тогда он будет запускаться вместе с сервером и подниматься после сбоев. Подробнее о службах рассказано в статье про [systemd](https://docs.f3cloud.com/ru/linux/systemd-services.md).

Сначала сохраните токен в файл, который может прочитать только `root`. Замените `ВАШ_ТОКЕН` на токен от BotFather.

```bash
echo "BOT_TOKEN=ВАШ_ТОКЕН" > /etc/tgbot.env
chmod 600 /etc/tgbot.env
```

Затем создайте службу.

```bash
nano /etc/systemd/system/tgbot.service
```

```ini
[Unit]
Description=Telegram bot
After=network-online.target
Wants=network-online.target

[Service]
User=tgbot
WorkingDirectory=/opt/tgbot
EnvironmentFile=/etc/tgbot.env
ExecStart=/opt/tgbot/venv/bin/python bot.py
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
```

Строка `EnvironmentFile` передаёт боту токен из файла. systemd читает этот файл от имени `root` ещё до запуска бота, поэтому самому пользователю `tgbot` доступ к нему не нужен.

Включите автозапуск и запустите бота.

```bash
systemctl daemon-reload
systemctl enable --now tgbot
systemctl status tgbot
```

<figure><img src="https://docs.f3cloud.com/img/telegram-bot-status.png" alt="systemctl status tgbot, служба active (running), процесс python bot.py"><figcaption><p>Бот работает как служба</p></figcaption></figure>

На нашем сервере служба с этим ботом занимала около 150 МБ памяти по данным `systemctl status`.

***

## Как обновлять бота и смотреть логи

* **Изменили код.** Отредактируйте `/opt/tgbot/bot.py` и перезапустите службу командой `systemctl restart tgbot`.
* **Добавили библиотеку.** Установите её в окружение бота командой `su - tgbot -c "venv/bin/pip install имя"` и перезапустите службу.
* **Логи.** Всё, что бот пишет в консоль, попадает в журнал. Последние строки показывает `journalctl -u tgbot -n 50`, а следить в реальном времени можно командой `journalctl -u tgbot -f`. Подробнее о журнале рассказано в статье про [логи Linux](https://docs.f3cloud.com/ru/linux/linux-logs.md).

***

## Частые вопросы

<details>

<summary>The virtual environment was not created successfully because ensurepip is not available</summary>

Не установлен пакет `python3-venv`. Мы получили эту ошибку на чистом Debian 12. Установите пакет командой `apt install -y python3-venv`, удалите неудачную папку командой `rm -rf venv` и создайте окружение заново.

<figure><img src="https://docs.f3cloud.com/img/telegram-bot-venv-error.png" alt="Ошибка python3 -m venv: ensurepip is not available, нужно установить python3-venv"><figcaption><p>Python подсказывает, какой пакет установить</p></figcaption></figure>

</details>

<details>

<summary>TelegramUnauthorizedError: Telegram server says - Unauthorized</summary>

Telegram не принял токен. Скорее всего, он скопирован не полностью или с лишним пробелом, либо был отозван командой `/revoke`. Проверьте строку в `/etc/tgbot.env` или получите новый токен у BotFather.

<figure><img src="https://docs.f3cloud.com/img/telegram-bot-unauthorized.png" alt="Ошибка aiogram TelegramUnauthorizedError: Telegram server says - Unauthorized"><figcaption><p>Так выглядит ответ Telegram на неверный токен</p></figcaption></figure>

</details>

<details>

<summary>TelegramConflictError: terminated by other getUpdates request</summary>

С этим токеном одновременно работают две копии бота. Мы получили эту ошибку, когда запустили бота вручную, пока работала служба. Обычно вторая копия осталась в другом окне терминала, в `screen` или на другом сервере. Остановите лишнюю копию. Когда она завершилась, служба на нашем сервере снова подключилась сама.

<figure><img src="https://docs.f3cloud.com/img/telegram-bot-conflict.png" alt="Ошибка TelegramConflictError: make sure that only one bot instance is running"><figcaption><p>Telegram требует, чтобы работала только одна копия бота</p></figcaption></figure>

</details>

<details>

<summary>ModuleNotFoundError: No module named 'aiogram'</summary>

Бот запущен системным Python, а не Python из окружения. Мы получили эту ошибку, запустив бота командой `python3 bot.py`. Запускайте его командой `venv/bin/python bot.py`, а в службе указывайте полный путь `/opt/tgbot/venv/bin/python`.

</details>

<details>

<summary>Бот не отвечает</summary>

1. Проверьте, что служба работает, командой `systemctl status tgbot`.
2. Посмотрите последние строки журнала командой `journalctl -u tgbot -n 50`. Там будет ошибка, из-за которой бот остановился.
3. Убедитесь, что не запущена вторая копия бота с тем же токеном.

</details>

***

## Наши ресурсы

**Telegram-канал:** [https://t.me/f3cloud_news](https://t.me/f3cloud_news)\
**Официальный сайт:** [https://f3cloud.com](https://f3cloud.com/ru)
