Как сделать локальный веб-сервер публичным с помощью Localtunnel

Автор: | 17.07.2026

На этой неделе мы решили поделиться информацией о Localtunnel — проекте, который я создал вне Twilio, чтобы помочь справиться с трудностями разработки приложений, использующих API на основе вебхуков (например, как у Twilio), когда вы работаете за NAT.

Сегодня довольно распространено использование локальной среды для веб-разработки. Независимо от того, работаете ли вы с Apache, Mongrel или App Engine SDK, все мы начинаем видеть преимущества наличия среды, похожей на продакшен, прямо на ноутбуке. Это позволяет итеративно писать код и отлаживать приложение без необходимости развертывания в интернете или даже подключения к нему.

С ростом популярности HTTP-колбэков, или вебхуков, возникают ситуации, когда отладить приложение можно только в режиме реального времени и при наличии доступа к интернету. Помимо вебхуков, есть и другие случаи, когда может понадобиться сделать локальные веб-серверы публичными, например, для тестирования или публичных демонстраций. Демонстрации — удивительно частый случай, особенно для многопользовательских систем («Жаль, что ты не можешь присоединиться к этому чат-приложению, которое я разрабатываю, ведь оно работает только на моем ноутбуке»).

Для некоторых решение очевидно: SSH-туннелирование! То есть использование магического набора опций SSH на удаленном сервере для создания туннеля с этой машины на вашу локальную. Когда люди подключаются к порту на вашем публичном сервере, соединение перенаправляется на локальный порт вашей машины, создавая впечатление, что этот порт находится на публичном IP.

Идея отличная, но настройка доставляет хлопоты. Это не просто длинная и неудобная команда, которую нужно вводить каждый раз, но также необходимо правильно настроить sshd на удаленной машине, чтобы создать публичный туннель. В противном случае придется настраивать два туннеля: один с вашей машины на частный порт удаленной машины, а затем другой на удаленной машине с публичного порта на частный порт (который перенаправляет на вашу машину).

Я считаю, что это слишком сложно, чтобы рассматривать SSH-туннелирование как «быстрый и простой вариант». Особенно если вы помогаете кому-то другому настроить туннель. Именно тогда я начал представлять простую команду и сервис, которые сделают этот процесс максимально простым. Вот как это реализовано в Localtunnel:

`$ localtunnel 8080`

И всё готово! С Localtunnel настолько просто настроить туннель, что это даже становится забавным. Более того, публично доступный URL имеет удобное доменное имя и использует порт 80, независимо от того, какой порт используется локально. При запуске Localtunnel вам сообщают, какой это URL:

«`

$ localtunnel 8080

Порт 8080 теперь доступен по адресу http://8bv2.localtunnel.com …

«`

Этот URL теперь можно делиться с другими, использовать для вебхуков и т.д. Мы предполагаем, что туннель будет относительно недолговечным, хотя активно не закрываем долго работающие туннели. Туннель обычно доступен до тех пор, пока вы не остановите процесс.

Вот еще один пример использования Localtunnel для публикации встроенного Python HTTP-сервера, чтобы быстро делиться файлами через интернет:

«`

$ python -m SimpleHTTPServer 8000 &

$ localtunnel 8000

Порт 8000 теперь доступен по адресу http://hy51.localtunnel.com …

«`

Теперь по этому URL будет доступен список файлов в текущей директории. Поделитесь URL, и другие смогут получить доступ к этим файлам, пока вы не закроете туннель.

Стоит уточнить, что в основе этого по-прежнему лежит SSH-туннелирование, но обернутое в удобный пакет, включающий простой клиент и сервер. Давайте посмотрим, что именно происходит.

Команда localtunnel написана на Ruby и использует SSH-библиотеку для открытия самого туннеля, но сначала она обращается к API регистрации туннеля. Этот API находится на том же сервере, через который проксируется туннель, и предоставляется серверной частью.

Серверная часть предоставляет два сервиса: обратный прокси к перенаправленному порту и API регистрации туннеля. Вы можете сами посмотреть на API регистрации, просто перейдите по адресу http://open.localtunnel.com. Этот простой API выделяет неиспользуемый порт для туннелирования и предоставляет клиенту localtunnel информацию, необходимую для настройки SSH-туннеля.

Конечно, есть и аутентификация. Поскольку это бесплатный и публичный сервис, я не хочу просто так предоставлять всем SSH-доступ к этой машине (как может показаться). Вместо этого, так как мы используем SSH, мы применяем публичные ключи и опции для каждого ключа, чтобы ограничить доступ, но при этом сохранить нормальный SSH-доступ для всего остального на сервере.

Сервер работает под пользователем без оболочки. У него есть только домашняя директория с файлом authorized_keys. При первом использовании Localtunnel необходимо использовать опцию -k, указав публичный ключ, который будет передан при регистрации туннеля. Мы проверяем, что это допустимый ключ, и добавляем его в файл authorized_keys с рядом опций, которые запрещают практически любое использование SSH, кроме туннелирования на частный порт сервера. После этого, если SSH сможет найти ваш приватный ключ, всё будет работать автоматически.

Мы разрешаем только туннелирование на частные порты, так как не хотим произвольного перенаправления публичных портов с сервера. Публичный доступ к этому частному порту на сервере осуществляется через наш обратный прокси, который слушает порт 80 для всех запросов к `*.localtunnel.com`. Мы храним соответствие случайно сгенерированных хостов для каждого активного порта в памяти и используем это для определения бэкенда нашего обратного прокси. Однако этот бэкенд на самом деле является вашим локальным сервером благодаря SSH-туннелю.

Важно учитывать, что на данный момент нет реальных гарантий конфиденциальности и поддержки HTTPS. Это в планах, но пока это означает, что не стоит передавать через Localtunnel особо чувствительные данные.

Вот, собственно, и всё. Вы можете изучить код на GitHub. Серверная часть написана на Twisted Python и содержит чуть больше 100 строк кода.

Вы можете начать использовать его сразу, если у вас установлены Ruby и Rubygems. Вам нужно лишь выполнить команду:

`$ gem install localtunnel`

Хотя сейчас проект зависит от Ruby, один из участников работает над Java-клиентом. Кстати, о контрибьюторах: в планах есть еще несколько вещей, если кто-то захочет помочь:

— Поддержка CNAME для долгоживущих или «зарезервированных» туннелей

— Поддержка HTTPS для полностью защищенных туннелей

— Автоматическая генерация ключей, устраняющая необходимость первоначального указания ключа

В противном случае пользуйтесь бесплатным сервисом и не стесняйтесь развернуть свой собственный экземпляр!