Привет, Хабр. Расскажу, как написал self-hosted аналог ngrok на Go. 10 часов чистого времени, один человек + Claude Code.

Проблема
Нужно протестировать вебхук от Т-Банк/Telegram/любого внешнего сервиса. Запускаешь ngrok — не работает. Россия заблокирована. Каждый раз VPN, а с ним становится недоступна часть внутренних ресурсов. В какой-то момент решил написать своё.
Что получилось
GoPublic — полноценный self-hosted аналог ngrok:
Клиент + сервер с туннелированием через yamux
TUI на Bubble Tea
Web-инспектор на localhost:4040 с replay запросов
Авторизация через
Telegram OAuthТелеграм-бота или Yandex IDLet's Encrypt сертификаты (с нюансами — ниже)
Конфиг нескольких туннелей через gopublic.yaml
Auto-update клиента с Ed25519 подписями
CI/CD с деплоем на VPS
Код: github.com/region23/gopublic.su
Сервис: gopublic.su — не думаю, что желающих будет много, поэтому бесплатно.
Архитектура
Client (localhost:3000)
↓ TLS/TCP :4443
↓ yamux multiplexing
Server Control Plane (:4443)
↓
HTTP Ingress (:80/:443)
↓
Public Internet ← роутинг по Host header
Два бинаря. Сервер слушает :4443 для управления туннелями (yamux over TLS) и :80/:443 для входящих HTTP-запросов. Клиент подключается, устанавливает yamux-сессию, принимает запросы и проксирует на локальный порт.
Почему yamux
yamux от HashiCorp — мультиплексирование TCP-соединений. Как HTTP/2, но для TCP: одно соединение, много потоков. Первый stream — handshake (авторизация + привязка доменов). Все последующие — HTTP-запросы от пользователей.
Альтернативы рассматривал, но yamux проверен временем — используется в Consul, Nomad, Vault.
Auto-update клиента
Клиент умеет обновляться сам. При запуске проверяет GitHub Releases, если есть новая версия — предлагает обновиться по нажатию u.
Проблема: как убедиться, что скачанный бинарник не подменён? HTTPS недостаточно — GitHub можно скомпрометировать, MITM возможен на уровне CDN.
Решение — Ed25519 подписи:
При релизе CI генерирует
checksums.txt(SHA256-хеши всех бинарей)Подписывает его приватным ключом Ed25519 →
checksums.sigПубличный ключ зашит в клиенте на этапе компиляции
При обновлении клиент:
Скачивает
checksums.txtиchecksums.sigПроверяет подпись публичным ключом
Скачивает бинарник
Проверяет SHA256
Если хоть один шаг не сходится — обновление отклоняется.
На Unix установка атомарная через os.Rename. На Windows сложнее — нельзя заменить запущенный exe, поэтому создаётся batch-скрипт, который заменяет файл при следующем запуске. На MacOS все работает как часы :)
Let's Encrypt: лимиты и wildcard
Сейчас использую стандартный ACME HTTP-01 challenge через golang.org/x/crypto/acme/autocert. Работает, но есть ограничение: 50 сертификатов на домен в неделю.
Каждый новый туннель — это random-name.gopublic.su, и на каждый нужен отдельный сертификат. 50 новых доменов в неделю — и лимит исчерпан. Сейчас я создаю 2 домена на пользователя при регистрации, то есть моя система выдержит 25 новых пользователей в неделю.
Решение: wildcard-сертификат
Wildcard-сертификат *.gopublic.su покрывает все поддомены. Но для него нужен DNS-01 challenge — Let's Encrypt проверяет владение доменом через TXT-запись в DNS.
Пока работаю на HTTP-01, но переход на DNS-01 в планах. Если сервис начнёт расти — это первое, что придётся сделать.
Inspector: отладка вебхуков
На localhost:4040 поднимается web-интерфейс. Каждый проксированный запрос логируется: метод, путь, заголовки, тело, время ответа.

Главная фича — replay. Пришёл вебхук от Telegram, посмотрел payload, поправил код, нажал replay — запрос повторился к локальному серверу. Не нужно заново тригерить событие в Telegram.

