Содержание:
- Почему бы не использовать имеющиеся сервисы, зачем городить свой «велосипед»?
- Проблемы существующих решений
- Ngrok
- Tuna
- localhost.run
- Внезапная имба и жемчужина — xTunnel
- Что это?
- Что по деньгам и ограничениям?
- Как начать использование?
- Итог
- Наконец, собственное решение, совмещающее плюсы всех вышеперечисленных и избавленное от их болячек/нюансов/проблем
- Что нам понадобится
- Краткое описание шагов
- А теперь к делу — сама настройка
- Шаг 1. Создание поддомена для проброса
- Шаг 2. Настраиваем nginx на VPS для проброса трафика
- Шаг 3. Открываем на VPS порт для проброса
- Шаг 4. Прописываем поддомен как алиас к нашему локальному проекту
- Шаг 5. Запускаем SSH-туннель, рекомендуемо — создаем для него нового пользователя
- Шаг 6. Донастройка VPS
- Шаг 7. Промежуточный результат
- Шаг 8. Регистрация вебхуков
- Заключение
Здравствуйте! Возникла задача написания простого telegram-бота, писал на PHP; в процессе разработки понадобилось тестировать и дебажить его.
Как это сделать? Известно два способа:
- Развернуть скрипт на dev-сервере, настроить удалённый xDebug;
- Разрабатывать локально, пользоваться локальным xDebug;
Если в случае с обычными php-проектами (вроде сайтов) проблем в дебаге не возникает (просто работаем локально, и пользуемся отладчиком), то при разработке бота, который должен реагировать на события извне, по вебхукам, это становится затруднительным.
Почему бы не использовать имеющиеся сервисы, зачем городить свой «велосипед»?
Вообще, для подобных целей, а также для демонстрации разрабатываемого сайта заказчику с локальной машины, существуют решения вроде ngrok/tuna/localhost.run . Но у каждого из них присутствуют свои ограничения.
Проблемы существующих решений
Ngrok
Во-первых, недоступен из России. Им можно воспользоваться, если имеется возможность подключиться из-за рубежа, но тогда возникает препятствие иного рода.

Это даже не проблема, а, скорее, нюанс. Если у вас бесплатный тариф, при первом посещении пользователь «извне» увидит не ваш сайт, а страницу-заглушку с кнопкой. Платформа оповестит пользователя о том, что сайт стоит открывать только если юзер ему доверяет, и он не должен указывать какую-то чувствительную информацию, типа номера карт или персональных данных. Пользователь должен подтвердить намерение перейти на сайт, нажав на кнопку — это делается для воспрепятствования использования сервиса мошенниками.
Из этого нюанса вытекает следующая проблема для нашего случая: внешняя система (у нас — telegram), которая нам не подконтрольна, будет просто пытаться отправить информацию о событии на url вебхука, не имея возможности пройти такую верификацию и обойти заглушку.
Для обхода нужно:
- либо установить заголовок запроса
ngrok-skip-browser-warning - либо установить нестандартный user-agent в браузере
- либо использовать платный аккаунт в ngrok 🙂
В случае с разработкой сайта или наличия вышеуказанных возможностей таких проблем не возникнет, однако это не наш случай.
И третий нюанс, возможно, он является индивидуальным. Я использую OSPanel (бывш. OpenServer) в качестве локального сервера, и для его работы с ngrok требуется:
- Установить стороннее дополнение отсюда, которое «изкаробки» не запустится, нужно переименовать файл
modules/Ngrok/ospanel_data/module.iniвmodule.dat(актуально для OSPanel 6.3.5+) - Добавить алиас ngrok-домена (посмотреть можно либо в dashboard.ngrok.com, либо в логах
logs/Ngrok/ngrok.log) для вашего проекта:
home/me.local/.osp/project.ini :[me.local]
php_engine = PHP-7.4
public_dir = {base_dir}\public_html
enabled = on
environment = System
aliases = me.local www.me.local ngrok-sample-domain.ngrok-free.dev
И на последнем шаге кроется проблема: бесплатный адрес может время от времени меняться, что добавляет головной боли в случае тестирования вебхуков с внешней системы — во-первых, нужно постоянно менять домен в конфиге проекта в OSPanel и полностью перезапускать сервер, а во-вторых заново регистрировать вебхуки.
Жаль, сервис хорош, но недружественен; нужен какой-нибудь русский аналог. UPD такой нашелся, о нём ближе к концу статьи 🙂.
Tuna
Позиционируется как аналог ngrok, доступный в России; выглядит многообещающе, доступен по адресу tuna.am. Проблема в том, что на бесплатном тарифе срок жизни единственного доступного туннеля ограничен 30 минутами, и, как я понял, это пожизненно, не раз в день/месяц/год — по крайней мере, обратную информацию (об обновлении лимитов) я не нашел. Чтобы убрать ограничения, нужно приобрести минимальный тариф (на 22.10.2025 — «Разработчик», 299 руб/месяц). Если вы разрабатываете проект в качестве хобби, вероятно, вы не захотите вкладывать в него что-то кроме энтузиазма 🙂.

