Бот на aiogram 3: установка, первый Telegram-бот на Python и запуск на сервере

Ставим aiogram 3 через pip, получаем токен у BotFather и пишем бота на Python: команда /start, эхо, inline-кнопки, фото и анкета на машине состояний.

В конце запуск на сервере через systemd и таблица ошибок, из-за которых первый бот чаще всего не стартует.

Статью написал:
Ваня Буявец, продюсер, основатель Checkroi
Ваня Буявец
Основатель Checkroi, продюсер, эксперт в выборе онлайн-курсов
Все 3046 статей автора Подписаться на Телеграм-канал
Одобрено экспертом:
Наташа Буявец, основатель Checkroi, эксперт по онлайн-курсам
Наташа Буявец
Основательница Checkroi, продюсер Youtube-каналов, эксперт по онлайн-курсам
Все 3700 экспертных мнений Подписаться на Телеграм-канал
Обложка: Бот на aiogram 3: установка, первый Telegram-бот на Python и запуск на сервере

aiogram — асинхронный фреймворк на Python для Telegram Bot API. Чтобы собрать на нём бота, поставьте Python 3.10 или новее, выполните pip install -U aiogram, получите токен у @BotFather и запустите скрипт, где Dispatcher вызывает start_polling. Ниже рабочий код третьей версии: команда /start, эхо, inline-кнопки, анкета на машине состояний и запуск на сервере.

Если асинхронный код пока пугает, начните с бота на pyTelegramBotAPI: там те же шаги на синхронной библиотеке. aiogram берут, когда бот обслуживает много людей сразу и не должен ждать, пока Telegram ответит на каждый запрос.

Что такое aiogram и какая версия актуальна

Рой пишет Telegram-бота на Python

Библиотека построена на asyncio и aiohttp. Пока один запрос к серверам Telegram в пути, бот уже обрабатывает следующее сообщение. По странице пакета на PyPI, версия 3.31.0 вышла 26 августа 2026 года и работает на Python от 3.10 до 3.14.

Главное, что надо знать до первой строки кода: aiogram 2 и aiogram 3 несовместимы. Примеры с executor и @dp.message_handler, которые ещё встречаются в учебных материалах, написаны под вторую версию и на третьей падают сразу.

Что aiogram 2.x aiogram 3.x
Запуск опроса executor.start_polling(dp) await dp.start_polling(bot)
Обработчик сообщений @dp.message_handler() @router.message()
Хранилища состояний aiogram.contrib.fsm_storage aiogram.fsm.storage

Полный список переименований есть в руководстве по переходу с 2.x на 3.x из официальной документации.

Как установить aiogram и получить токен

  1. Проверьте версию Python: python3 --version на macOS и Linux, python --version на Windows. Нужна 3.10 или выше. Если Python нет, поставьте его по инструкции для Windows, macOS и Linux.
  2. Создайте папку проекта и виртуальное окружение, чтобы библиотеки бота не смешались с системными.
  3. Активируйте окружение и поставьте библиотеку из PyPI.
mkdir tgbot
cd tgbot
python3 -m venv .venv
source .venv/bin/activate      # Windows: .venv\Scripts\activate
pip install -U aiogram

Проверьте, что библиотека встала:

python -c "import aiogram; print(aiogram.__version__)"
3.31.0

Команда pip install -U aiogram взята из раздела Installation документации. Ключ -U обновит библиотеку, если старая версия уже стоит. Для хранения анкет в Redis понадобится дополнение: pip install -U "aiogram[redis]".

Если пишете в редакторе кода, выберите в нём интерпретатор из папки .venv. Иначе запуск из редактора закончится ошибкой ModuleNotFoundError, хотя в терминале всё работает. Как это сделать в одной из популярных сред, показано в настройке VS Code для Python.

Токен у BotFather и где его хранить

  1. Найдите в Telegram аккаунт @BotFather и отправьте ему /newbot.
  2. Придумайте имя бота и username. Username должен заканчиваться на bot.
  3. BotFather пришлёт токен вида 123456789:AAH…. Это ключ от бота: кто его знает, тот и управляет ботом.

Поэтому токен не пишут в код, особенно если код уйдёт на GitHub. Его кладут в переменную окружения, а скрипт читает её при старте:

export BOT_TOKEN="123456789:AAH..."      # macOS и Linux
$env:BOT_TOKEN="123456789:AAH..."        # Windows, PowerShell

Переменная живёт, пока открыт терминал. Закрыли окно, и перед запуском её придётся задать снова.

