Перейти к основному содержанию
Скидка 50% все планы, ограниченное время. Начиная от $2.48/mo
17 min left
Инструменты разработчика и DevOps

Как опубликовать localhost-приложение без VPS

B Автор: Bill 17 мин чтения
Заставка «Публикуем localhost без VPS»: локальное приложение на ноутбуке расходится через туннель к телефону, окну браузера и домашней сети

Ваше приложение работает. Вы запустили dev-сервер, открыли http://localhost:3000, и оно делает то, что должно. Потом кто-то просит ссылку, и выясняется, что URL на вашем экране ничего не значит ни для кого, кроме вас.

Есть три способа дать localhost-приложению публичный URL без VPS, плюс один более быстрый вариант, когда собеседник находится в вашей локальной сети, и выбор между ними — это не вопрос инструмента. Это вопрос того, как долго приложение должно оставаться доступным и может ли оно работать где-то, кроме вашего ноутбука. Ниже — каждый путь, команда, которая даёт URL, и то, что именно заставит этот URL перестать работать.

Кратко (TL;DR)

  • Кому-то в вашем Wi-Fi нужно это увидеть: привяжите dev-сервер ко всем сетевым интерфейсам и сообщите свой LAN-IP. Готово за секунды, умирает в тот момент, когда гость покидает вашу сеть.
  • Нужна ссылка, которую откроет кто угодно в ближайший час: запустите туннель (cloudflared, ngrok, localtunnel, localhost.run). Публичный HTTPS-URL примерно за минуту, никаких изменений на роутере, и он умирает вместе с процессом, который его запустил.
  • Оно должно работать, пока ноутбук закрыт: отправьте приложение на бесплатный тариф хостинга. Это отвязывает приложение от ноутбука и вводит новые правила: банковские карты, коммерческое использование и то, переживут ли ваши данные перезапуск.
  • Вашему приложению не нужен серверный код в момент запроса: соберите его и выложите статический результат на статический хостинг. Он может оставаться онлайн без вашего ноутбука, и там нет процесса приложения, который нужно будить, пока аккаунт и лимиты хостинга это позволяют.
  • Одно значение по умолчанию, о котором стоит знать: next dev и python -m http.server уже слушают все сетевые интерфейсы без всяких флагов. Если вы считали, что ваш dev-сервер виден только на вашем ноутбуке, это не так.

Какой путь подходит вашему приложению

Схема принятия решения от локального приложения к одному из четырёх путей: только LAN, публичный туннель, хостинг приложений или статическая сборка, с временем настройки, возможностью выключить ноутбук и лучшим сценарием для каждого

Три из этих четырёх путей дают приложению публичный URL в интернете; первый достигает только вашей сети, что делает его одновременно самым быстрым и самым ограниченным. Отсортируйте их по тому, как долго должен жить URL, и выбор почти сделает себя сам.

ПутьВремя до получения URLСколько живётЧто его убиваетДля кого
Одна сетьСекундыПока вы оба в сетиГость переходит в другой Wi-FiКоллега за соседним столом или ваш собственный телефон
ТуннельОколо минутыПока работает процессЗакрыть ноутбук, убить терминал, упереться в лимиты тарифаДемо, показ клиенту, тест вебхука
Бесплатный тариф хостингаОт 10 до 30 минутБессрочно, с условиямиУсыпление, эфемерная файловая система или условия тарифаТо, что должно отвечать, пока вы спите
Статическая сборкаОт 10 до 20 минутБессрочноПотребность в серверном коде в момент запросаПриложения, которые можно полностью сгенерировать при сборке или выполнять на клиенте