localhost.run
Отличный сервис, совмещающий в себе плюсы двух вышеперечисленных решений — доступен в России, даёт вдоволь бесплатно использовать базовые необходимые возможности, отсутствует заглушка перед входом на ваш локальный ресурс.
И даже больше — нет нужды установки стороннего ПО, подключение устанавливается одной-единственной командой из терминала:
ssh -R 80:127.0.126.17:80 nokey@localhost.run
У меня IP сайта отличается от стандартного
127.0.0.1, поэтому вместоlocalhostв команде выше вручную проставлен IP из OSPanel (Настройки — Файл HOSTS — найти свой домен и подставить IP от него).

После выполнения команды сервис нас поприветствует и укажет наш временный домен вида 3daaaaaaaaaa6.lhr.life , а также сгенерирует qr-код для перехода с мобильных устройств. Временный домен, как и в случае с ngrok, нужно будет дописывать в конфиге проекта OSPanel — на этом всё, можно регистрировать вебхуки и тестировать систему, не беспокоясь о заглушках.
Звучит хорошо? Безусловно! Однако, здесь в качестве защиты от мошенников используется более агрессивная политика в отношении периодической смены доменов — они меняются как по таймауту, так и по количеству переходов (конкретных лимитов не назову, что-то около 10-15 минут и 10 запросов). То есть, сохраняется головная боль с перерегистрацией вебхуков и обновлению конфига/перезапуска локального сервиса.
Внезапная имба и жемчужина — xTunnel
Уже после написания статьи наткнулся на еще одно стороннее решение, позволяющее минут за 10 настроить туннель без лишних «танцев с бубном». Не мог не дополнить статью и не познакомить вас с этим многообещающим инструментом! Знакомьтесь, xTunnel.
Что это?
Мини-приложение от российского разработчика, работающее из командной строки. Доступны сборки под Winx64/x86/arm64, Mac x64/arm64, Linux x64/arm64. Для Винды установка доступна как через chocolatey, так и через скачивание архива с сайта. Я воспользовался последним способом.
Что по деньгам и ограничениям?
Бесплатный тариф не обладает сколько-нибудь значимыми для нашего кейса ограничениями, однако перечислю их: публичный адрес — временный, ограничение в 100 запросов в минуту, до 1 ГБ трафика в сутки.

По тарифам — базовый доступен бесплатно, лимиты являются не постоянными, как в случае с Tuna, а возобновляемыми, за что разработчику спасибо. Самый дорогой равен по стоимости начальному платному в вышеупомянутой Tuna. Как мы видим, ценовая политика довольно щадящая. Стоит сказать, что Tuna предлагает больше «фишечек» и является технологически более сложным продуктом, однако для наших целей эти навороты не нужны.
Как начать использование?
Несколько шагов:
- Регистрация учётной записи на cabinet.xtunnel.ru
- Скачивание архива / установка через пакетный менеджер
- Активация ключом из ЛК и запуск
Регистрируемся, подтверждаем учётную запись через email. Попадаем в личный кабинет и копируем ключ от бесплатной лицензии.

Устанавливаем софтину. В моём случае это было скачивание архива для Windows x64 и распаковка в любую папку — например, на рабочий стол.
Первым после скачивания, по инструкции разработчика, является установка корневого сертификата xtunnel. Я пропустил его, и всё заработало без проблем.
После установки вызываем командную строку (в случае с установкой из архива — открываем командную строку в папке с exe’шником), в ней нужно активировать программу бесплатным ключом. Выполняем xtunnel.exe -k ВАШ_КЛЮЧ, дожидаемся сообщения «Registration completed successfully».

И, наконец, запуск. Мой проект расположен на OSPanel-домене me.local, и висит на дефолтном порту 80. С учётом этого, команда для запуска будет xtunnel http me.local:80.