Канал основателя Checkroi Вани Буявца3 700 человек читают мой Телеграм-канал про нейросетиСобрал промпты для Claude Code и ChatGPT, разборы ИИ-инструментов и лайфхаки по продвижению бизнеса в одном местеПрисоединиться

Первый бот на aiogram 3: команда /start и эхо

Создайте файл bot.py. Этот бот здоровается по имени на /start и повторяет любой текст:

import asyncio
import logging
import os

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

router = Router()


@router.message(CommandStart())
async def cmd_start(message: Message) -> None:
    await message.answer(
        f"Привет, {message.from_user.first_name}! Пришлите текст, и я его повторю. "
        "Меню с кнопками: /menu"
    )


@router.message(F.text)
async def echo(message: Message) -> None:
    await message.answer(message.text)


async def main() -> None:
    logging.basicConfig(level=logging.INFO)
    bot = Bot(token=os.environ["BOT_TOKEN"])
    dp = Dispatcher()
    dp.include_router(router)
    await dp.start_polling(bot)


if __name__ == "__main__":
    asyncio.run(main())

Запустите его командой python bot.py. В терминале появится строка INFO:aiogram.dispatcher:Start polling, и бот начнёт отвечать. Остановить его можно сочетанием Ctrl+C.

Что здесь происходит:

  • Router собирает обработчики. В маленьком боте он один, в большом их делят по файлам: анкета отдельно, админка отдельно.
  • CommandStart() ловит /start, а F.text ловит любое текстовое сообщение.
  • message.answer() отправляет ответ в тот же чат. Перед ним стоит await, потому что метод асинхронный. Если async и await пока не складываются в картину, посмотрите курсы по асинхронному программированию.
  • Имя в приветствии подставляет f-строка: всё, что стоит в фигурных скобках, Python вычисляет и вставляет в текст.
  • dp.start_polling(bot) раз за разом спрашивает у Telegram новые сообщения. Пока скрипт работает, бот на связи.

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

CheckroiCheckroiПодборка курсов по Python567 курсов • 51 школаСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→

Кнопки и фото в боте на aiogram

Inline-кнопки под сообщением

Кнопки под сообщением собирают через InlineKeyboardBuilder. Добавьте в bot.py импорты и два обработчика нажатий. Код ставится выше эха:

from datetime import datetime

from aiogram.filters import Command
from aiogram.types import CallbackQuery
from aiogram.utils.keyboard import InlineKeyboardBuilder


@router.message(Command("menu"))
async def cmd_menu(message: Message) -> None:
    builder = InlineKeyboardBuilder()
    builder.button(text="Который час", callback_data="time")
    builder.button(text="Убрать кнопки", callback_data="hide")
    await message.answer("Что сделать?", reply_markup=builder.as_markup())


@router.callback_query(F.data == "time")
async def on_time(callback: CallbackQuery) -> None:
    await callback.answer(datetime.now().strftime("%H:%M"), show_alert=True)


@router.callback_query(F.data == "hide")
async def on_hide(callback: CallbackQuery) -> None:
    await callback.message.edit_reply_markup(reply_markup=None)
    await callback.answer()

Как это работает:

  • При нажатии бот получает не сообщение, а CallbackQuery со строкой из callback_data. По описанию InlineKeyboardButton, в ней от 1 до 64 байт, поэтому туда кладут короткий код действия, а не данные.
  • show_alert=True показывает ответ всплывающим окном. Без этого флага текст всплывёт уведомлением вверху чата.
  • edit_reply_markup(reply_markup=None) убирает клавиатуру из сообщения.
  • Обе кнопки встанут в один ряд. Чтобы разложить их по одной в строке, вызовите builder.adjust(1) перед as_markup().

callback.answer() вызывайте всегда, даже если отвечать нечего. В описании CallbackQuery сказано: после нажатия клиент Telegram показывает индикатор загрузки, пока бот не вызовет AnswerCallbackQuery.

Клавиатура под полем ввода и отправка фото

Inline-кнопки висят под конкретным сообщением. Есть второй вид: клавиатура вместо обычной, под полем ввода. Нажатие на такую кнопку просто отправляет её текст в чат, поэтому ловят его обычным фильтром по тексту.

from aiogram.types import FSInputFile, ReplyKeyboardRemove
from aiogram.utils.keyboard import ReplyKeyboardBuilder