Какие строки вам доступны, зависит от трёх вещей, которые можно проверить в собственном проекте:

  • Нужен ли приложению ваш серверный код в момент запроса? Маршрут Flask или FastAPI, эндпоинт в server.js или любая серверная логика, зависящая от запроса, требует серверного хостинга. Серверный код на этапе сборки не исключает статическое развёртывание автоматически: Server Components в Next.js могут выполняться во время next build, а статические GET Route Handlers можно пререндерить. Если каждый запрос во время работы можно отдать как статические файлы или отправить напрямую из браузера во внешний API, статический путь по-прежнему открыт.
  • Читает или пишет ли оно файл, который нужно сохранять? Файл базы данных (.db, .sqlite), папка загрузок, JSON-файл, который оно редактирует. Если да, проверьте модель хранения хостинга перед развёртыванием. Бесплатные веб-сервисы Render и бесплатные инстансы Koyeb используют эфемерное локальное хранилище, а Vercel Functions работают с файловой системой только для чтения и временным пространством /tmp . Держите постоянное состояние в надёжном томе, базе данных или объектном хранилище, а не рассчитывайте, что локальный диск приложения уцелеет.
  • Нужен ли ему секрет во время работы? Ключ в файле .env работает без изменений на первых двух путях, так как приложение по-прежнему запущено на вашей машине. На двух других вы вводите его заново в настройках окружения провайдера, и его не должно быть в репозитории, который вы пушите.

Поделитесь в своей сети

next dev уже слушает все сетевые интерфейсы вашей машины (именно это и означает 0.0.0.0 , когда вы его видите), и то же самое делает python -m http.server. Ни одному из них не нужен флаг, так что dev-сервер, который у вас запущен прямо сейчас, скорее всего уже доступен с телефона в том же Wi-Fi.

Next.js описывает -H как способ изменить это имя хоста, со значением по умолчанию 0.0.0.0, а документация Python говорит, что модуль привязывается ко всем интерфейсам , если не передать --bind 127.0.0.1. Это делает такой способ самым быстрым, чтобы поделиться localhost-приложением: без аккаунта, без установки, без развёртывания. Остальным популярным dev-серверам нужно сказать об этом явно.

# Already listening on all interfaces. Nothing to add.
next dev
python -m http.server 8000
streamlit run app.py

# Needs the flag.
npm run dev -- --host             # Vite
flask run --host=0.0.0.0
uvicorn main:app --host 0.0.0.0   # FastAPI

Документация Vite: server.host по умолчанию равен localhost, а также принимает --host в командной строке или server.host: '0.0.0.0' в файле конфигурации. Uvicorn по умолчанию использует 127.0.0.1, что покрывает и FastAPI, поскольку именно он его запускает. Streamlit оставляет server.address незаданным, а его справочник по конфигурации отмечает, что его задание ограничивает доступ только этим адресом: не задано — значит без ограничений.

Дальше нужен адрес, который вы сообщите. Это собственный IP вашей машины в локальной сети, а не localhost:

# macOS
ipconfig getifaddr en0

# Linux
hostname -I

# Windows (PowerShell)
ipconfig | findstr IPv4

Дайте гостю http://<that-address>:3000 , и он внутри. Подвох в форме всего пути: этот адрес ничего не значит за пределами вашей сети. Как только гость окажется в другом Wi-Fi, в мобильной сети или дома, ссылка для него мертва.

Примечание: если команда отрабатывает нормально, а другое устройство всё равно не может подключиться, почти всегда виноват файрвол ОС, а не команда. Документация Apple по файрволу говорит, что macOS показывает предупреждение для приложения, которому вы ещё не дали разрешение, и отклоняет подключение, пока вы не примете решение. Windows же спрашивает, какой сетевой профиль применить, и держит отдельные правила для частных и общедоступных сетей. В домашней или офисной сети выбирайте «Частная». Никогда не выбирайте «Общедоступная».

Спрячьте его за туннель

Туннель — это небольшая программа, которая работает рядом с вашим приложением и даёт ему публичный HTTPS-адрес. Одна команда даёт бесплатный туннель до localhost примерно за минуту, и стоит сразу знать, что URL умирает в тот момент, когда завершается эта команда:

cloudflared tunnel --url http://localhost:3000

