Problem: Browser Won't Trust Your Local HTTPS Server
Your local dev server runs on HTTPS but browsers show "Your connection is not private" warnings, blocking API calls and breaking OAuth flows that require secure contexts.
You'll learn:
- Why self-signed certificates fail in modern browsers
- How to generate trusted local certificates
- Setting up HTTPS for React, Next.js, and Vite
Time: 12 min | Level: Beginner
Why This Happens
Browsers require certificates signed by a trusted Certificate Authority (CA). Your self-signed localhost certificate isn't in the system's trust store, so browsers treat it as potentially malicious.
Common symptoms:
NET::ERR_CERT_AUTHORITY_INVALIDin Chrome DevTools- "This Connection Is Not Private" warnings
- Service workers won't register
- OAuth redirects fail on localhost
Solution
Step 1: Install mkcert
mkcert creates locally-trusted certificates automatically.
# macOS
brew install mkcert
brew install nss # for Firefox support
# Ubuntu/Debian
sudo apt install libnss3-tools
wget https://github.com/FiloSottile/mkcert/releases/download/v1.4.4/mkcert-v1.4.4-linux-amd64
sudo mv mkcert-v1.4.4-linux-amd64 /usr/local/bin/mkcert
sudo chmod +x /usr/local/bin/mkcert
# Windows (PowerShell as Admin)
choco install mkcert
Expected: mkcert -version shows v1.4.4 or newer
Step 2: Create Local CA
# Install local CA in system trust store
mkcert -install
Why this works: Adds mkcert's root certificate to your OS and browser trust stores. All certificates it generates will now be trusted.
You should see: "The local CA is now installed in the system trust store!"
Step 3: Generate Certificates
# Create certs directory in your project
mkdir -p .cert
cd .cert
# Generate certificate for localhost
mkcert localhost 127.0.0.1 ::1
# For custom domains (add to /etc/hosts first)
mkcert myapp.local
Expected: Creates localhost.pem (certificate) and localhost-key.pem (private key)
If it fails:
- "permission denied": Add
sudobeforemkcert -install - Firefox still warns: Install
nsspackage and re-run-install
Step 4: Configure Your Dev Server
React (Create React App)
// package.json
{
"scripts": {
"start": "HTTPS=true SSL_CRT_FILE=.cert/localhost.pem SSL_KEY_FILE=.cert/localhost-key.pem react-scripts start"
}
}
Next.js
// server.js
const { createServer } = require('https');
const { parse } = require('url');
const next = require('next');
const fs = require('fs');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const httpsOptions = {
key: fs.readFileSync('./.cert/localhost-key.pem'),
cert: fs.readFileSync('./.cert/localhost.pem')
};
app.prepare().then(() => {
createServer(httpsOptions, (req, res) => {
handle(req, res, parse(req.url, true));
}).listen(3000, () => {
console.log('> Ready on https://localhost:3000');
});
});
// package.json
{
"scripts": {
"dev": "node server.js"
}
}
Vite
// vite.config.ts
import { defineConfig } from 'vite';
import fs from 'fs';
export default defineConfig({
server: {
https: {
key: fs.readFileSync('./.cert/localhost-key.pem'),
cert: fs.readFileSync('./.cert/localhost.pem'),
},
port: 3000
}
});
Verification
# Start your dev server
npm run dev
# Test in browser
curl -I https://localhost:3000
You should see: No certificate warnings in browser. DevTools shows valid certificate under Security tab.
What You Learned
- mkcert creates CA-signed certificates for local development
- Modern browsers require trusted certificates even for localhost
- Each framework has different HTTPS configuration methods
Limitations:
- Certificates only trusted on your machine (teammates need their own)
- Don't commit
.cert/to git (add to.gitignore) - Expires after 2 years (regenerate with same commands)
Troubleshooting
Certificate still not trusted?
# Verify CA installation
mkcert -CAROOT
# Reinstall CA
mkcert -uninstall
mkcert -install
Need to trust on mobile device?
# Get CA certificate
cat "$(mkcert -CAROOT)/rootCA.pem"
# Email to yourself and install on iPhone/Android
# iOS: Settings → Profile Downloaded → Install
# Android: Settings → Security → Install from storage
Docker containers can't verify?
# Add to Dockerfile
COPY .cert/rootCA.pem /usr/local/share/ca-certificates/
RUN update-ca-certificates
Tested with mkcert 1.4.4, Chrome 130, Firefox 133, Safari 17, Node.js 22.x