All Deployment guides Deployment

HTTPS for Localhost: SSL Certificates for Local Development

Modern web APIs (service workers, geolocation, clipboard, camera) require HTTPS — even during development. This guide covers how to get trusted HTTPS on localhost without browser warnings.

Why you can’t use Let’s Encrypt for localhost

Let’s Encrypt validates domain ownership by checking a file on your server or a DNS record. localhost isn’t a real domain — it resolves to 127.0.0.1 on your machine only. No one can verify you “own” localhost, so no public CA will issue a certificate for it.

Your options for localhost HTTPS:

  1. mkcert — creates locally-trusted certificates (recommended)
  2. Self-signed certificate — works but shows browser warnings
  3. Tunneling service — ngrok, Cloudflare Tunnel (real domain, real cert)

mkcert creates a local Certificate Authority on your machine, adds it to your system trust store, and issues certificates signed by that CA. Browsers trust these certificates with no warnings.

Install mkcert

# macOS
brew install mkcert

# Linux (requires libnss3-tools for Firefox)
sudo apt install libnss3-tools
brew install mkcert  # or download from GitHub releases

# Windows
choco install mkcert
# or: scoop install mkcert

Set up the local CA

mkcert -install
# Output: Created a new local CA
# The local CA is now installed in the system trust store

This adds a root certificate to your system and browser trust stores. Do this once — it works for all future certificates.

Generate certificates

# For localhost
mkcert localhost 127.0.0.1 ::1

# For a custom local domain
mkcert myapp.test "*.myapp.test" localhost 127.0.0.1

# Output:
# Created a new certificate valid for the following names:
#  - "localhost"
#  - "127.0.0.1"
#  - "::1"
# The certificate is at "./localhost+2.pem" and the key at "./localhost+2-key.pem"

Use with your dev server

Node.js/Express:

const https = require('https');
const fs = require('fs');
const app = require('./app');

https.createServer({
  key: fs.readFileSync('./localhost+2-key.pem'),
  cert: fs.readFileSync('./localhost+2.pem'),
}, app).listen(3000);

Nginx (local):

server {
    listen 443 ssl;
    server_name localhost;
    ssl_certificate     /path/to/localhost+2.pem;
    ssl_certificate_key /path/to/localhost+2-key.pem;
    # ...
}

Vite / webpack dev server:

// vite.config.js
import fs from 'fs';
export default {
  server: {
    https: {
      key: fs.readFileSync('./localhost+2-key.pem'),
      cert: fs.readFileSync('./localhost+2.pem'),
    },
  },
};

Security warning

Never share the mkcert root CA key (rootCA-key.pem in mkcert -CAROOT). Anyone who has it can create trusted certificates for any domain on your machine — essentially a local man-in-the-middle capability.

mkcert is for development only. For production, use Let’s Encrypt.

Option 2: Self-signed certificate

If you can’t install mkcert, generate a self-signed certificate with OpenSSL:

openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 \
  -keyout localhost-key.pem -out localhost-cert.pem \
  -days 365 -nodes -subj "/CN=localhost" \
  -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"

Downside: Browsers show a security warning because self-signed certificates aren’t trusted by any CA. You’ll need to click through the warning each time (or add an exception).

Option 3: Tunneling (real domain + real certificate)

Use a tunneling service to expose your local server with a real domain and certificate:

# ngrok
ngrok http 3000
# Gives you: https://abc123.ngrok.io

# Cloudflare Tunnel
cloudflared tunnel --url http://localhost:3000
# Gives you: https://random-name.trycloudflare.com

When this makes sense: testing webhooks, sharing with a teammate, testing OAuth callbacks that require HTTPS.

mkcert vs self-signed vs tunneling

mkcertSelf-signedTunneling
Browser warningsNoneYes (every session)None
Setup effortLow (one install)Low (one command)Low
Works offline
PerformanceLocal speedLocal speedNetwork latency
Custom domains✅ (*.test, etc.)Provider-assigned
Best forDaily developmentQuick one-offWebhooks, sharing

Frequently asked questions

Can I use the same mkcert certificate across my team?

Don’t share the root CA key. Each developer should run mkcert -install on their own machine to create their own local CA. You can share the generated certificates (the .pem files), but each person needs the CA installed to trust them.

Does mkcert work with Docker?

Yes. Mount the certificate files into the container and reference them in the server config. The container itself doesn’t need mkcert installed — just the .pem files. Your host machine (where the browser runs) needs the mkcert CA installed.

Which local domain should I use?

Use .test (e.g., myapp.test) — it’s reserved by IETF for testing and will never conflict with a real domain. Avoid .dev (owned by Google) and .local (used by mDNS). Add an entry to /etc/hosts to point your .test domain to 127.0.0.1.

How do I switch from localhost HTTPS to production HTTPS?

They’re completely separate. Your localhost certificate (mkcert/self-signed) stays on your dev machine. For production, get a real certificate from Let’s Encrypt via GetHTTPS. Your code should read cert paths from environment variables so the switch is just changing a config.

Related articles

Getting Started 2026-05-08
How to Get a Free SSL Certificate (Step-by-Step Guide)
Get a free SSL certificate from Let's Encrypt in 5 minutes — no software to install, no account to create. Complete guide covering 4 methods, both challenge types, installation on 6 platforms, and troubleshooting.
Deployment 2026-05-08
How to Use SSL Certificates with Node.js
Configure HTTPS in Node.js and Express. Load PEM certificate files, set up TLS options, and handle both development and production SSL.
Deployment 2026-05-08
SSL Certificates with Docker and Reverse Proxies
Configure HTTPS for Docker containers using Nginx reverse proxy, Traefik with automatic Let's Encrypt, or manual certificate mounting.
Get a free SSL certificate in your browser
No installation, no account. Your private key never leaves your device.
Get your certificate