На роутере ничего не меняется из-за направления, в котором идёт соединение. Ваша машина открывает исходящее соединение к граничному узлу провайдера, того же типа, что ваш браузер открывает для загрузки любой страницы, а провайдер держит его открытым и проталкивает входящие запросы обратно по нему. Входящие порты с вашей стороны остаются закрытыми, поэтому это работает в гостиничном Wi-Fi, через точку доступа телефона и на домашнем подключении, роутер которого вы не контролируете.

Примечание: последний случай заслуживает шестидесятисекундной проверки, прежде чем рассматривать проброс портов. Откройте страницу состояния роутера, найдите WAN-IP, который он показывает, и сравните его с вашим реальным публичным IP из любого сервиса «какой у меня IP». Если WAN-IP лежит внутри 100.64.0.0/10, вероятная причина — CGNAT. Если WAN-IP и публичный IP просто различаются, значит, выше по цепочке есть ещё один слой NAT, но это может быть как CGNAT, так и обычный двойной NAT. В любом случае проброса портов только на этом роутере может не хватить. Этот диапазон зарезервирован RFC 6598 как общее адресное пространство, и именно за него вас ставит провайдер, когда у него заканчиваются адреса.

Варианты различаются в основном тем, что они требуют от вас в первую очередь.

Быстрые туннели Cloudflare — это команда выше: без аккаунта, без домена, случайный поддомен на trycloudflare.com . Cloudflare ограничивает их 200 одновременными запросами, сверх этого возвращая 429, не поддерживает Server-Sent Events и в той же документации говорит, что бесплатные туннели предназначены для тестирования и разработки, а не для развёртывания продакшен-сайта.

ngrok сначала требует регистрации, а затем ngrok http 3000. Текущий бесплатный тариф даёт 5 $ разового включённого использования, которое не обновляется ежемесячно, до 3 онлайн-эндпоинтов, 1 ГБ трафика, 20 000 HTTP/S-запросов и промежуточную страницу с предупреждением, через которую гостю нужно кликнуть. Вы также получаете бесплатный автоматически выданный домен для разработки, о котором ngrok объявил в 2023 году , чтобы закрыть старую жалобу на URL, меняющийся при каждом перезапуске.

localtunnel не требует ни регистрации, ни установки, кроме npx: npx localtunnel --port 3000. Вы получаете случайный поддомен, и README прямо говорит, что --subdomain запрашивает имя, но не гарантирует его.

localhost.run ничего не устанавливает, потому что использует SSH-клиент, который уже есть в вашей ОС: ssh -R 80:localhost:3000 localhost.run. В документации отмечено, что скачивать ничего не нужно и что для бесплатных доменов не требуется создавать аккаунт.

VS Code умеет это в панели Ports, удобно, если вы и так живёте в редакторе. Нужен вход через GitHub или Microsoft, а значение по умолчанию вас подведёт: проброшенный порт является частным, то есть гостя попросят войти с вашей учётной записью, пока вы не переключите порт в публичный. (Нормально для коллеги. Бесполезно для клиента, который просто хочет кликнуть по ссылке.)

Tailscale Funnel тоже это умеет, с двумя ограничениями, которые обычно и решают дело: URL может жить только на домене вашего tailnet, и он может слушать только порты 443, 8443 и 10000.

Что бы вы ни выбрали, чётко понимайте, что именно вы раздали. С публичным туннелем без контроля доступа всё, что отдаёт dev-сервер, доступно любому, у кого есть этот URL, включая маршруты, на которые вы никогда не ссылались, и любой отладочный интерфейс, который вы оставили включённым. Нормально для пятнадцатиминутного демо. Гораздо хуже для URL, вставленного в публичный Discord.

