Свой прокси для Telegram Bot API на nginx
Небольшой гайд, как поднять собственный домен-обёртку над api.telegram.org на своём nginx, без Cloudflare Workers и без единой строчки кода. Идея взята из проекта telegram-bot-api-worker, но реализована средствами самого nginx — воркер там на деле делает одну вещь: подменяет хост в запросе и проксирует его дальше как есть. То же самое proxy_pass умеет из коробки.
Зачем это нужно
api.telegram.orgу части провайдеров/стран заблокирован или тормозит — свой домен на нормальном хостинге снимает эту проблему- Красивый и предсказуемый адрес вида
https://ваш-домен/api/bot<token>/<method>вместоapi.telegram.org - Можно повесить перед прокси логирование, rate-limit, IP-allowlist для вебхуков и т.д. — то, чего у голого Telegram API нет
Что понадобится
- Сервер с nginx
- Домен (или поддомен), указывающий на этот сервер
- Выпущенный TLS-сертификат (в примерах — Let's Encrypt / certbot)
Итоговый результат
Запрос вида
https://api.telegram.org/bot123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11/getMe
начинает работать через ваш домен:
https://ваш-домен/api/bot123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11/getMe
и отдаёт ровно тот же ответ — метод, тело запроса, заголовки и файлы (для sendPhoto/sendDocument) прокидываются как есть.
Шаг 1. DNS
Создайте A-запись поддомена (например, bot-api.example.com) на IP вашего сервера. Дайте записи немного времени на распространение перед выпуском сертификата.
Шаг 2. Сертификат
sudo certbot certonly --nginx -d bot-api.example.com
Если у вас уже есть сайт на этом же домене/поддомене с действующим сертификатом — этот шаг можно пропустить и использовать существующие пути к сертификату.
Шаг 3. Конфиг nginx
Замените bot-api.example.com на свой домен.
server {
listen 80;
server_name bot-api.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name bot-api.example.com;
ssl_certificate /etc/letsencrypt/live/bot-api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/bot-api.example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location /api/bot {
# /api/bot123:ABC.../getMe -> /bot123:ABC.../getMe
rewrite ^/api/(bot.*)$ /$1 break;
proxy_pass https://api.telegram.org;
proxy_ssl_server_name on;
proxy_http_version 1.1;
proxy_set_header Host api.telegram.org;
proxy_set_header Connection "";
client_max_body_size 50m; # sendDocument / sendPhoto — Telegram принимает файлы до 50 МБ
proxy_read_timeout 60s;
}
location / {
return 404;
}
}
Почему конфиг устроен именно так
| Директива | Зачем |
|---|---|
location /api/bot |
Ловит только запросы к боту, не пересекается с остальным сайтом на этом же домене |
rewrite ^/api/(bot.*)$ /$1 break |
Убирает /api спереди, оставляя оригинальный путь /bot<token>/<method>, который ждёт Telegram |
proxy_set_header Host api.telegram.org |
Обязательно: без этого nginx отправит апстриму Host: bot-api.example.com, и Telegram не поймёт запрос |
proxy_ssl_server_name on |
Корректный SNI при TLS-соединении к api.telegram.org |
client_max_body_size 50m |
Иначе загрузка файлов через бота будет обрываться на лимите по умолчанию (1 МБ) |
| тело, метод, заголовки | Прокидываются как есть — proxy_pass копирует запрос без изменений, JSON и multipart работают одинаково |
Если у вас на этом домене уже есть сайт — просто добавьте location /api/bot { ... } в существующий server { listen 443 ssl ... } блок, ничего дублировать не нужно.
Применить конфиг:
sudo nginx -t && sudo systemctl reload nginx
Шаг 4. Проверка
curl "https://bot-api.example.com/api/bot<TOKEN>/getMe"
Должен вернуться тот же JSON, что и при прямом запросе к api.telegram.org.
Как переключить на него бота
Большинство библиотек позволяют задать свой apiRoot/baseApiUrl вместо api.telegram.org.
Node.js, node-telegram-bot-api:
const TelegramBot = require('node-telegram-bot-api');
const bot = new TelegramBot(TOKEN, {
baseApiUrl: 'https://bot-api.example.com/api',
polling: true,
});
Node.js, telegraf:
const { Telegraf } = require('telegraf');
const bot = new Telegraf(TOKEN, {
telegram: { apiRoot: 'https://bot-api.example.com/api' },
});
Python, pyTelegramBotAPI (telebot):
import telebot
from telebot import apihelper
apihelper.API_URL = "https://bot-api.example.com/api/bot{0}/{1}"
bot = telebot.TeleBot(TOKEN)
curl / любой HTTP-клиент: просто замените api.telegram.org на bot-api.example.com/api в URL.
Важно понимать перед использованием
- Это открытый релей. Домен не привязан к конкретному боту — через него пройдёт запрос с любым валидным токеном. Секретность даёт только сам токен в URL, ровно как и при прямом обращении к
api.telegram.org. Не логируйте URL с токеном в общедоступные логи. - Для вебхуков (
setWebhook) через этот же домен можно принимать входящие апдейты от Telegram — тогда стоит дополнительно ограничитьlocationпод вебхук по IP-диапазонам Telegram. - Прокси ничего не шифрует и не подменяет данные — это чистый transparent proxy, поведение бота не меняется, меняется только адрес, на который он стучится.
Источник идеи
Оригинальная реализация на Cloudflare Workers: manzoorwanijk/telegram-bot-api-worker. Этот гайд — тот же принцип, но без воркера, средствами голого nginx.