После выполнения команды мы увидим наш публичный адрес, который будет неизменным до перезапуска туннеля (это прямо не описывается, но за полчаса теста я не заметил его смены). Это очень удобно, не нужно следить за его «устареванием», как у предыдущих сервисов!
Теперь, при открытии публичного адреса мы сразу попадаем на наш локальный сайт 🙂. И нам даже не пришлось прописывать алиас в конфиге проекта OSPanel, мы просто указали в качестве target наш домен и порт! Еще одно удобство!
При работе с нашим сайтом «извне» в командной строке мы будем видеть краткий лог запросов. Выключение туннеля производится через Ctrl+C.
Итог
xTunnel — шикарнейший молодой сервис, позволяющий пробросить туннель извне к вашему локальному веб-приложению, обладающий всем необходимым в базовом тарифе, не налагающий строгих ограничений на бесплатную лицензию, простой в установке и настройке, в дополнение обладающий обратной связью в виде тг-сообщества. Пожалуй, его смело можно использовать в качестве бесплатного аналога-замены ngrok в России.
Наконец, собственное решение, совмещающее плюсы всех вышеперечисленных и избавленное от их болячек/нюансов/проблем
С учетом обновления статьи подглавой про xTunnel, фактически эта её часть, про самостоятельный проброс трафика извне на локальный проект через собственный VPS, теряет пользу и является либо аварийным способом «на будущее», либо инструкцией для желающих «поразбираться». В моём случае xTunnel закрывает потребности по тестированию ТГ-бота с вебхуками, но на всякий случай я оставлю её текст здесь. Да и потраченного времени жалко, чтобы его удалять 😀.
Время идёт, энтузиазм <пока что> разгорается, но ограничения сторонних сервисов угрожают растратить его на попытки «подружиться» с ними. Каков верный ход мысли? Правильно, попытаться собрать рабочее решение «без головняков» самостоятельно. Этим и займёмся 😀!
Что нам понадобится
- Собственный домен (или бесплатный технический, предоставляемый с хостингом)
- Арендованный VPS с nginx
Краткое описание шагов
- Создаём поддомен, который будет использоваться в качестве пробрасываемого.
- Направляем его на свой VPS.
- На VPS создаём сайт под этот поддомен, и настраиваем nginx-профиль для проброса трафика на незанятый порт.
- Открываем порт в файрволле.
- Дописываем поддомен в алиасы в профиль проекта в OSPanel.
- Запускаем SSH-туннель до нашего VPS с пробросом портов.
- Опционально — открываем конфигурацию sshd на VPS.
- Регистрируем вебхуки и радуемся жизни.
А теперь к делу — сама настройка
В моём случае уже был приобретён домен и VPS от Beget с предустановленной панелью hestia, детальные инструкции будут для этого кейса, но в общем — они одинаковы для всех провайдеров.

Шаг 1. Создание поддомена для проброса
Допустим, у нас есть домен example.ru, под проброс мы выделяем поддомен local.example.ru. В личном кабинете Beget переходим в раздел DNS, где выбираем наш или бесплатный технический домен, поочерёдно добавляем две подзоны — «local.» и «www.local.», сохраняем, затем корректируем IP (по-умолчанию ставится отличающийся от актуального). Альтернативно — можно попробовать добавить через раздел Домены.
Вторая подзона (www-версия) нужна для корректного получения SSL-сертификата.



Шаг 2. Настраиваем nginx на VPS для проброса трафика
Перед этим нужно дождаться, чтобы информация по поддомену на NS-серверах обновилась. В случае с подзоной, обычно на это уходит 10-15 минут. После этого можно продолжать.
Вообще, требуется установить nginx, получить TLS-сертификат (sudo apt update, sudo apt install nginx certbot python3-certbot-nginx -y, sudo certbot --nginx -d local.example.ru), создать конфиг nginx (/etc/nginx/sites-available/local.example.ru) заполнить его, как в примере ниже, затем выполнить sudo nginx -t и sudo systemctl reload nginx . Также, можно открыть порт 9200 для ufw, если он установлен и активен.
server {
listen 443 ssl;
server_name local.example.ru;
# Пути certbot обычно такие, но проверьте свои:
ssl_certificate /etc/letsencrypt/live/local.example.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/local.example.ru/privkey.pem;
location / {
proxy_pass http://127.0.0.1:9200;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
# (опционально) редирект http -> https
server {
listen 80;
server_name local.example.ru;
return 301 https://$host$request_uri;
}В моём случае на VPS предустановлена панель hestia, что решает проблему обновления SSL и в целом даёт удобный способ управления доменом. В этом случае порядок действий такой:
1) Создаём новый шаблон конфига nginx
Логинимся на VPS по SSH, переходим в /usr/local/hestia/data/templates/web/nginx, создаём два файла — port_tunnel.tpl и port_tunnel.stpl. Вообще, за основу можно взять имеющиеся default.tpl и default.stpl, скопировать и изменить их, удалив лишнее.
Ниже приложу архив моих файлов конфигурации — без регистрации и смс.
2) Создаём сайт с этим поддоменом и конфигурацией в hestia
С главной страницы личного кабинета Beget переходим в панель Hestia:

Логинимся, переходим во вкладку «ВЕБ» вверху, нажимаем кнопку ниже «Добавить домен», добавляем наш local.example.ru, выбирая тот IP, что мы указывали в разделе DNS.

