Как развернуть Telegram-бота на aiogram 3 и безопасно обновлять его

Запуск Telegram-бота на aiogram 3: Dockerfile, секреты, одна polling-реплика, безопасное обновление и проверка после перезапуска.

Как развернуть Telegram-бота на aiogram 3 и безопасно обновлять его

Бот отвечает на ноутбуке, но перестаёт работать, как только закрывается терминал. Следующий шаг — запустить его как постоянный процесс и проверить не только команду /start, но и обновления, секреты и восстановление после сбоя.

Разберём небольшой бот на aiogram 3 с long polling. Такой вариант не требует публичного HTTP-адреса: приложение само обращается к Telegram. Для первого бота это позволяет обойтись без настройки входящих вебхуков.

Polling или webhook: сначала выберите способ доставки

Вопрос Long polling Webhook
Кто устанавливает соединение Бот обращается к Telegram Telegram обращается к вашему HTTPS-адресу
Нужен публичный HTTP endpoint Нет Да
Как запускать обработчики Один polling-процесс на токен Несколько обработчиков за маршрутизацией, с общим состоянием
Что учитывать при обновлении Не допускать двух poller одновременно Проверять подлинность запросов и повторную доставку

Ограничение одного polling-процесса относится к одному токену, а не к серверу целиком. Локальный бот и облачная копия с одинаковым токеном тоже конфликтуют. Это поведение описано в документации aiogram.

Если бот уже использует webhook, сначала спланируйте переключение. Не добавляйте безусловный delete_webhook(drop_pending_updates=True) в каждый запуск: так можно незаметно потерять ожидающие события.

Минимальный бот без токена в исходниках

Создайте bot.py:

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):
    await message.answer("Бот работает. Можно добавлять команды.")


async def main():
    async with Bot(token=os.environ["BOT_TOKEN"]) as bot:
        webhook = await bot.get_webhook_info()
        if webhook.url:
            raise RuntimeError("Webhook is configured; plan the switch to polling first")
        await dp.start_polling(bot)


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

Отсутствующий BOT_TOKEN завершит процесс с понятной ошибкой вместо запуска неработающего сервиса. Токен задаётся через переменные приложения; не включайте его в Git, Dockerfile или пример команды, который попадёт в историю терминала.

В requirements.txt для знакомства с примером достаточно aiogram>=3,<4. Перед рабочим релизом зафиксируйте конкретную проверенную версию и зависимости lock-файлом: диапазон версий сам по себе не обеспечивает повторяемую сборку.

Упакуйте процесс в контейнер

FROM python:3.12-slim
ENV PYTHONUNBUFFERED=1 PYTHONDONTWRITEBYTECODE=1
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN useradd --create-home app
COPY --chown=app:app bot.py .
USER app
CMD ["python", "bot.py"]

Добавьте в .dockerignore как минимум .git, .env, .venv и __pycache__. Не задавайте HTTP-порт только ради формы деплоя: этот бот не запускает веб-сервер. Его рабочий режим — постоянный процесс с исходящим доступом к Telegram.

В Inquir Compute создайте приложение в проекте, добавьте BOT_TOKEN в переменные, выберите постоянный запуск и одну реплику. Соберите исходники с Dockerfile или используйте готовый образ. Публичный домен для polling не нужен. Общий порядок работы с релизами описан в документации приложений; готовая отправная точка есть в репозитории примеров.

Обновление: одна реплика ещё не исключает конфликт

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

Для небольшого бота допустимо запланировать короткую паузу: остановить старый polling-процесс, убедиться, что локальная копия тоже выключена, затем запустить новый. Если нужен непрерывный приём с несколькими обработчиками, переходите к webhook и храните состояние вне процессов. Не рассчитывайте, что увеличение числа реплик polling ускорит обработку.

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

Что проверить после запуска

  1. Отправьте /start тестовому боту и сопоставьте время ответа с логами приложения.
  2. Остановите локальную копию. Проверьте, что нет ошибок конфликта getUpdates.
  3. Перезапустите облачный процесс: бот должен вернуться без ручного ввода токена.
  4. Проверьте сценарий с сохранённым состоянием — например, продолжение диалога после перезапуска.
  5. Выполните обновление и откат на тестовом боте, наблюдая, сколько процессов использует токен.

Статус «процесс запущен» ещё не доказывает связь с Telegram. Следите за ошибками API, временем последнего успешно обработанного события и задержкой ответа. В логи достаточно писать идентификаторы и статусы; токен и содержимое личных сообщений туда помещать не нужно.

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