Настройка сервера через Claude Code
Это был самый неожиданный опыт. Дал Claude Code SSH-доступ (по ключу) к VPS и попросил настроить продакшн. За 15 минут он:
Обновил систему, поставил Docker и docker-compose
Настроил firewall (ufw) — открыл только 22, 80, 443, 4443
Создал systemd-сервис для автозапуска
Настроил логирование с ротацией
Сгенерировал docker-compose.yml под проект
Настроил GitHub Actions для автодеплоя
CI/CD работает так: push в main → GitHub Actions собирает образ → пушит в GitHub Container Registry → подключается по SSH к VPS → делает docker-compose pull && up.
Я ожидал, что придётся править руками. Не пришлось. Он даже добавил health-check и правильный restart policy.
Timeline
Вечер 1 (~5 часов):
Базовая архитектура клиент-сервер
Yamux-туннелирование
Handshake-протокол
Локальный запуск работает
Вечер 2 (~5 часов):
Регистрация домена gopublic.su
Настройка VPS через Claude Code
Let's Encrypt интеграция
CI/CD пайплайн
TUI на Bubble Tea
Auto-update с подписями
Итого: 10 часов — от идеи до работающего продакшна.
Про вайбкодинг
Я слышал много восторженных отзывов про Antigravity. Купил подписку и как раз решил на этом проекте попробовать в деле. В Antigravity разработал спецификацию на проект и первую бету. Но экспириенс работы с этой IDE и Gemini 3 Pro показал себя слабо: долго думает, код пишет невнимательно, упуская детали из ТЗ, сама IDE глючит, ну и кредиты закончились за пару часов :)))
Открыл проект в Claude Code и продолжил в нем — совсем другой уровень. Рефакторинг, ревизия безопасности (нашёл пару потенциальных проблем с race conditions), помог настроить инфраструктуру. Особенно впечатлила работа с SSH — я не ожидал, что он сможет реально настроить сервер.
Это не "ИИ написал код за меня". Это "ИИ ускорил меня в 10-20 раз". Архитектурные решения, дизайн протокола, выбор библиотек — всё равно мои. Но рутину — код, настройка сервера, написание тестов — он забрал на себя.
Стек
Go 1.24
yamux — мультиплексирование
Gin — HTTP-роутер
Bubble Tea — TUI
Cobra — CLI
GORM — ORM для SQLite
securecookie — шифрование сессий
golang.org/x/crypto— Ed25519, autocert
Итого
За 10 часов один человек с ИИ-ассистентом собрал production-ready сервис уровня ngrok:
Код: github.com/region23/gopublic.su
Сервис: gopublic.su
Буду рад фидбэку!
P.S. Меня всегда триггерит, когда в конце статьи просят подписаться на телеграм-канал. Я просить подписаться не буду, но если что, он у меня тоже есть. Там пишу регулярно, в основном на тему "ИИ в разработке".
Комментарии (24)

zip_rnd
26.12.2025 13:08Спасибо за труд! Очень круто!

jidckii
26.12.2025 13:08Это не труд, это вайбкодинг за 2 вечера ))

evgensenin
26.12.2025 13:08кодинг разве не труд (хоть и вайб) ? человек (именно человек) тратил свое драгоценное время

MaximKiselev
26.12.2025 13:08А мне понравилось . Симпатично. Правда таких сервисов уже куча и дорогих и дешёвых и бесплатных. Самая веселая часть наверно это как раз виртуальные хосты и сертификаты . А чем вас не устроили текущие решения ? Из того что я смотрел были решения на node/go/rust, вроде работают. У вас были какие то специальные требования к протоколу или ещё что ?

pivolan
26.12.2025 13:08Я бы предложил авторизацию через телеграмм сделать с помощью простой ссылки на своего бота и доп параметра t.me/yourbot?start=uid
А там уже в боте разберётесь что куда привязано. И не надо просить юзера номер телефона от телеграмма вводить. А сейчас Реально выглядит как скам авторизация, телеграмм стоит на телефоне ожидаешь что через него просто авторизует, а он данные просит написать.

