Fix SSL/TLS Certificate Errors in Local Dev in 12 Minutes

Solve localhost HTTPS certificate warnings and NET::ERR_CERT_AUTHORITY_INVALID errors with mkcert for trusted local development.

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_INVALID in 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 sudo before mkcert -install
  • Firefox still warns: Install nss package 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