[{"data":1,"prerenderedAt":144},["ShallowReactive",2],{"$f2qcx0encwexll":3,"articles":42},{"slug":4,"title":5,"description":6,"date":7,"updated":7,"tags":8,"emoji":13,"minutes":14,"html":15,"headings":16},"kak-zapustit-telegram-bota-na-servere","Как запустить Telegram бота на сервере","Polling или webhook, где взять токен и как его защитить, как запускать бота через systemd, pm2 или Docker и что делать при сбоях.","2026-10-01",[9,10,11,12],"telegram","бот","сервер","webhook","bot",4,"\u003Ch2 id=\"korotko\">Коротко\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>Обновления боту приходят двумя способами: polling (бот сам спрашивает Telegram) и webhook (Telegram сам присылает их на ваш HTTPS-адрес). Без особых причин начинайте с polling.\u003C\u002Fli>\n\u003Cli>Токен из BotFather работает как пароль от бота. Храните его в переменных окружения, а не в коде и не в git.\u003C\u002Fli>\n\u003Cli>Запускайте бота как службу (systemd, pm2 или Docker) с автоматическим перезапуском.\u003C\u002Fli>\n\u003Cli>Если токен утёк, выполните \u003Ccode>\u002Frevoke\u003C\u002Fcode> в BotFather.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"polling-ili-webhook\">Polling или webhook\u003C\u002Fh2>\n\u003Cp>\u003Cstrong>Polling\u003C\u002Fstrong> (метод \u003Ccode>getUpdates\u003C\u002Fcode>): бот регулярно запрашивает новые сообщения. Домен и HTTPS не нужны, работает даже за NAT, отлаживать проще. С одним токеном должен работать только один экземпляр бота.\u003C\u002Fp>\n\u003Cp>\u003Cstrong>Webhook\u003C\u002Fstrong>: Telegram отправляет каждое обновление на ваш адрес. Нужны домен с действующим HTTPS-сертификатом и один из портов: 443, 80, 88 или 8443. Если домен проксируется Cloudflare, используйте 443 или 8443. Подходит для бессерверных окружений и нескольких экземпляров за балансировщиком.\u003C\u002Fp>\n\u003Cp>Одновременно использовать оба способа нельзя: пока установлен webhook, \u003Ccode>getUpdates\u003C\u002Fcode> не работает. В руководстве Telegram отдельно сказано, что использовать \u003Ccode>getUpdates\u003C\u002Fcode> вполне нормально.\u003C\u002Fp>\n\u003Ch2 id=\"token-i-peremennye-okruzheniya\">Токен и переменные окружения\u003C\u002Fh2>\n\u003Cp>В @BotFather выполните \u003Ccode>\u002Fnewbot\u003C\u002Fcode>, задайте имя и username (он заканчивается на \u003Ccode>bot\u003C\u002Fcode>). BotFather пришлёт токен, который даёт полный контроль над ботом. Не публикуйте его в репозитории, на скриншотах и в логах.\u003C\u002Fp>\n\u003Cp>Положите значения в файл \u003Ccode>.env\u003C\u002Fcode> рядом с ботом, задайте права \u003Ccode>chmod 600 .env\u003C\u002Fcode> и добавьте файл в \u003Ccode>.gitignore\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cpre class=\"code\">\u003Ccode class=\"hljs language-ini\">\u003Cspan class=\"hljs-attr\">BOT_TOKEN\u003C\u002Fspan>=PASTE_TOKEN_HERE\n\u003Cspan class=\"hljs-attr\">ADMIN_IDS\u003C\u002Fspan>=\u003Cspan class=\"hljs-number\">123456789\u003C\u002Fspan>\n\u003Cspan class=\"hljs-attr\">WEBHOOK_SECRET\u003C\u002Fspan>=PASTE_RANDOM_STRING\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"zapusk-kak-sluzhby\">Запуск как службы\u003C\u002Fh2>\n\u003Cp>Создайте для бота отдельного пользователя без sudo и положите код и \u003Ccode>.env\u003C\u002Fcode> в его каталог (ниже это \u003Ccode>\u002Fhome\u002Fmybot\u002Fapp\u003C\u002Fcode>):\u003C\u002Fp>\n\u003Cpre class=\"code\">\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> adduser --disabled-password --gecos \u003Cspan class=\"hljs-string\">&quot;&quot;\u003C\u002Fspan> mybot\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Затем создайте файл \u003Ccode>\u002Fetc\u002Fsystemd\u002Fsystem\u002Fmybot.service\u003C\u002Fcode>:\u003C\u002Fp>\n\u003Cpre class=\"code\">\u003Ccode class=\"hljs language-ini\">\u003Cspan class=\"hljs-section\">[Unit]\u003C\u002Fspan>\n\u003Cspan class=\"hljs-attr\">Description\u003C\u002Fspan>=Telegram bot\n\u003Cspan class=\"hljs-attr\">After\u003C\u002Fspan>=network-\u003Cspan class=\"hljs-literal\">on\u003C\u002Fspan>line.target\n\u003Cspan class=\"hljs-attr\">Wants\u003C\u002Fspan>=network-\u003Cspan class=\"hljs-literal\">on\u003C\u002Fspan>line.target\n\n\u003Cspan class=\"hljs-section\">[Service]\u003C\u002Fspan>\n\u003Cspan class=\"hljs-attr\">User\u003C\u002Fspan>=mybot\n\u003Cspan class=\"hljs-attr\">WorkingDirectory\u003C\u002Fspan>=\u002Fhome\u002Fmybot\u002Fapp\n\u003Cspan class=\"hljs-attr\">EnvironmentFile\u003C\u002Fspan>=\u002Fhome\u002Fmybot\u002Fapp\u002F.env\n\u003Cspan class=\"hljs-attr\">ExecStart\u003C\u002Fspan>=\u002Fhome\u002Fmybot\u002Fapp\u002F.venv\u002Fbin\u002Fpython main.py\n\u003Cspan class=\"hljs-attr\">Restart\u003C\u002Fspan>=always\n\u003Cspan class=\"hljs-attr\">RestartSec\u003C\u002Fspan>=\u003Cspan class=\"hljs-number\">5\u003C\u002Fspan>\n\n\u003Cspan class=\"hljs-section\">[Install]\u003C\u002Fspan>\n\u003Cspan class=\"hljs-attr\">WantedBy\u003C\u002Fspan>=multi-user.target\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cpre class=\"code\">\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> systemctl daemon-reload\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> systemctl \u003Cspan class=\"hljs-built_in\">enable\u003C\u002Fspan> --now mybot\n\u003Cspan class=\"hljs-built_in\">sudo\u003C\u002Fspan> journalctl -u mybot -f\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Для Node.js в \u003Ccode>ExecStart\u003C\u002Fcode> нужен абсолютный путь к \u003Ccode>node\u003C\u002Fcode>, его покажет \u003Ccode>which node\u003C\u002Fcode>. Вариант на pm2: \u003Ccode>pm2 start index.js --name mybot\u003C\u002Fcode>, затем \u003Ccode>pm2 startup\u003C\u002Fcode> и \u003Ccode>pm2 save\u003C\u002Fcode>. Учтите, что pm2 сам \u003Ccode>.env\u003C\u002Fcode> не читает: бот должен загружать файл, например библиотекой dotenv. Вариант на Docker: \u003Ccode>docker run -d --name mybot --restart unless-stopped --env-file .env mybot-image\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Ch2 id=\"webhook-i-https\">Webhook и HTTPS\u003C\u002Fh2>\n\u003Cp>Поставьте перед ботом Caddy или nginx, который проксирует запросы на локальный порт (пример в статье \u003Ca href=\"\u002Farticles\u002Fkak-razvernut-sait-na-vps\">как развернуть сайт на VPS\u003C\u002Fa>), и зарегистрируйте адрес. Чтобы токен не попал в историю команд, сначала загрузите значения из \u003Ccode>.env\u003C\u002Fcode> в оболочку (от имени пользователя, которому принадлежит файл):\u003C\u002Fp>\n\u003Cpre class=\"code\">\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-built_in\">set\u003C\u002Fspan> -a; \u003Cspan class=\"hljs-built_in\">source\u003C\u002Fspan> .\u003Cspan class=\"hljs-built_in\">env\u003C\u002Fspan>; \u003Cspan class=\"hljs-built_in\">set\u003C\u002Fspan> +a\ncurl \u003Cspan class=\"hljs-string\">&quot;https:\u002F\u002Fapi.telegram.org\u002Fbot\u003Cspan class=\"hljs-variable\">${BOT_TOKEN}\u003C\u002Fspan>\u002FsetWebhook&quot;\u003C\u002Fspan> \\\n  -d \u003Cspan class=\"hljs-string\">&quot;url=https:\u002F\u002Fbot.example.com\u002Fwebhook&quot;\u003C\u002Fspan> \\\n  -d \u003Cspan class=\"hljs-string\">&quot;secret_token=\u003Cspan class=\"hljs-variable\">${WEBHOOK_SECRET}\u003C\u002Fspan>&quot;\u003C\u002Fspan>\ncurl \u003Cspan class=\"hljs-string\">&quot;https:\u002F\u002Fapi.telegram.org\u002Fbot\u003Cspan class=\"hljs-variable\">${BOT_TOKEN}\u003C\u002Fspan>\u002FgetWebhookInfo&quot;\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>В \u003Ccode>secret_token\u003C\u002Fcode> допустимы буквы, цифры, \u003Ccode>_\u003C\u002Fcode> и \u003Ccode>-\u003C\u002Fcode>. Telegram передаёт его в заголовке \u003Ccode>X-Telegram-Bot-Api-Secret-Token\u003C\u002Fcode>, и бот должен его проверять. Сертификату нужна полная цепочка (fullchain). Метод \u003Ccode>getWebhookInfo\u003C\u002Fcode> показывает \u003Ccode>last_error_message\u003C\u002Fcode> и \u003Ccode>pending_update_count\u003C\u002Fcode>. Про сертификаты читайте в статье \u003Ca href=\"\u002Farticles\u002Fssl-sertifikat-https\">SSL сертификат и HTTPS\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"proverka-i-sboi\">Проверка и сбои\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>Добавьте адрес \u003Ccode>\u002Fhealth\u003C\u002Fcode>, который отвечает кодом 200, и проверяйте его внешним мониторингом по публичному адресу либо локальным скриптом, который пишет вам при сбое. Для бота без HTTP проверяйте \u003Ccode>systemctl is-active mybot\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>\u003Ccode>Restart=always\u003C\u002Fcode> перезапускает процесс, а причину ищите в \u003Ccode>sudo journalctl -u mybot -n 100\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>Перехватывайте исключения в обработчиках. Если бот падает на одном сообщении, после перезапуска Telegram может отдать его снова, и бот зациклится.\u003C\u002Fli>\n\u003Cli>При ответе 429 соблюдайте паузу \u003Ccode>retry_after\u003C\u002Fcode>.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"bezopasnost\">Безопасность\u003C\u002Fh2>\n\u003Cul>\n\u003Cli>Админов определяйте по числовому ID и проверяйте \u003Ccode>from.id\u003C\u002Fcode> перед командами. Username меняется, ID нет.\u003C\u002Fli>\n\u003Cli>Не пишите в логи токен, полные адреса запросов к API (в них есть токен) и личные данные пользователей.\u003C\u002Fli>\n\u003Cli>Запускайте бота от отдельного пользователя без sudo, а не от root и не от своего администратора.\u003C\u002Fli>\n\u003Cli>Docker публикует порты в обход ufw, поэтому порт webhook открывайте только на localhost: \u003Ccode>-p 127.0.0.1:3000:3000\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>Если токен утёк, выполните \u003Ccode>\u002Frevoke\u003C\u002Fcode> у BotFather, обновите значение в \u003Ccode>.env\u003C\u002Fcode> и перезапустите бота. Старый токен перестанет работать.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"esli-ne-poluchilos\">Если не получилось\u003C\u002Fh2>\n\u003Col>\n\u003Cli>Ошибка 401 Unauthorized: токен неверный или отозван.\u003C\u002Fli>\n\u003Cli>Ошибка 409 Conflict: запущено два экземпляра с polling либо установлен webhook. Оставьте один экземпляр или вызовите \u003Ccode>deleteWebhook\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>Webhook не доходит: смотрите \u003Ccode>last_error_message\u003C\u002Fcode> в \u003Ccode>getWebhookInfo\u003C\u002Fcode> и проверьте порт, полную цепочку сертификата, DNS, файрвол и правила защиты в Cloudflare.\u003C\u002Fli>\n\u003Cli>Бот молчит в группе: включён privacy mode. Отключите его командой \u003Ccode>\u002Fsetprivacy\u003C\u002Fcode> у BotFather, затем удалите бота из группы и добавьте снова, иначе изменение не вступит в силу. Можно и сделать бота админом.\u003C\u002Fli>\n\u003Cli>Бот не стартует: прочитайте \u003Ccode>sudo journalctl -u mybot -n 100\u003C\u002Fcode>, проверьте путь в \u003Ccode>ExecStart\u003C\u002Fcode> и то, что код и \u003Ccode>.env\u003C\u002Fcode> лежат в каталоге пользователя \u003Ccode>mybot\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>С сервера нет доступа к Telegram: выполните \u003Ccode>curl -I https:\u002F\u002Fapi.telegram.org\u003C\u002Fcode>. Любой ответ значит, что связь есть, а зависание или ошибка соединения указывает на проблему. Доступность зависит от страны и провайдера.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>Если что-то непонятно, напишите мне в Telegram: @lztcoder\u003C\u002Fp>\n",[17,21,24,27,30,33,36,39],{"id":18,"text":19,"level":20},"korotko","Коротко",2,{"id":22,"text":23,"level":20},"polling-ili-webhook","Polling или webhook",{"id":25,"text":26,"level":20},"token-i-peremennye-okruzheniya","Токен и переменные окружения",{"id":28,"text":29,"level":20},"zapusk-kak-sluzhby","Запуск как службы",{"id":31,"text":32,"level":20},"webhook-i-https","Webhook и HTTPS",{"id":34,"text":35,"level":20},"proverka-i-sboi","Проверка и сбои",{"id":37,"text":38,"level":20},"bezopasnost","Безопасность",{"id":40,"text":41,"level":20},"esli-ne-poluchilos","Если не получилось",[43,51,53,62,72,82,90,95,104,115,123,130,136],{"slug":44,"title":45,"description":46,"date":7,"updated":7,"tags":47,"emoji":50,"minutes":14},"kak-vybrat-hosting","Как выбрать хостинг для сайта или бота","Чем отличаются виртуальный хостинг, VPS, облако и статический хостинг, сколько памяти нужно сайту и боту и что спросить у продавца.",[48,49,11],"хостинг","vps","server",{"slug":4,"title":5,"description":6,"date":7,"updated":7,"tags":52,"emoji":13,"minutes":14},[9,10,11,12],{"slug":54,"title":55,"description":56,"date":7,"updated":7,"tags":57,"emoji":61,"minutes":14},"kak-kupit-domen","Как и где купить домен","Какую зону выбрать, что проверить перед оплатой, чем регистратор отличается от перепродавца и как не потерять домен.",[58,59,60],"домен","регистратор","dns","domain",{"slug":63,"title":64,"description":65,"date":7,"updated":7,"tags":66,"emoji":71,"minutes":14},"kak-oplatit-zakaz-kriptovalutoy","Как оплатить заказ криптовалютой","Как оплатить счёт из бота на странице Heleket, выбрать валюту и сеть, отправить точную сумму, проверить ссылку и действовать при ошибке.",[67,68,69,70],"оплата","криптовалюта","heleket","безопасность","pay",{"slug":73,"title":74,"description":75,"date":7,"updated":7,"tags":76,"emoji":80,"minutes":81},"kak-podgotovit-brif-dlya-sayta","Как подготовить бриф для сайта или бота","Что описать заранее, чтобы разработчик дал реалистичную оценку, от цели и аудитории до интеграций, срока и бюджета. Есть шаблон.",[77,78,10,79],"бриф","сайт","разработка","doc",3,{"slug":83,"title":84,"description":85,"date":7,"updated":7,"tags":86,"emoji":89,"minutes":14},"cloudflare-dlya-domena","Как подключить домен к Cloudflare","Как добавить домен в Cloudflare, сменить NS, выбрать режим SSL\u002FTLS и понять разницу между оранжевым и серым облаком.",[87,60,58,88],"cloudflare","ssl","cloud",{"slug":91,"title":92,"description":93,"date":7,"updated":7,"tags":94,"emoji":61,"minutes":14},"kak-privyazat-domen-k-hostu","Как привязать домен к хостингу","Что такое A-запись и NS, как подключить домен к хостингу или VPS и как проверить, что всё заработало.",[58,60,48],{"slug":96,"title":97,"description":98,"date":7,"updated":7,"tags":99,"emoji":103,"minutes":14},"kak-razvernut-sait-na-vps","Как развернуть сайт на VPS","Пошаговый путь для Ubuntu LTS от пользователя и SSH-ключа до Caddy с HTTPS, запуска через pm2, логов, обновлений и бэкапов.",[49,100,101,102],"ubuntu","node","caddy","rocket",{"slug":105,"title":106,"description":107,"date":7,"updated":7,"tags":108,"emoji":114,"minutes":14},"pochta-na-svoem-domene","Почта на своём домене: MX, SPF, DKIM, DMARC","Как подключить почту на своём домене, настроить MX, SPF, DKIM и DMARC, проверить доставку и понять, почему письма попадают в спам.",[109,110,111,112,113],"почта","mx","spf","dkim","dmarc","mail",{"slug":116,"title":117,"description":118,"date":7,"updated":7,"tags":119,"emoji":122,"minutes":14},"spamblok-telegram-chto-delat","Спамблок в Telegram: что это и что делать","Что такое ограничения аккаунта Telegram, как проверить статус через @SpamBot, как подать апелляцию и чего делать нельзя.",[9,120,121,70],"спамблок","аккаунт","help",{"slug":124,"title":125,"description":126,"date":7,"updated":7,"tags":127,"emoji":129,"minutes":14},"cloudflare-api-klyuch","Cloudflare: API токен и Global API Key","Чем API токен отличается от Global API Key в Cloudflare, какие права нужны для DNS, как выглядят запросы и что делать при утечке ключа.",[87,128,70],"api","key",{"slug":131,"title":132,"description":133,"date":7,"updated":7,"tags":134,"emoji":60,"minutes":14},"dns-zapisi-prostymi-slovami","DNS записи простыми словами","Что означают записи A, AAAA, CNAME, MX, TXT, NS, SRV и CAA, что такое TTL и почему CNAME нельзя поставить на корень домена.",[60,58,135],"записи",{"slug":137,"title":138,"description":139,"date":7,"updated":7,"tags":140,"emoji":143,"minutes":81},"ssl-sertifikat-https","SSL сертификат и HTTPS: как включить","Что даёт сертификат, как включить HTTPS через панель хостинга, Let's Encrypt с certbot, Caddy или Cloudflare и как проверить результат.",[88,141,142,70],"https","сертификат","shield",1791314128894]