@router.message(Command("photo"))
async def cmd_photo(message: Message) -> None:
    await message.answer_photo(FSInputFile("cat.jpg"), caption="Это кот")


@router.message(Command("ask"))
async def cmd_ask(message: Message) -> None:
    builder = ReplyKeyboardBuilder()
    builder.button(text="Да")
    builder.button(text="Нет")
    await message.answer(
        "Подписаться на рассылку?",
        reply_markup=builder.as_markup(resize_keyboard=True, one_time_keyboard=True),
    )


@router.message(F.text.in_({"Да", "Нет"}))
async def on_answer(message: Message) -> None:
    await message.answer(f"Ответ принят: {message.text}", reply_markup=ReplyKeyboardRemove())
  • FSInputFile отправляет файл с диска, путь считается от папки, откуда запущен скрипт, как и при открытии файла через open(). Для документа то же самое делает answer_document.
  • resize_keyboard=True подгоняет высоту клавиатуры под число рядов, без него она занимает столько же места, сколько обычная. one_time_keyboard=True прячет её после нажатия, вернуть можно значком в поле ввода. Оба флага описаны на странице ReplyKeyboardMarkup.
  • ReplyKeyboardRemove() убирает клавиатуру совсем, когда ответ получен.

Эти обработчики тоже ставятся выше эха, иначе «Да» и «Нет» бот просто повторит.

Анкета на машине состояний (FSM)

Шаги анкеты в боте: имя, город, готово

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

from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup


class Signup(StatesGroup):
    name = State()
    city = State()


@router.message(Command("signup"))
async def signup_start(message: Message, state: FSMContext) -> None:
    await state.set_state(Signup.name)
    await message.answer("Как вас зовут?")


@router.message(Signup.name, F.text)
async def signup_name(message: Message, state: FSMContext) -> None:
    await state.update_data(name=message.text)
    await state.set_state(Signup.city)
    await message.answer("Из какого вы города?")


@router.message(Signup.city, F.text)
async def signup_city(message: Message, state: FSMContext) -> None:
    data = await state.get_data()
    await state.clear()
    await message.answer(f"Записал: {data['name']}, {message.text}")

Signup — обычный класс Python, где каждое поле State() означает один шаг анкеты. Диалог выглядит так: /signup → «Как вас зовут?» → «Аня» → «Из какого вы города?» → «Казань» → «Записал: Аня, Казань». state.clear() в конце сбрасывает анкету, и следующее сообщение снова попадёт в эхо.

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

from aiogram.fsm.storage.redis import RedisStorage

dp = Dispatcher(storage=RedisStorage.from_url("redis://localhost:6379/0"))
CheckroiCheckroiПодборка курсов по асинхронному программированию19 курсов • 9 школСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→

Как запустить бота на сервере

Бот на вашем компьютере засыпает вместе с компьютером. Чтобы он отвечал круглосуточно, скрипт переносят на Linux-сервер. Получать сообщения можно двумя способами:

Способ Как работает Что нужно
Polling Бот сам спрашивает у Telegram новые сообщения, как в примерах выше Любой сервер, домен не нужен
Webhook Telegram сам присылает каждое обновление HTTPS-запросом с JSON на ваш адрес (метод SetWebhook) Домен с HTTPS и веб-сервер; готовый каркас есть в разделе Webhook

Для первого бота хватит polling. Скрипт оформляют службой systemd, чтобы он сам поднимался после сбоя и перезагрузки сервера. Файл службы и порядок команд разобраны в инструкции по боту на pyTelegramBotAPI, для aiogram меняется только одно. Наш код читает токен из переменной окружения, поэтому добавьте в раздел [Service] строку с файлом, где лежит токен:

[Service]
EnvironmentFile=/home/bot/tgbot/.env
ExecStart=/home/bot/tgbot/.venv/bin/python bot.py

В самом .env одна строка: BOT_TOKEN=123456789:AAH.... Права на файл лучше сразу ограничить: chmod 600 .env.

Ваня БуявецКанал основателя Checkroi Вани БуявцаЗабирайте промпты и обучение по нейросетям в моём Телеграм-каналеБольше 3 700 человек уже применяют Claude Code, ChatGPT и другие нейросети в работе, учёбе, бизнесе и жизниПерейти в канал

Частые ошибки и что с ними делать

Рой спокойно обходит ошибки с чек-листом

Большинство проблем с первым ботом укладывается в семь симптомов. Ищите в таблице текст из своего терминала:

