Два инструмента, одна задача: ваш 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 ради туннельной части этой настройки.