Все статьи
HTTPSmkcertlocal developmentlocalhost tunneling

HTTPS на localhost: mkcert против туннеля, честное сравнение

Два инструмента, одна задача: ваш dev-сервер должен быть доступен по HTTPS. mkcert даёт локально доверенный TLS-сертификат, так что https://localhost:3000 просто работает. Туннель даёт публичный HTTPS-URL с настоящим сертификатом от настоящего CA. Они не конкуренты — решают разные задачи, — но люди постоянно относятся к ним как к конкурентам.

Короткий ответ

  • Нужен HTTPS только на своей машине, для своего браузера? Берите mkcert.
  • Нужно, чтобы внешний сервис (Stripe, GitHub, Auth0, телефон) достучался до dev-сервера? Берите туннель.
  • И то и другое? Запустите оба. Они не конфликтуют.

Это вся статья в трёх пунктах. Остальное — лишь почему.

mkcert: локально доверенные сертификаты за 30 секунд

mkcert устанавливает локальный удостоверяющий центр в хранилище доверия вашей ОС и выпускает из него сертификаты. Браузер видит сертификат как доверенный, потому что доверенный CA. Никаких предупреждений подключение не защищено, никаких флагов --ignore-certificate-errors, никакой самодельной возни с self-signed.

# один раз на машину
mkcert -install

# один раз на проект
mkcert localhost 127.0.0.1

# теперь у вас localhost.pem и localhost-key.pem

Подключите их к dev-серверу (Vite, Next.js, Express, Django runserver_plus — все поддерживают TLS-аргументы), и у вас https://localhost:3000 с настоящим сертификатом.

Подвох: этому CA доверяет только ваша машина. Браузер коллеги выдаст предупреждение. Телефон не доверится без ручной установки корня CA.

Туннель: настоящий HTTPS, настоящий публичный URL

localhost-туннель перенаправляет трафик с публичного HTTPS-URL на ваш локальный порт. Сертификат выпущен настоящим CA (Let's Encrypt и т. п.) и доверен каждым браузером на каждом устройстве.

npx portpreview 3000

Туннель выполняет терминирование TLS на облачном шлюзе. Локальный сервер может остаться на обычном HTTP — публичный URL это HTTPS, и именно его касается каждый внешний сервис.

Бок о бок

ПотребностьmkcertТуннель
HTTPS в локальном браузереДаДа (через публичный URL)
Тест service worker / secure cookie в браузереДаДа
Внешний провайдер может вас достатьНетДа
Телефон в руке может вас достатьНет (без установки CA)Да
OAuth-провайдер принимает URLИногда (Google: да; многие: нет)Да
Stripe / GitHub / Twilio могут слать вебхукНетДа
Время настройки30 секунд на машинуОдна команда на сессию
Работает офлайнДаНет
Переживает авиарежимДаНет

Где люди ошибаются

Пытаются использовать mkcert для тестирования вебхуков

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

Используют туннель для сольного HTTPS только в браузере

Если нужно лишь, чтобы заработали service worker или установилась secure cookie в собственном браузере, mkcert быстрее и работает офлайн. Не жгите сессию туннеля на то, что решает файл сертификата.

Выбирают один инструмент и протискивают через него другой кейс

Запускать оба — нормально. Большая часть нашей настройки использует mkcert для ежедневной работы со стороны браузера и туннель, когда тестируем вебхуки или OAuth-колбэки. Они сосуществуют в package.json без конфликта.

А как же Caddy или nginx?

Да, можно запустить Caddy с автоматическим HTTPS перед dev-сервером, и это тоже работает — по сути это «mkcert с лишними шагами и обратным прокси». Для большинства локальной разработки mkcert проще. Для более сложной маршрутизации с несколькими локальными сервисами Caddy оправдывает себя.

Наша реальная настройка

В одном репозитории, где мы работаем, есть mkcert в dev-скрипте для HTTPS на стороне localhost и отдельный npm-скрипт tunnel, запускающий portpreview, когда кому-то нужны вебхуки или тестирование на мобильных. URL туннеля передаётся через env-переменную, чтобы OAuth redirect URI было легко менять. Сборка заняла 20 минут, и с тех пор мы больше не думали о локальном TLS.

О настройке туннеля под OAuth см. как тестировать OAuth-колбэки локально. Чтобы делиться превью с коллегами или дизайнерами — поделиться локальным dev-сервером. Запишитесь в лист ожидания PortPreview ради туннельной части этой настройки.

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

Что использовать для локального HTTPS — mkcert или туннель?
Оба, для разного. mkcert даёт вашему браузеру доверенный сертификат на localhost и работает офлайн. Туннель даёт публичный HTTPS-URL, доступный внешним сервисам и другим устройствам. Они не конфликтуют — большинство команд используют оба.
Справится ли mkcert с тестированием вебхуков от Stripe или GitHub?
Нет. Сертификаты mkcert доверены только на машине, где установлен CA. Внешние провайдеры вебхуков не могут достучаться до localhost, как бы доверенным сертификат ни выглядел в вашем браузере. Для любого входящего публичного трафика используйте туннель.
Работает ли mkcert для OAuth-колбэков на localhost?
Некоторые провайдеры (Google, отдельные dev-уровни Auth0) принимают localhost по HTTP или HTTPS для разработки. Многие — нет. mkcert даёт HTTPS для тех, кто принимает; для строгих нужен туннель с публичным HTTPS-URL.