Что видите Почему Что сделать
ModuleNotFoundError: No module named 'aiogram' Библиотека стоит в другом окружении, чем то, которым запускаете скрипт Активируйте .venv и выполните python -m pip install -U aiogram
ImportError: cannot import name 'executor' from 'aiogram' Код написан под aiogram 2 Запускайте через asyncio.run(main()) и await dp.start_polling(bot)
AttributeError: 'Dispatcher' object has no attribute 'message_handler' Тоже код второй версии Замените декоратор на @router.message()
TokenValidationError: Token is invalid! В переменной не токен: пусто, лишний пробел, обрезана часть Скопируйте токен из чата с BotFather заново
TelegramUnauthorizedError: Telegram server says - Unauthorized Токен правильного вида, но Telegram его не принимает: опечатка или токен отозван Возьмите действующий токен у @BotFather
TelegramConflictError Тот же токен уже опрашивает другая копия бота Оставьте одну запущенную копию: на сервере или на ноутбуке
Кнопка нажата, а на ней крутится загрузка Обработчик не вызвал callback.answer() или нет обработчика под эту callback_data Добавьте await callback.answer() и сверьте строки в кнопке и в фильтре F.data

С ModuleNotFoundError разбираются одинаково для любой библиотеки. Как выбрать правильное окружение, подробно рассказано в разборе той же ошибки в инструкции по установке PyGame.

Если бот молчит без всяких ошибок, проверьте две вещи. Отправляете ли вы текст, а не стикер: эхо ловит только F.text. И не стоит ли обработчик ниже эха.

CheckroiCheckroiПодборка курсов по чат-ботам160 курсов • 42 школыСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→

Где освоить Python, чтобы бот вырос

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

Если хотите учиться с проверкой заданий и наставником, ниже курсы из каталога по Python:

КурсШколаСтоимость со скидкойВ рассрочкуДлитель­ностьОбзор курса от Checkroi
Профессия «Python-разработчик»
Перейти на сайт курса
SkillboxSkillbox157 335 ₽5987 ₽/мес.10 месяцевОбзор курса
Fullstack-разработчик на Python
Перейти на сайт курса
НетологияНетология137 000 ₽7125 ₽/мес.21 месяцОбзор курса
ДО Профессия Python-разработчик
Перейти на сайт курса
GeekBrainsGeekBrains149 001 ₽3167 ₽/мес.10 месяцевОбзор курса
Автоматизированное тестирование на Python
Перейти на сайт курса
SkillboxSkillbox122 226 ₽4108 ₽/мес.9 месяцевОбзор курса
Профессия Python-разработчик
Перейти на сайт курса
SkillFactorySkillFactory154 044 ₽4279 ₽/мес.10 месяцевОбзор курса

Больше программ — в полном каталоге курсов по Python

Часто задаваемые вопросы

Что такое aiogram?

Асинхронный фреймворк на Python для Telegram Bot API, построенный на asyncio и aiohttp. Пока один запрос к Telegram в пути, бот уже обрабатывает следующее сообщение, поэтому aiogram выбирают для ботов, у которых много пользователей одновременно. Если хотите делать таких ботов за деньги, посмотрите курсы для разработчиков Telegram-ботов.

Как установить aiogram?

Создайте виртуальное окружение, активируйте его и выполните pip install -U aiogram. Нужен Python 3.10 или новее. Проверить установку можно командой python -c "import aiogram; print(aiogram.__version__)".

Почему код из старого урока по aiogram не запускается?

Скорее всего, урок написан под aiogram 2. В третьей версии нет executor и @dp.message_handler: бота запускают через await dp.start_polling(bot), а обработчики вешают на @router.message().

Есть ли документация aiogram на русском?

Официальная документация на docs.aiogram.dev выходит на английском и украинском. На русском есть бесплатная книга «Пишем Telegram-ботов с aiogram 3.x», она начинается с установки и первого бота.

Чем aiogram отличается от pyTelegramBotAPI?

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

Почему бот на aiogram не отвечает?

Проверьте, что запущена одна копия бота с этим токеном, что обработчик эха стоит последним и что после нажатия inline-кнопки вызывается callback.answer(). Если в терминале есть ошибка, найдите её текст в таблице частых ошибок выше.

Читайте Checkroi первым в Google
Добавьте Checkroi в избранные источники — и наши разборы курсов и обзоры школ будут показываться выше в вашей выдаче Google.
Оставить комментарий
0 комментариев
Форма комментария

Оставьте комментарий

Напишите, что думаете. Нам важно ваше мнение!