When working with wildcard subdomains under *.localhost
, Chrome's strict SSL validation can be particularly problematic. Modern browsers have deprecated support for Subject Common Name (CN) matching in favor of Subject Alternative Name (SAN) extensions.
The error net::ERR_CERT_COMMON_NAME_INVALID
occurs because:
- Chrome no longer trusts CN-based wildcards for localhost
- The certificate lacks proper SAN extensions
- Modern browsers require explicit domain specification
Generate a new certificate with SAN support using this OpenSSL config file (localhost.cnf
):
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
x509_extensions = v3_req
[dn]
C = AU
ST = Western Australia
L = Perth
O = Zephon
CN = *.localhost
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = *.localhost
Then generate the certificate:
openssl req -x509 -newkey rsa:2048 \
-keyout localhost.key -out localhost.crt \
-days 3650 -nodes -config localhost.cnf
Modify your Nginx config to explicitly handle wildcard subdomains:
server {
listen 80;
listen 443 ssl;
server_name ~^(?.+).localhost$ localhost;
ssl_certificate /etc/nginx/ssl/localhost.crt;
ssl_certificate_key /etc/nginx/ssl/localhost.key;
# SSL optimizations
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
After generating the new certificate:
- Import the CRT file into Chrome's certificate store
- Restart Chrome completely (chrome://restart)
- Verify the certificate appears in chrome://settings/certificates
- For testing, you might need to:
# Temporarily disable Chrome's security
google-chrome --ignore-certificate-errors --ignore-urlfetcher-cert-requests
For production-like local development, consider:
1. Using .test
instead of .localhost
(IANA reserved TLD)
2. Setting up a local CA with mkcert:
brew install mkcert # For macOS
mkcert -install
mkcert "*.example.test" "example.test" "localhost" "127.0.0.1"
3. Using a DNS service like nip.io or sslip.io
When setting up wildcard subdomains *.localhost
with Nginx reverse proxy, Chrome throws ERR_CERT_COMMON_NAME_INVALID
even after importing the self-signed certificate. This occurs because modern browsers (Chrome 58+) enforce stricter SSL certificate validation through CA/Browser Forum's deprecation of Common Name matching.
Your current OpenSSL command doesn't include Subject Alternative Names (SANs), which are now mandatory. Here's the corrected version:
openssl req -x509 -sha256 -newkey rsa:2048 \
-keyout localhost.key -out localhost.crt \
-days 3650 -nodes -subj "/CN=*.localhost" \
-extensions san -config <(echo \
"[req]"; \
"distinguished_name=req"; \
"[san]"; \
"subjectAltName=DNS:localhost,DNS:*.localhost")
Your current Nginx configuration needs three critical adjustments:
server {
listen 80;
listen 443 ssl;
server_name localhost *.localhost; # Added wildcard here
ssl_certificate /etc/nginx/ssl/localhost.crt;
ssl_certificate_key /etc/nginx/ssl/localhost.key;
# Modern SSL configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
# ... rest of your proxy settings
}
}
For local development, you can either:
- Create a proper CA-signed certificate using
mkcert
:mkcert "*.localhost" localhost 127.0.0.1 ::1
- Or enable Chrome flags temporarily:
chrome://flags/#allow-insecure-localhost
Ensure your DNSmasq config includes:
address=/localhost/127.0.0.1
address=/.localhost/127.0.0.1
Verify resolution works with:
dig anytest.localhost @127.0.0.1
After implementing all changes:
curl -vIk https://test.localhost
openssl s_client -connect test.localhost:443 -servername test.localhost | openssl x509 -noout -text