region23 Автор
26.12.2025 13:08Вы же понимаете, что предлагаемый вами способ - это костыль и это неправильно. Телеграм предлагает официальный способ и я использую его https://telegram.org/blog/login?setln=ru
jidckii
Ещё 1 велосипед для self-hosted коих уже за сотню https://github.com/anderspitman/awesome-tunneling.
Преимущество ngrok или tuna в том, что это услуга и есть гарантиии и сапорт, а если надо чёт там самому хостить и зазбираться то и ssh туннелями можно нагородить.
region23 Автор
Так я не только написал, но еще и сервис в интернете развернул - это SaaS - заходите на сайт, скачивайте клиент и юзайте точно также как ngrok - в этом и фишка. Я знаю, что таких сервисов и opensource-проектов очень много. Как и любых других. Но мне было интересно попробовать в работе Antigravity и этот проект стал идеальным кандидатом.
jidckii
Авторизация выглядит как скамный угон TG аккаунтов.
> SaaS - заходите на сайт, скачивайте клиент и юзайте точно также как ngrok
если это действительно так, ждите скамеров, малварьщиков и абузы к вашему хостинг провайдеру, что через вас вирусы раздают.
region23 Автор
>Авторизация выглядит как скамный угон TG аккаунтов.
Это родной виджет авторизации Телеграм. И он ничем не отличается от той же авторизации через Гугл. Если вы хоть раз авторизовывались на сайтах через телегу, такого вопроса возникнуть не должно.
P.S. Последнее время часто использую авторизацию через ТГ вместо гугла и вы не первый кто так на него реагирует, честно не понимаю с чем это связано, может с тем, что авторизацию через телегу встречаешь не так часто и паттерн в головах пользователей еще не закрепился.
> если это действительно так, ждите скамеров, малварьщиков и абузы к вашему хостинг провайдеру, что через вас вирусы раздают.
хорошая задачка на подумать как от этого защититься
jidckii
сделайте по почте / гугл / яндекс вход, хочу попробовать
region23 Автор
Ок может прикручу на выходных, как раз давно хотел научиться интегрировать авторизацию через Яндекс
region23 Автор
Прикрутил вход через Яндекс
aborouhin
А вот фишинговые сайты для угона Телеграма через "авторизацию" (когда на самом деле приходит код для входа с нового устройства) встречаешь очень часто. Те самые "проголосуйте за мою племянницу на конкурсе детских рисунков" и иже с ними. Так что вот я уж на что довольно подкованный юзер, и то остерегусь :)
region23 Автор
ну тут только один способ - повышение общей грамотности и осведомленности пользователей: "когда авторизовываешься на сторонних сайтах через Телеграм, он присылает сообщение с кнопками разрешить или отклонить через стандартный аккаунт Telegram. Всё остальное фишинг и скам"
aborouhin
Дабы не вникать в нюансы каждой платформы и не отслеживать новинки фишинговых технологий в режиме онлайн - я и сам руководствуюсь таким правилом, и всем, до повышения чьей грамотности могу дотянуться :) его рекомендую:
если есть простая регистрация по эл. почте, а не вход через Гугл/Яндекс/Телегу/Гитхаб/пр. - её и используйте;
если нет - хорошо подумайте, а Вам туда вообще надо?
region23 Автор
Вот это кстати очень неожиданно. Я считаю себя продвинутым пользователем со стажем и последние годы, если на сайтах есть способ авторизации через OAuth, то всегда препочту его классическому входу через email/pass. Потому что это улучшает и упрощает пользовательский опыт взаимодействия с сайтом. И сейчас понял, что это уже на таком автоматизме происходит, что я даже не смотрю на URL виджета :(
aborouhin
Мне тоже лень смотреть на URL, список запрашиваемых разрешений, а потом после прекращения пользования сайтом отзывать их (а то мало ли кто и в каких целях перехватит контроль над этим сайтом после того, как я не него уже три года не заходил, а разрешение-то осталось).
Я не особый параоник на тему прайвеси, но всё же предпочту минимизировать количество точек, где про то, чем и когда я пользуюсь, собирается слишком много информации в одном месте.
Мне было бы грустно в случае, если меня забанят на Гугле/Яндексе/Телеге/пр., потерять ещё и доступ к кучке других сервисов.
Пользовательский опыт замечательно упрощает менеджер паролей.
А OAuth у меня свой поднят, для внутренних сервисов :) А вот публичные - по описанным выше причинам избегаю.