Как развернуть Telegram-бота на aiogram 3 и безопасно обновлять его
Запуск Telegram-бота на aiogram 3: Dockerfile, секреты, одна polling-реплика, безопасное обновление и проверка после перезапуска.
Бот отвечает на ноутбуке, но перестаёт работать, как только закрывается терминал. Следующий шаг — запустить его как постоянный процесс и проверить не только команду /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 ускорит обработку.
Диалоги, заказы и задания не должны существовать только в памяти. Перезапуск уничтожает такую память; временная файловая система контейнера также не заменяет базу или постоянный том. Для операций с внешним эффектом сохраняйте идентификатор события и результат обработки, чтобы повтор не создавал второй заказ.
Что проверить после запуска
- Отправьте
/startтестовому боту и сопоставьте время ответа с логами приложения. - Остановите локальную копию. Проверьте, что нет ошибок конфликта
getUpdates. - Перезапустите облачный процесс: бот должен вернуться без ручного ввода токена.
- Проверьте сценарий с сохранённым состоянием — например, продолжение диалога после перезапуска.
- Выполните обновление и откат на тестовом боте, наблюдая, сколько процессов использует токен.
Статус «процесс запущен» ещё не доказывает связь с Telegram. Следите за ошибками API, временем последнего успешно обработанного события и задержкой ответа. В логи достаточно писать идентификаторы и статусы; токен и содержимое личных сообщений туда помещать не нужно.
Дальше можно добавить очередь для тяжёлых операций: например, бот сразу подтверждает приём документа, а отдельный обработчик готовит результат. Начните с размещения Telegram-ботов, а надёжность повторов разберите в статье об идемпотентности.