Истечение застаёт врасплох, потому что выглядит так, будто приложение сломалось. Большинство быстрых путей здесь по-прежнему зависят от туннельного ПО на вашем ноутбуке: остановите cloudflared, ngrok, localtunnel или SSH-сессию localhost.run — и проброс прекратится. Tailscale Funnel — исключение, если запустить его с --bg: тогда конфигурация Funnel продолжает работать в фоне и восстанавливается после перезагрузки. Ни один из них не сможет отдавать ваше локальное приложение, пока сам ноутбук офлайн. Туннель можно держать запущенным днями, и он будет работать ровно до тех пор, пока не закроется крышка или вы не упрётесь в лимит запросов.

Туннель — правильный инструмент для демо и неправильный для хостинга: его аптайм равен аптайму вашего ноутбука.

Пусть приложение покинет вашу машину

Это первый путь, на котором ваш ноутбук перестаёт быть опорой, и первый, где условия важнее инструментов. Заканчивает всё здесь не таймер. Это усыпление, сброс файловой системы или тариф, решивший, что ваше приложение — не то, что он хочет видеть на бесплатном инстансе.

Варианты ниже — от постоянных бесплатных тарифов до коротких пробных периодов. Одни могут держать приложение онлайн бессрочно в рамках своих лимитов; другие останавливаются после фиксированного пробного периода или требуют платный аккаунт за вычисления. Проверьте правила оплаты, сна и хранения перед развёртыванием.

Условия бесплатных тарифов ниже сверены со страницами цен или документации каждого провайдера 7 сентября 2026 года.

ПровайдерКоммерческое использование?Переживают ли данные перезапуск?Подвох
NetlifyРазрешеноДа, с Netlify Blobs или DatabaseКарта для старта не нужна; если израсходовать все месячные кредиты тарифа Free, проекты ставятся на паузу до следующего расчётного периода, если не перейти на платный тариф
RenderНе указаноТеряются при перезапускеКарта для старта не нужна; засыпает после 15 минут простоя; бесплатный Postgres истекает через 30 дней после создания
Cloudflare Pages / WorkersНе указаноДа, с KV, D1, R2 или Durable Objects500 сборок Pages в месяц; бесплатный Workers ограничен 100 000 запросами в день
VercelНе на HobbyТеряются при перезапускеHobby только для личного использования; файловая система функций доступна только для чтения
GitHub PagesЗапрещеноТолько статический результатНикакого онлайн-бизнеса, e-commerce или коммерческого SaaS; таймаут развёртывания 10 минут
PythonAnywhereНе указаноДаБесплатные аккаунты достигают только белого списка внешних хостов; бесплатное веб-приложение истекает через месяц , если его не продлить
Fly.ioНе указаноДа, с Fly VolumeПостоянного бесплатного тарифа нет: 2 машино-часа или 7 дней; пробные Machines автоматически останавливаются через 5 минут работы, а пробный период включает 20 ГБ хранилища на томах; после окончания пробного периода приложения останавливаются, пока вы не добавите карту
KoyebНе указаноНет постоянного локального хранилищаНужна карта; Koyeb делает и отменяет предавторизацию на 29 $, но при регистрации по умолчанию выбран Pro, и его пропорциональная стоимость списывается, если не переключиться на Starter
Hugging Face SpacesНе указаноТеряются при перезапускеStatic Spaces бесплатны; Gradio и Docker в целом требуют платного тарифа, но подходящие бесплатные личные аккаунты могут размещать до двух Gradio Spaces на ZeroGPU
RailwayНе указаноДа, если приложение использует включённый том на 0,5 ГБ30-дневный пробный период с разовым кредитом 5 $, затем тариф Free за 0 $ с 1 $ кредита на ресурсы в месяц; карта не требуется

«Не указано» означает, что собственные страницы провайдера не отвечают на этот вопрос для бесплатного тарифа. Считайте это неизвестным, а не «да» или «нет».

Три из этих строк заслуживают отдельного взгляда перед стартом. У Fly.io нет постоянного бесплатного тарифа: пробный период заканчивается через 2 машино-часа или 7 дней. У Koyeb есть бесплатный инстанс, но процесс регистрации и оплаты требует внимания перед развёртыванием. Hugging Face оставляет Static Spaces бесплатными, тогда как новые Gradio- и Docker-Spaces требуют платного аккаунта, за исключением ограниченного исключения ZeroGPU. Railway больше не место в этом списке предупреждений: после 30-дневного пробного периода с 5 $ кредита он теперь переходит на тариф Free за 0 $ с 1 $ кредита на ресурсы в месяц.

