lan-ca: Local HTTPS in 300 Lines of Go
Getting HTTPS working on .lan domains is annoying. Let’s Encrypt won’t issue certs for non-public domains. Self-signed certs trigger browser warnings. mkcert exists but felt like overkill for my needs.
So I wrote a 300-line Go tool that does exactly what I need: create a root CA once, generate certs for any .lan domain, trust it on macOS with one command.
The Tool
# Initialize (creates ~/.lan-ca/ca.crt and ca.key)
lan-ca init
# Generate cert for specific domains
lan-ca generate grafana.lan prometheus.lan
# Or generate a wildcard for all .lan domains
lan-ca wildcard
# Trust the CA on macOS
sudo security add-trusted-cert -d -r trustRoot -p ssl \
-k /Library/Keychains/System.keychain $(lan-ca ca-path)
That’s it. After trusting the CA once, any cert you generate is automatically trusted.
How It Works
The core is straightforward Go crypto:
// Generate ECDSA P-384 key
key, _ := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
// Create certificate template
template := &x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{CommonName: "grafana.lan"},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(0, 0, 365),
DNSNames: []string{"grafana.lan"},
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
}
// Sign with CA
certDER, _ := x509.CreateCertificate(rand.Reader, template, caCert, &key.PublicKey, caKey)
The tool outputs fullchain certs (server cert + CA cert bundled) so nginx/traefik/caddy just work.
My Setup
I run ~30 services on my homelab, all behind Traefik with a wildcard cert:
# traefik config
tls:
certificates:
- certFile: /certs/wildcard.lan.crt
keyFile: /certs/wildcard.lan.key
One cert, all services. grafana.lan, prometheus.lan, home.lan—all green padlock, no warnings.
Trusting on iOS
For accessing services from my phone:
- AirDrop
~/.lan-ca/ca.crtto the device - Install the profile in Settings
- Settings → General → About → Certificate Trust Settings
- Enable trust for “Homelab Root CA”
Now Safari shows the green padlock for all my .lan services.
Why Not mkcert?
mkcert is great, but:
- It’s 2000+ lines vs my 300
- It auto-installs the CA (I wanted explicit control)
- It doesn’t do wildcards easily
- I wanted to understand exactly what’s happening
Sometimes the best tool is the one you wrote yourself.
300 lines of Go. No dependencies. Just crypto/x509 and the standard library.