Привет, Хабр. Расскажу, как написал self-hosted аналог ngrok на Go. 10 часов чистого времени, один человек + Claude Code.
Нужно протестировать вебхук от Т-Банк/Telegram/любого внешнего сервиса. Запускаешь ngrok — не работает. Россия заблокирована. Каждый раз VPN, а с ним становится недоступна часть внутренних ресурсов. В какой-то момент решил написать своё.
GoPublic — полноценный self-hosted аналог ngrok:
Клиент + сервер с туннелированием через yamux
TUI на Bubble Tea
Web-инспектор на localhost:4040 с replay запросов
Авторизация через Telegram OAuth
Let'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 от HashiCorp — мультиплексирование TCP-соединений. Как HTTP/2, но для TCP: одно соединение, много потоков. Первый stream — handshake (авторизация + привязка доменов). Все последующие — HTTP-запросы от пользователей.
Альтернативы рассматривал, но yamux проверен временем — используется в Consul, Nomad, Vault.
Клиент умеет обновляться сам. При запуске проверяет 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 все работает как часы :)
Сейчас использую стандартный ACME HTTP-01 challenge через golang.org/x/crypto/acme/autocert. Работает, но есть ограничение: 50 сертификатов на домен в неделю.
Каждый новый туннель — это random-name.gopublic.su, и на каждый нужен отдельный сертификат. 50 новых доменов в неделю — и лимит исчерпан. Сейчас я создаю 2 домена на пользователя при регистрации, то есть моя система выдержит 25 новых пользователей в неделю.
Wildcard-сертификат *.gopublic.su покрывает все поддомены. Но для него нужен DNS-01 challenge — Let's Encrypt проверяет владение доменом через TXT-запись в DNS.
Пока работаю на HTTP-01, но переход на DNS-01 в планах. Если сервис начнёт расти — это первое, что придётся сделать.
На localhost:4040 поднимается web-интерфейс. Каждый проксированный запрос логируется: метод, путь, заголовки, тело, время ответа.
Главная фича — replay. Пришёл вебхук от Telegram, посмотрел payload, поправил код, нажал replay — запрос повторился к локальному серверу. Не нужно заново тригерить событие в Telegram.
Это был самый неожиданный опыт. Дал 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.
Вечер 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 и Gimini 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. Меня всегда триггерит, когда в конце статьи просят подписаться на телеграм-канал. Я просить подписаться не буду, но если что, он у меня тоже есть. Там пишу регулярно, в основном на тему "ИИ в разработке".
Источник