Затем встаёт вопрос данных — именно здесь работающее приложение незаметно превращается в сломанное. Бесплатные веб-сервисы Render работают на эфемерной файловой системе, и документация говорит прямо: всё, что туда записано, включая загруженные изображения и локальные базы SQLite, теряется при каждом повторном развёртывании, перезапуске и усыплении. Функции Vercel работают на файловой системе только для чтения с одним лишь временным рабочим пространством, так что файл SQLite, который пишет ваше приложение, там тоже не в безопасности. Если приложение хранит состояние в файле, перенесите его в надёжное хранилище: управляемую базу данных, объектное хранилище или постоянный том там, где платформа его предлагает.

Усыпление стоит прочувствовать до того, как вы на что-то подпишетесь. На бесплатном тарифе Render 15 минут простоя отправляют сервис спать, а следующий запрос будит его примерно за минуту, показывая страницу загрузки тому, кто кликнул по вашей ссылке. Для портфолио — пожать плечами. Для клиента, открывающего ссылку во время созвона, — шестьдесят очень плохих секунд.

У PythonAnywhere ловушка более тонкая. Усыпления по простою нет, но бесплатное веб-приложение истекает через месяц и останавливается, если не кликнуть по ссылке продления, которую PythonAnywhere присылает на почту, а бесплатные аккаунты получают ограниченный исходящий доступ в интернет и достигают только белого списка внешних хостов. Приложение, вызывающее API вне этого списка, стоит себе полностью онлайн и проваливает каждый запрос к этому неразрешённому API (ужасно отлаживать, потому что нигде ничего не выглядит упавшим).

Выпустите его как статический сайт

Если ничто из того, что делает приложение, не требует серверного кода в момент запроса, статический хостинг здесь ближе всего к «настроил и забыл»: он может оставаться онлайн без вашего ноутбука, и там нет процесса приложения, ждущего пробуждения. Аккаунт и лимиты хостинга по-прежнему действуют. Подходящих приложений больше, чем кажется, поэтому на первый из тех трёх вопросов стоит ответить до того, как решать, что вам нужен серверный хостинг.

Правило уже, чем «есть ли у него бэкенд». Приложение подходит, если каждый его запрос идёт либо к вашим статическим файлам, либо напрямую из браузера в чужой API. Обращаться к Supabase или публичному API из браузера нормально, с одной оговоркой: ключ в коде браузера — это ключ, который вы опубликовали. Дверь закрывает необходимость выполнять ваш собственный код на сервере при каждом запросе.

Если подходит, схема короткая:

npm run build   # Vite writes to dist/, a Next.js static export writes to out/

Затем разверните результат сборки на статическом хостинге. Cloudflare Pages, Netlify и Vercel умеют собирать из подключённого репозитория. GitHub Pages может публиковать статические файлы из ветки или использовать GitHub Actions, чтобы запустить сборку вашего фреймворка и развернуть сгенерированный результат.

У GitHub Pages ограничения достаточно жёсткие, чтобы учитывать их с самого начала. Только статика, один пользовательский или организационный сайт на аккаунт, и условия использования, где сказано, что это не бесплатный хостинг для бизнеса, e-commerce-сайта или коммерческого SaaS. Если приложение будет принимать платежи, это исключает его ещё до начала.

У этого пути нет истечения процесса приложения. Он продолжает работать, пока аккаунт хостинга активен и в рамках лимитов, и перестаёт подходить, как только приложению нужна серверная работа в момент запроса.

Где заканчиваются бесплатные пути