Дожидаемся уведомления «Домен local.example.ru успешно создан», затем возвращаемся во вкладку «ВЕБ», находим в списке наш добавленный поддомен и редактируем его. Нам нужно дописать www-версию, включить SSL для домена и настроить его для Let’s Encrypt, включить редирект, и главное — настроить шаблон Proxy и остальные.

При нажатии «Сохранить» будет запущено получение Let’s Encrypt сертификата; оно может завершиться неудачей, если записи на домене еще не обновились. В этом случае необходимо дождаться окончания процесса обновления, и попробовать еще раз.
Шаг 3. Открываем на VPS порт для проброса
Обычно, при предустановке hestia в ней создаётся две учетки — основная и админская. Открытие портов делается через админскую, доступы к ней обычно приходят на почту от бегета, логин, как правило, admin. Находим кредлы и логинимся с ними.
Теперь переходим к настройке: кликаем по шестерёнке в верхней панели, затем по кнопке «Файрволл», затем — «Добавить правило». Указываем действие «ПРИНЯТЬ», выбираем протокол «TCP», указываем порт (в нашем конфиге 9200), в IP-адрес укажем 0.0.0.0/0 или локальный 127.0.0.1 для большей секьюрности, пишем произвольный комментарий. По идее, не обязательно, но повторяем действие для протокола «UDP».


Шаг 4. Прописываем поддомен как алиас к нашему локальному проекту
Самый быстрый шаг 🙂. В project.ini нашего проекта (например, home/me.local/.osp/project.ini) дописываем/обновляем параметр aliases, пример:
[me.local]
php_engine = PHP-7.4
public_dir = {base_dir}\public_html
enabled = on
environment = System
aliases = me.local www.me.local local.example.ruШаг 5. Запускаем SSH-туннель, рекомендуемо — создаем для него нового пользователя
Можем соединяться с VPS через имеющуюся учётку, но я бы советовал создать отдельную. Например, логинимся, переключаемся на root (su - root) и создаем юзера через su adduser port-tunnel , придумывая пароль, и заполняя/пропуская остальные данные.
Теперь, открываем командную строку, выполняем команду:
ssh -N -R 127.0.0.1:9200:127.0.126.17:80 port-tunnel@<ip или домен вашего сервера>, где 127.0.126.17 заменяем на актуальный IP нашего локального сайта из настроек OSPanel. Для удобства можем сохранить команду в bat-файл и положить его в удобное место.
В случае удачного подключения мы увидим перенос курсора в командной строке на новую строку и больше ничего. В случае возникновения ошибок они отобразятся в консоли. Например, «Warning: remote port forwarding failed for listen port 9200». Тогда переходим к опциональному шагу — донастройке VPS.
Шаг 6. Донастройка VPS
Внимание! Действия из этого раздела рекомендуется производить ТОЛЬКО в случае, если к этому моменту всё ещё не заработало само собой, так как потенциально эти изменения могут несколько снизить защищённость вашего VPS перед внешними сканнерами/ботами.
Обычно, проблема кроется в конфигурации sshd, решается перенастройкой нескольких параметров, которые, правда, несколько снижают защищенность сервера.
- Переходим в
/etc/ssh/sshd_config, ищем последнее вхождение опцииAllowTcpForwardingи меняем её значение наyes, если эта опция закомментирована — раскомментируем её - То же делаем с параметром
GatewayPorts, необходимое значение —clientspecified - Проверяем значение опции
PermitOpen— если находим её, закомментируем
После внесения правок сохраняем файл и перезапускаем sshd командой sudo systemctl restart sshd, после этого пробуем снова подключиться по SSH командой из предыдущего шага. Должно заработать.
Шаг 7. Промежуточный результат
По идее, на данном этапе ваш проект уже доступен из внешнего интернета, и при переходе на local.example.ru соединение будет пробрасываться к вашему компьютеру и вашему сайту в OSPanel. Включаем xDebug и дебажим, или демонстрируем сайт заказчику. Но у нас на повестке дня — работа с апи Telegram, поэтому завершим начатое, зарегистрировав вебхуки!
Шаг 8. Регистрация вебхуков
Второй самый быстрый шаг 🙂. Открываем командную строку и выполняем curl -X POST "https://api.telegram.org/bot<ВАШ_BOT_TOKEN>/setWebhook" -d "url=https://local.example.ru/webhook.php", заменив токен бота и путь к php-обработчику. В ответ мы должны увидеть json со статусом «ок», после этого можем тестировать наши вебхуки.
Заключение
Вот как бывает, хотели просто написать лёгкого бота для Telegram для своей группы с друзьями, а в итоге погрузились в изучение проброса портов между локальной машиной и удалённым сервером, настройку nginx-конфигураций, перенаправление трафика из целевого публичного домена внутрь виртуальной сети на локальный, обслуживаемый OSPanel, домен. Надеюсь, эта инструкция поможет вам и позволит сэкономить пару часов времени и немало нервов!

