Local HTTPS Development Setup
Get trusted HTTPS certificates for local development using mkcert + Caddy.
Why Local HTTPS?
Section titled “Why Local HTTPS?”- Test HTTPS-only features (Service Workers, HTTP/3, etc.)
- Match production environment
- No browser security warnings
- Test with real certificates
Method 1: Self-Signed (Quick)
Section titled “Method 1: Self-Signed (Quick)”1. Update Caddyfile
Section titled “1. Update Caddyfile”chat.local { tls internal # Self-signed cert reverse_proxy faster-chat:8787 encode gzip zstd}2. Add to /etc/hosts
Section titled “2. Add to /etc/hosts”echo "127.0.0.1 chat.local" | sudo tee -a /etc/hosts3. Restart Caddy
Section titled “3. Restart Caddy”docker compose -f docker-compose.yml -f docker-compose.caddy.yml restart caddy4. Access
Section titled “4. Access”Note: Browser will show security warning - click “Advanced” → “Proceed”
Method 2: mkcert (Trusted Certificates - Recommended!)
Section titled “Method 2: mkcert (Trusted Certificates - Recommended!)”1. Install mkcert
Section titled “1. Install mkcert”Arch Linux:
sudo pacman -S mkcert nssDebian/Ubuntu:
sudo apt install libnss3-toolscurl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64"chmod +x mkcert-v*-linux-amd64sudo mv mkcert-v*-linux-amd64 /usr/local/bin/mkcertmacOS:
brew install mkcert2. Create Local Certificate Authority
Section titled “2. Create Local Certificate Authority”mkcert -installThis installs a local CA in your system trust store - all browsers will trust it!
3. Generate Certificates
Section titled “3. Generate Certificates”cd /home/mikekey/Projects/1_React/faster-chat
# Create certs directorymkdir -p certs
# Generate cert for chat.localmkcert -cert-file certs/cert.pem -key-file certs/key.pem \ chat.local localhost 127.0.0.1 ::14. Update Caddyfile
Section titled “4. Update Caddyfile”chat.local { tls /etc/caddy/certs/cert.pem /etc/caddy/certs/key.pem reverse_proxy faster-chat:8787
encode gzip zstd
# Optional: Security headers header { Strict-Transport-Security "max-age=31536000" X-Content-Type-Options "nosniff" }}
# Also work with localhost HTTPSlocalhost { tls /etc/caddy/certs/cert.pem /etc/caddy/certs/key.pem reverse_proxy faster-chat:8787}5. Mount Certificates in Docker
Section titled “5. Mount Certificates in Docker”Update docker-compose.caddy.yml:
services: caddy: image: caddy:2-alpine restart: unless-stopped ports: - "80:80" - "443:443" - "443:443/udp" volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - ./certs:/etc/caddy/certs:ro # Add this line - caddy-data:/data - caddy-config:/config depends_on: - faster-chat6. Add to /etc/hosts
Section titled “6. Add to /etc/hosts”echo "127.0.0.1 chat.local" | sudo tee -a /etc/hosts7. Restart Everything
Section titled “7. Restart Everything”docker compose -f docker-compose.yml -f docker-compose.caddy.yml downdocker compose -f docker-compose.yml -f docker-compose.caddy.yml up -d8. Access with Trusted HTTPS
Section titled “8. Access with Trusted HTTPS”- https://chat.local ✅ No warnings!
- https://localhost ✅ Fully trusted!
Method 3: LAN Access (Other Devices)
Section titled “Method 3: LAN Access (Other Devices)”Want to access from phone/tablet on your local network?
1. Find Your LAN IP
Section titled “1. Find Your LAN IP”ip addr show | grep "inet 192.168"# Example: 192.168.1.1002. Generate Cert for LAN IP
Section titled “2. Generate Cert for LAN IP”mkcert -cert-file certs/cert.pem -key-file certs/key.pem \ chat.local localhost 127.0.0.1 ::1 \ 192.168.1.100 # Your actual LAN IP3. Update Caddyfile
Section titled “3. Update Caddyfile”chat.local, localhost, 192.168.1.100 { tls /etc/caddy/certs/cert.pem /etc/caddy/certs/key.pem reverse_proxy faster-chat:8787}4. Access from Other Devices
Section titled “4. Access from Other Devices”On your phone/tablet, install the mkcert CA certificate:
# On your computer, get the CA certcat "$(mkcert -CAROOT)/rootCA.pem"
# Copy output, paste into a file on your phone# Install it in Settings → Security → Install CertificateThen access: https://192.168.1.100
Method 4: Tailscale + Let’s Encrypt (Real Certs!)
Section titled “Method 4: Tailscale + Let’s Encrypt (Real Certs!)”If you use Tailscale, you can get real Let’s Encrypt certificates for your tailnet domain!
1. Enable HTTPS in Tailscale
Section titled “1. Enable HTTPS in Tailscale”# Enable MagicDNS and HTTPS certificates in Tailscale admin2. Update Caddyfile
Section titled “2. Update Caddyfile”your-machine-name.your-tailnet.ts.net { # Caddy automatically gets Let's Encrypt cert! reverse_proxy faster-chat:8787}3. Access from Anywhere on Tailnet
Section titled “3. Access from Anywhere on Tailnet”https://your-machine-name.your-tailnet.ts.net
Real certificate, works everywhere on your Tailscale network!
Troubleshooting
Section titled “Troubleshooting”Certificate Not Trusted
Section titled “Certificate Not Trusted”If mkcert-generated certs aren’t trusted:
# Reinstall CAmkcert -uninstallmkcert -install
# Restart browser completely (not just refresh)Caddy Not Finding Certificates
Section titled “Caddy Not Finding Certificates”Check file permissions:
ls -la certs/# Should be readable by allchmod 644 certs/*.pemCheck Docker mount:
docker exec faster-chat-caddy-1 ls -la /etc/caddy/certs/Chrome Still Shows Warning
Section titled “Chrome Still Shows Warning”Chrome caches HSTS. Clear it:
chrome://net-internals/#hsts→ Delete domain security policies for "chat.local"Firefox Won’t Trust mkcert
Section titled “Firefox Won’t Trust mkcert”Firefox uses its own certificate store:
# Find your Firefox profilels ~/.mozilla/firefox/
# mkcert should auto-install, but verify:certutil -d sql:~/.mozilla/firefox/PROFILE.default -LQuick Reference
Section titled “Quick Reference”| Method | Trust Level | Setup Time | Use Case |
|---|---|---|---|
| Self-signed | ❌ Untrusted | 30 sec | Quick testing |
| mkcert | ✅ Trusted | 2 min | Local development |
| Tailscale | ✅ Real CA | 5 min | Remote access |
| LAN IP + mkcert | ✅ Trusted* | 5 min | Testing on devices |
*Requires installing CA on each device
Recommended Setup (Complete)
Section titled “Recommended Setup (Complete)”# 1. Install mkcertsudo pacman -S mkcert nss # Arch# or: brew install mkcert # macOS
# 2. Create local CAmkcert -install
# 3. Generate certificatescd /path/to/faster-chatmkdir -p certsmkcert -cert-file certs/cert.pem -key-file certs/key.pem \ chat.local localhost 127.0.0.1 ::1
# 4. Add to hostsecho "127.0.0.1 chat.local" | sudo tee -a /etc/hosts
# 5. Update docker-compose.caddy.yml to mount certs/
# 6. Update Caddyfile with TLS paths
# 7. Restartdocker compose -f docker-compose.yml -f docker-compose.caddy.yml up -d
# 8. Accessopen https://chat.localYou’ll have fully trusted HTTPS for local development! 🔒✨