Пошаговый туториал: от пустой папки до работающего бота на сервере
Если ты пишешь на Python и ещё не сделал ни одного Telegram-бота — ты теряешь деньги, время или удобство. Потому что бот — это самый быстрый способ автоматизировать что угодно: уведомления, напоминания, мини-сервисы для себя или клиентов.
Эта статья проведёт тебя от нуля до рабочего бота на сервере. Без воды, с реальным кодом.
Шаг 0. Что мы будем делать
Напишем бота, который:
- отвечает на команду /start
- принимает текстовое сообщение и отвечает на него
- умеет отправлять кнопки
Этого достаточно, чтобы понять механику. Дальше ты сам добавишь всё что нужно.
Инструменты: Python 3.10+, библиотека aiogram 3, сервер для запуска (или твой компьютер для тестирования).
Шаг 1. Создаём бота в Telegram — получаем токен
Открой Telegram, найди бота @BotFather. Это официальный бот для управления ботами.
Напиши ему /newbot. Он спросит:
- Имя бота — то, что видят пользователи. Например: Мой первый бот
- Username — уникальный идентификатор, обязательно заканчивается на bot. Например: myfirstbot_bot
После этого BotFather пришлёт токен — длинную строку вида:
7412345678:AAHxyz_abcdefghijklmnopqrstuvwxyz123
Это твой главный ключ. Не публикуй его нигде — кто угодно с этим токеном получает полный контроль над ботом.
Шаг 2. Настраиваем проект
Создай папку, сделай виртуальное окружение, установи библиотеку:
mkdir mybot && cd mybot
python3 -m venv venv
source venv/bin/activate # на Windows: venv\Scripts\activate
pip install aiogram
Почему aiogram, а не python-telegram-bot? Aiogram написан асинхронно — он умеет обрабатывать много запросов одновременно без тормозов. Для серьёзных проектов это критично. Для учебного — просто хорошая привычка.
Создай файл .env для хранения токена:
BOT_TOKEN=7412345678:AAHxyz_abcdefghijklmnopqrstuvwxyz123
И установи библиотеку для работы с .env:
pip install python-dotenv
Никогда не вставляй токен прямо в код. Это первое правило.
Шаг 3. Пишем первого бота
Создай файл bot.py:
import asyncio
import os
from dotenv import load_dotenv
from aiogram import Bot, Dispatcher, F
from aiogram.types import Message
from aiogram.filters import CommandStart, Command
load_dotenv()
bot = Bot(token=os.getenv("BOT_TOKEN"))
dp = Dispatcher()
@dp.message(CommandStart())
async def cmd_start(message: Message):
await message.answer(
f"Привет, {message.from_user.first_name}! Я работаю."
)
@dp.message(Command("help"))
async def cmd_help(message: Message):
await message.answer(
"Я умею:\n"
"/start — поздороваться\n"
"/help — показать это сообщение"
)
@dp.message(F.text)
async def echo(message: Message):
await message.answer(f"Ты написал: {message.text}")
async def main():
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())
Запусти:
python bot.py
Открой своего бота в Telegram, напиши /start. Он ответит.
Поздравляю — бот работает.
Шаг 4. Разбираемся что происходит
Несколько вещей, которые важно понять сразу.
Polling — это режим работы, при котором бот сам каждые несколько секунд спрашивает серверы Telegram: «есть ли новые сообщения?». Это удобно для разработки: не нужен публичный адрес и SSL. Для продакшена лучше webhook, но об этом позже.
Декораторы @dp.message(...) — это фильтры. Они говорят: «если пришло сообщение, которое соответствует условию, — вызови эту функцию». CommandStart() — фильтр на /start. F.text — фильтр на любое текстовое сообщение.
async/await — бот асинхронный. Пока он ждёт ответа от Telegram API, он может обрабатывать других пользователей. Если тебе непривычно — просто пиши await перед каждым вызовом метода бота, и всё будет работать.
Шаг 5. Добавляем кнопки
Кнопки делают бота живым. Есть два вида:
ReplyKeyboard — кнопки прикрепляются к полю ввода снизу, как на клавиатуре. Нажатие отправляет текст боту.
InlineKeyboard — кнопки прикрепляются к конкретному сообщению. Нажатие отправляет callback_query, а не текст.
Вот пример с inline-кнопками:
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
from aiogram.types import CallbackQuery
def get_main_keyboard():
buttons = [
[
InlineKeyboardButton(text="Вариант А", callback_data="choice_a"),
InlineKeyboardButton(text="Вариант Б", callback_data="choice_b"),
]
]
return InlineKeyboardMarkup(inline_keyboard=buttons)
@dp.message(CommandStart())
async def cmd_start(message: Message):
await message.answer(
"Выбери вариант:",
reply_markup=get_main_keyboard()
)
@dp.callback_query(F.data == "choice_a")
async def choice_a(callback: CallbackQuery):
await callback.message.edit_text("Ты выбрал вариант А")
await callback.answer() # убирает «часики» на кнопке
@dp.callback_query(F.data == "choice_b")
async def choice_b(callback: CallbackQuery):
await callback.message.edit_text("Ты выбрал вариант Б")
await callback.answer()
callback_data — это строка, которую ты придумываешь сам. По ней ты понимаешь, какую кнопку нажали. Делай её осмысленной: action_itemid — хорошо, btn1 — плохо.
Шаг 6. Хранение данных пользователя
Самый частый вопрос: как запомнить, что пользователь выбрал на предыдущем шаге?
Для простых случаев — MemoryStorage, который встроен в aiogram. Данные хранятся в памяти и сбрасываются при перезапуске бота.
Для серьёзного проекта — база данных. Самый простой вариант — SQLite через aiosqlite:
pip install aiosqlite
import aiosqlite
async def get_db():
return await aiosqlite.connect("bot.db")
async def save_user(user_id: int, username: str):
async with aiosqlite.connect("bot.db") as db:
await db.execute(
"INSERT OR IGNORE INTO users (id, username) VALUES (?, ?)",
(user_id, username)
)
await db.commit()
Создай таблицу при старте бота — и у тебя уже есть постоянное хранилище.
Шаг 7. Запускаем бота на сервере
На своём компьютере бот работает только пока открыт терминал. Чтобы он работал постоянно — нужен сервер.
Минимальный вариант — VPS с 1 ГБ RAM. Этого хватит на несколько ботов одновременно.
Загрузи файлы на сервер (через scp или git), создай окружение:
python3 -m venv venv
source venv/bin/activate
pip install aiogram python-dotenv
Создай .env с токеном прямо на сервере — не загружай его через git.
Теперь нужно, чтобы бот запускался автоматически и перезапускался при падении. Для этого используй systemd:
sudo nano /etc/systemd/system/mybot.service
Вставь:
[Unit]
Description=My Telegram Bot
After=network.target
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/mybot
EnvironmentFile=/home/ubuntu/mybot/.env
ExecStart=/home/ubuntu/mybot/venv/bin/python bot.py
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Активируй:
sudo systemctl daemon-reload
sudo systemctl enable mybot
sudo systemctl start mybot
Проверь что работает:
sudo systemctl status mybot
Теперь бот запускается при старте сервера и перезапускается сам, если упал.
Шаг 8. Частые ошибки, которые ломают всё
Токен в коде или в git. Если ты запушил токен на GitHub — немедленно перегенерируй его через BotFather командой /revoke. Боты с публичными токенами угоняют в течение минут.
Один экземпляр бота. Нельзя запускать два процесса с одним токеном одновременно — они будут перехватывать сообщения друг у друга. Перед запуском нового — останови старый.
Не вызван callback.answer(). Если не вызвать после обработки callback, у пользователя на кнопке будет висеть бесконечная загрузка. Всегда вызывай — даже если ответ пустой.
Блокирующий код в асинхронных функциях. Если внутри async def ты вызываешь что-то долгое и синхронное (например, обычный requests), бот зависает для всех пользователей. Используй httpx или aiohttp вместо requests.
Нет обработки исключений. Бот может упасть из-за любой непойманной ошибки. Оберни основную логику в try/except и хотя бы логируй ошибки в файл или отправляй себе в Telegram.
Что дальше
Этот бот — каркас. Дальше ты можешь добавить:
- FSM (машина состояний) — для многошаговых диалогов: регистрация, оформление заказа, опрос.
- Планировщик — apscheduler, чтобы бот отправлял сообщения по расписанию.
- Webhook вместо polling — быстрее и правильнее для продакшена, но требует публичного адреса с SSL.
- База данных — PostgreSQL через asyncpg для серьёзных проектов.
- Интеграции — погода, курсы валют, GPT, любой API — бот становится интерфейсом ко всему.
Телеграм-бот — это, наверное, самый быстрый путь от идеи до работающего инструмента в Python. Первый занимает час. Десятый — двадцать минут.
Пробуй.
Если что-то не получилось — напиши в комментарии, разберём. А если получилось — расскажи, что сделал. Интересно читать про реальные применения.