Бесплатные пути ломаются в разных местах, а не все сразу. Статический хостинг уже решает вопрос аптайма ноутбука и даёт стабильный URL провайдера. Бесплатный хостинг приложений может то же самое, а некоторые теперь включают постоянное хранилище. VPS начинает иметь смысл, когда требования накапливаются: ваш собственный серверный процесс должен оставаться онлайн, нужно предсказуемое постоянное хранилище, а правила ресурсов или использования бесплатного тарифа больше не подходят.

Этот порог стоит уважать. Одно демо — не повод покупать сервер, как и статический проект с низким трафиком. Оставайтесь на туннеле для короткого шеринга, на статическом хостинге — пока приложение действительно статическое, и на бесплатном хостинге приложений — пока его лимиты соответствуют тому, что вы запускаете.

Переходите на VPS, когда вам нужен постоянно работающий сервер под вашим контролем и вы готовы взять на себя сопутствующую эксплуатационную работу. Наш Linux VPS — один из вариантов, и сопоставимый VPS у другого провайдера справится с той же задачей. Подбирайте сервер под приложение, а не рассчитывайте, что хватит самого маленького тарифа.

Посмотреть тарифы Linux

Разрабатывайте на Linux VPS с root-доступом, NVMe и мощью AMD EPYC.

Посмотреть тарифы Linux

После этого меняются две вещи. Рабочий процесс развёртывания «push в git», который давал платформенный хостинг, больше не автоматический. Его можно воссоздать с помощью self-hosted PaaS вроде Coolify или Dokkuили построить собственный CI/CD-путь, и в любом случае обновления и обслуживание теперь на вас.

Второе изменение: на машине живёт не только приложение. Она с радостью будет запускать Code Server и Claude Code , если вы предпочитаете, чтобы там жил и ваш редактор, что либо приятный бонус, либо целые новые выходные — зависит от вас.

Часто задаваемые вопросы

Почему мой публичный URL перестал работать после того, как я закрыл ноутбук?

Потому что туннель был привязан к процессу, который его создал, а не к приложению. Закрытие ноутбука или завершение терминала останавливает этот процесс, публичный URL умирает, а с приложением всё в порядке. Перезапуск туннеля даёт новый URL, если только инструмент не выдаёт вам зарезервированный домен. Если ссылка должна пережить сон ноутбука, приложение должно покинуть вашу машину.

Нужно ли доменное имя, чтобы вывести локальное приложение на публичный URL?

Нет, почти во всех случаях. Быстрый туннель Cloudflare, выданный ngrok домен для разработки, localtunnel, localhost.run и бесплатные тарифы хостинга выше бесплатно выдают вам поддомен на своём домене. Исключение — именованный туннель Cloudflare, которому нужен домен, уже добавленный в Cloudflare DNS.

Может ли кто-то из другой Wi-Fi-сети открыть мой локальный IP-адрес?

Нет. Адрес вроде 192.168.1.42 указывает на то устройство, которому он достался в сети, к которой вы сейчас подключены, а в любой другой сети это другое устройство или вообще ничего. Любому вне вашего Wi-Fi нужен туннель, бесплатный тариф хостинга или статический хостинг.

Что из этого работает, если у приложения есть вход и база данных?

Пути «одна сеть» и «туннель» работают без изменений, потому что приложение по-прежнему запущено на вашей машине. Статическое развёртывание тоже может работать, если запросы входа и базы данных идут напрямую из браузера в размещённый сервис и ни для одного запроса не нужно выполнять приватный серверный код. Если вашему собственному коду аутентификации или базы данных нужен сервер в момент запроса, используйте серверный хостинг. На бесплатном хостинге приложений держите постоянные данные в надёжном хранилище, а не рассчитывайте, что локальная файловая система приложения уцелеет.

Поделиться

Обсуждение

Комментарии

Войдите, чтобы присоединиться к обсуждению.

Ещё в блоге

Читайте дальше.

Готовы к развёртыванию? От $2,48/мес.

Независимое облако с 2008 года. AMD EPYC, NVMe, 40 Gbps. Возврат денег в течение 14 дней.