Все статьи
Сравнение HTTPS на локальном сертификате и HTTPS через туннель на localhost.
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.