Запускаем Telegram Bot на локальном сервере
При разработке Telegram ботов многие сталкиваются с ограничениями официального Bot API: лимиты на размер файлов, ограниченные возможности вебхуков и другие технические барьеры. В этом руководстве я покажу, как развернуть собственный сервер Telegram Bot API, который даст вам полный контроль над работой бота и избавит от этих ограничений.
Преимущества локального Bot API сервера
Запуск собственного сервера Telegram Bot API дает несколько ключевых преимуществ:
- Загрузка файлов до 2000 МБ (вместо стандартных 50 МБ)
- Использование локальных путей для файлов через URI схему
- Гибкая настройка вебхуков:
- Возможность использовать HTTP (не только HTTPS)
- Любые локальные IP-адреса и порты
- До 100000 соединений (max_webhook_connections)
- Прямой доступ к файлам через локальные пути (без дополнительной загрузки через getFile)
Установка и настройка Telegram Bot API сервера
Исходный код доступен на GitHub: https://github.com/tdlib/telegram-bot-api
Инструкции по сборке https://tdlib.github.io/telegram-bot-api/build.html?os=Linux
clang:
apt-get update
apt-get upgrade
apt-get install make git zlib1g-dev libssl-dev gperf cmake clang-18 libc++-18-dev libc++abi-18-dev
git clone --recursive https://github.com/tdlib/telegram-bot-api.git
cd telegram-bot-api
rm -rf build
mkdir build
cd build
CXXFLAGS="-stdlib=libc++" CC=/usr/bin/clang-18 CXX=/usr/bin/clang++-18 cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr/local ..
cmake --build . --target install
cd ../..
ls -l /usr/local/bin/telegram-bot-api*
После сборки проверяем работу бинарного файла:
telegram-bot-api --help
Регистрация Telegram приложения
Для работы API сервера необходимо зарегистрировать приложение в Telegram:
- Перейдите на my.telegram.org
- Войдите с вашим номером телефона (потребуется код подтверждения)
- В разделе "API development tools" заполните форму:
- Укажите название и короткое имя приложения
- Сохраните полученные
api_id
иapi_hash
Регистрация приложения:
Запуск сервера
Запустим Telegram API сервер в локальном режиме.
Запускаем сервер с нашими параметрами:
telegram-bot-api --local --api-id=YOUR_API_ID --api-hash=YOUR_API_HASH --http-port=8081
По умолчанию сервер слушает на всех интерфейсах (0.0.0.0:8081).
Настройка автозапуска (Systemd)
Создаем файл сервиса/etc/systemd/system/telegram-bot-api.service
:
[Unit]
Description=Telegram Bot API Server
After=network.target network-online.target nss-lookup.target
[Service]
Type=simple
ExecStart=/usr/local/bin/telegram-bot-api --local --api-id=<api_id> --api-hash=<api_hash> --http-port=8081
Restart=always
TimeoutStartSec=10
TimeoutStopSec=10
[Install]
WantedBy=multi-user.target
Активируем сервис:
systemctl start telegram-bot-api
systemctl enable telegram-bot-api
systemctl status telegram-bot-api
Создание и настройка бота
Создадим бота:
- Найдите в Telegram
@BotFather
- Отправьте команду
/newbot
и следуйте инструкциям - Сохраните полученный токен бота (формат:
123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
)
Отвязываем бота от облачного сервера
curl https://api.telegram.org/bot<BOT_TOKEN>/logOut
Получаем chat ID:
curl https://api.telegram.org/bot<BOT_TOKEN>/getUpdates | jq 'result[].message.chat.id'
Установка и запуск бота
Устанавливаем зависимости:
pip install python-telegram-bot yt-dlp
Если возникает ошибка externally-managed-environment
, удалите файл:
rm /usr/lib/python3.12/EXTERNALLY-MANAGED
Создаем исполняемый файл бота (/usr/local/bin/your_bot.py):
#!/usr/bin/env python3
# Telegram Bot for downloading YouTube audio.
# Requirements:
## Telegram Bot API Server: https://github.com/tdlib/telegram-bot-api/
## System packages: ffmpeg
## Python packages: python-telegram-bot, yt-dlp
import logging
import os
from pathlib import Path
from typing import Optional
import yt_dlp
from telegram import Update, InputFile
from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler, Application
# Configure logging
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO
)
logger = logging.getLogger(__name__)
# List of allowed user IDs (replace with your actual allowed users)
ALLOWED_USERS = {
123807789, # Example user ID 1
000000000 # Example user ID 2
}
BOT_TOKEN = "token"
FFMPEG_PATH = "/usr/bin/ffmpeg" # Default ffmpeg path on Ubuntu
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Send a welcome message when the command /start is issued."""
user = update.effective_user
user_id = user.id if user else None
try:
await update.message.reply_html(
rf"Hi {user.mention_html()}! Your user ID is: {user_id}. I'm a bot running in {'local' if LOCAL_MODE else 'normal'} mode. \n"
"Available commands:\n"
"/start - Show this message\n"
"/help - Show help information\n"
"/downloadyoutubeaudio url - Download audio from YouTube"
)
except Exception as e:
logger.error(f"Cannot send start message: {e}")
await update.message.reply_text(f"Sorry, I couldn't send the welcome message: {e}")
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Show help information."""
await update.message.reply_text(
"Available commands:\n"
"/start - Show welcome message\n"
"/help - Show this help\n"
"/downloadyoutubeaudio <url> - Download audio from YouTube\n\n"
"Example:\n"
"/downloadyoutubeaudio https://www.youtube.com/watch?v=dQw4w9WgXcQ"
)
async def downloadyoutubeaudio(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
user = update.effective_user
# Check if user is allowed
if not user or user.id not in ALLOWED_USERS:
await update.message.reply_text(
chat_id=update.effective_chat.id,
text="?? Sorry, you don't have permission to use this command."
)
return
url = update.message.text.split()[1] if update.message.text else None # Assuming the URL is sent as a message
# Validate URL
if 'youtube.com' not in url and 'youtu.be' not in url:
await update.message.reply_text("Please provide a valid YouTube URL.")
return
# Set up yt-dlp options
ydl_opts = {
'format': 'bestaudio/best',
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '0', # Best quality
}],
'ffmpeg_location': '/usr/bin/ffmpeg', # Default ffmpeg path on Ubuntu
'outtmpl': '%(title)s.%(ext)s',
'download_archive': None, # Don't record downloaded videos
'external_downloader_args': {
'ffmpeg_i': ['-reconnect', '1', '-reconnect_streamed', '1', '-reconnect_delay_max', '5']
}
}
try:
# Send "processing" message
processing_msg = await update.message.reply_text("Downloading audio...")
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(url, download=True)
filename = ydl.prepare_filename(info)
# The actual file will have the mp3 extension
mp3_filename = os.path.splitext(filename)[0] + '.mp3'
if mp3_filename:
# Send the audio file
with open(mp3_filename, 'rb') as audio_file:
await update.message.reply_audio(
audio=audio_file,
title=info.get('title', 'audio'),
performer=info.get('uploader', 'unknown artist'),
duration=info.get('duration', 0)
)
# Delete the temporary file
os.remove(mp3_filename)
# Update processing message
await processing_msg.edit_text("Audio sent successfully!")
except Exception as e:
logger.error(f"Error downloading video: {e}")
await update.message.reply_text(f"Sorry, I couldn't download that video. Error: {e}")
# If processing message exists, update it with error
if 'processing_msg' in locals():
await processing_msg.edit_text(f"Sorry, I couldn't download that video. Error: {e}"
)
if __name__ == '__main__':
"""Start the bot."""
application = ApplicationBuilder().token(BOT_TOKEN).base_url("http://localhost:8081/bot").build()
# Register command handlers
application.add_handler(CommandHandler('start', start))
application.add_handler(CommandHandler("help", help_command))
application.add_handler(CommandHandler("downloadyoutubeaudio", downloadyoutubeaudio))
logger.info("Bot is starting...")
application.run_polling()
Делаем файл исполняемым:
chmod +x your_bot.py
Запускаем бота:
./your_bot.py
Устанавливаем пакет для конвертации:
apt install ffmpeg
Настройка автозапуска бота (Systemd)
Создаем файл /etc/systemd/system/telegram-bot.service
:
[Unit]
Description=Telegram Bot
After=network.target network-online.target nss-lookup.target
[Service]
Type=simple
ExecStart=/usr/local/bin/your_bot.py
Restart=always
TimeoutStartSec=10
TimeoutStopSec=10
[Install]
WantedBy=multi-user.target
Активируем сервис:
systemctl start telegram-bot
systemctl enable telegram-bot
systemctl status telegram-bot
Немного про сетевую связность
Важно отметить, что:
- Бот подключается только к локальному Bot API серверу (порт 8081)
- Bot API сервер взаимодействует с серверами Telegram
- Рекомендуется ограничить внешний доступ к порту 8081 через фаерволл
Итоги
В результате мы: - Развернули локальный Bot API сервер как systemd-сервис - Зарегистрировали приложение в Telegram - Создали и настроили бота через @BotFather - Запустили бота как systemd-сервис