Set Up Trusted Local HTTPS with mkcert
Generate a real, browser-trusted TLS certificate for localhost in minutes — no more certificate warnings during local development.
What You'll Build
You'll install mkcert, register a local Certificate Authority with your OS and browser, and generate a TLS certificate so any dev server runs on https://localhost with a padlock and no warnings — identical behavior to a production HTTPS endpoint.
Prerequisites
| Requirement | Details |
|---|---|
| macOS 12+ or Ubuntu 20.04+ | Windows users: swap brew install for scoop install mkcert |
| Homebrew | macOS/Linux — install at brew.sh |
| Node.js 18+ | Only needed for the example server |
Step 1 — Install mkcert
brew install mkcert
Firefox users need extra NSS tooling installed before Step 2, or Firefox won't trust the CA:
# macOS
brew install nss
# Ubuntu / Debian Linux
sudo apt install libnss3-tools
Step 2 — Create and Install Your Local CA
This single command creates a root Certificate Authority and registers it with your OS trust store. Chrome and Safari pick it up automatically. Run this once per machine — not once per project.
mkcert -install
You'll be prompted for your system password. To confirm where the CA files live:
mkcert -CAROOT
# Example: /Users/you/Library/Application Support/mkcert
⚠ Security note: The CA root key lives only on your machine. Never commit it or share it — anyone with it can issue trusted certificates for any domain on any browser that trusts your CA.
Step 3 — Generate a Certificate for Localhost
From your project directory, run:
mkcert localhost 127.0.0.1 ::1
Covering the hostname, IPv4, and IPv6 loopback means it works however your server binds. Two files appear in the current directory:
| File | Purpose |
|---|---|
localhost+2.pem |
Certificate (public — safe to commit if needed) |
localhost+2-key.pem |
Private key — never commit this |
Add the key pattern to .gitignore immediately:
echo "*-key.pem" >> .gitignore
Step 4 — Start a Secure Dev Server
Create server.js using Node's built-in https module — no extra packages required:
const https = require('https');
const fs = require('fs');
const server = https.createServer(
{
key: fs.readFileSync('localhost+2-key.pem'),
cert: fs.readFileSync('localhost+2.pem'),
},
(req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello, secure localhost!\n');
}
);
server.listen(3000, () => console.log('Listening on https://localhost:3000'));
node server.js
Verify It Works
Open https://localhost:3000 in your browser. You should see:
- A padlock icon with no security warning
- The text
Hello, secure localhost!
Also verify with curl — if the CA is trusted system-wide, this works too:
curl https://localhost:3000
# Hello, secure localhost!
Troubleshooting
Firefox still shows a certificate warning
Firefox uses its own NSS certificate store. Install nss (macOS: brew install nss) or libnss3-tools (Linux: sudo apt install libnss3-tools), then re-run mkcert -install and fully restart Firefox.
mkcert -install warns it can't write to the system trust store on Linux
Always run mkcert -install as your normal (non-root) user — never prefixed with sudo. mkcert internally requests elevated privileges (via sudo or pkexec) only when it needs to write to the system trust store, so you'll be prompted automatically. Running the entire command as root stores the CA under the root user's home directory; subsequent non-root runs won't find it and will generate a new, untrusted CA instead.
ENOENT: no such file or directory, open 'localhost+2-key.pem'
Cert files are created in whichever directory was active when you ran mkcert. Move them to your project root or use the full absolute path in readFileSync.
Chrome shows NET::ERR_CERT_AUTHORITY_INVALID right after install
Chrome caches the trust store at startup. Fully quit Chrome (Cmd+Q / Alt+F4) and relaunch — it will pick up the new CA on restart.
Next Steps
- Vite projects:
vite-plugin-mkcertautomates certificate wiring insidevite.config.js. - Custom
.testdomains: Add127.0.0.1 myapp.testto/etc/hosts, then runmkcert myapp.testto mirror your real domain name locally. - Other frameworks: Pass the same
key/certpaths to Express, Fastify, or any HTTPS-capable server — the options are identical. - Production TLS: mkcert is development-only. Use Let's Encrypt (via Certbot or your platform's managed TLS) for staging and production environments.
Lenn writes about cloud platforms, Kubernetes internals, and the infrastructure decisions that quietly make or break engineering organizations. Based in Berlin's vibrant tech scene, they have a talent for turning dense platform-engineering topics into prose that people actually finish reading.
Discussion 0
No comments yet
Be the first to weigh in.