Wildcard SSL/TLS Certificates - Best Practices and Pitfalls
Wildcard certificates are a powerful tool in every administrator’s arsenal, but as Spider-Man says - “with great power comes great responsibility”. In this article, we’ll show when to use wildcard certificates, how to deploy them securely, and what pitfalls to avoid.
What Is a Wildcard Certificate?
A wildcard certificate is an SSL/TLS certificate that secures a main domain and all its first-level subdomains. It uses an asterisk (*) as a wildcard.
Example
A certificate for *.example.com secures:
- ✅
blog.example.com - ✅
shop.example.com - ✅
api.example.com - ❌
example.com(main domain - must be added separately) - ❌
admin.api.example.com(second-level subdomain)
Multi-Domain Wildcard
You can combine wildcard with SAN (Subject Alternative Names):
Common Name: *.example.com
SAN:
- *.example.com
- example.com
- *.staging.example.com
This secures:
example.comblog.example.comshop.example.comapi.staging.example.com
When to Use Wildcard Certificates?
✅ Good Use Cases
1. Development and Testing Environments
dev-feature1.staging.example.com
dev-feature2.staging.example.com
dev-feature3.staging.example.com
A wildcard certificate for *.staging.example.com covers all branch deployments.
2. SaaS Applications with Customer Subdomains
customer1.app.example.com
customer2.app.example.com
customer3.app.example.com
One certificate for *.app.example.com instead of hundreds of individual ones.
3. Microservices with Dynamic Subdomains
service-auth.internal.example.com
service-api.internal.example.com
service-db.internal.example.com
4. CDN and Load Balancers
cdn1.assets.example.com
cdn2.assets.example.com
cdn3.assets.example.com
❌ Bad Use Cases
1. Single Production Applications
If you only have www.example.com and api.example.com, use a multi-domain (SAN) certificate instead of wildcard.
2. High Security Requirements
For sensitive systems (banking, healthcare), it’s better to isolate certificates.
3. Different Subdomain Owners
If different teams manage different subdomains, sharing a certificate can be problematic.
4. When You Need EV Certificates
Extended Validation certificates are not available as wildcard.
Wildcard Certificate Security
Compromise Risk
Problem: If the private key is compromised, all subdomains are at risk.
Solution:
- Hardware Security Modules (HSM)
# Store keys in HSM
# Never export keys in plaintext
- Limited Access
# Permissions for private key
chmod 600 /etc/ssl/private/wildcard.key
chown root:root /etc/ssl/private/wildcard.key
- Key Rotation
# Renew certificate with new key every 3-6 months
# Don't use the same key/certificate pair for years
Certificate Pinning
For mobile applications using wildcard certificates:
// Android - Certificate Pinning
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add("*.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.add("*.example.com", "sha256/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=") // backup
.build();
OkHttpClient client = new OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build();
// iOS - Certificate Pinning
let evaluator = PinnedCertificatesTrustEvaluator(
certificates: [Certificates.wildcard],
acceptSelfSignedCertificates: false,
performDefaultValidation: true,
validateHost: true
)
let serverTrustManager = ServerTrustManager(evaluators: ["*.example.com": evaluator])
Monitoring and Auditing
# Monitor private key access (auditd)
auditctl -w /etc/ssl/private/wildcard.key -p rwxa -k wildcard_key_access
# Review logs
ausearch -k wildcard_key_access
Obtaining Wildcard Certificates
Let’s Encrypt with DNS-01 Challenge
Why DNS-01? HTTP-01 doesn’t work for wildcard because Let’s Encrypt cannot verify all possible subdomains.
With Cloudflare
# Install certbot with Cloudflare plugin
apt-get install certbot python3-certbot-dns-cloudflare
# Credentials file
cat > /root/.cloudflare.ini <<EOF
dns_cloudflare_api_token = your-cloudflare-api-token
EOF
chmod 600 /root/.cloudflare.ini
# Obtain certificate
certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.cloudflare.ini \
-d example.com \
-d *.example.com \
--email [email protected] \
--agree-tos \
--non-interactive
# Automatic renewal
echo "0 3 * * * certbot renew --quiet" | crontab -
With Route53 (AWS)
# Install plugin
apt-get install certbot python3-certbot-dns-route53
# Credentials via AWS CLI or IAM role
aws configure
# Obtain certificate
certbot certonly \
--dns-route53 \
-d example.com \
-d *.example.com \
--email [email protected] \
--agree-tos \
--non-interactive
With acme.sh (Universal)
# Installation
curl https://get.acme.sh | sh
# Cloudflare
export CF_Token="your-cloudflare-api-token"
acme.sh --issue --dns dns_cf -d example.com -d *.example.com
# Route53
export AWS_ACCESS_KEY_ID="your-access-key"
export AWS_SECRET_ACCESS_KEY="your-secret-key"
acme.sh --issue --dns dns_aws -d example.com -d *.example.com
# Google Cloud DNS
export GCE_PROJECT="your-project"
export GCE_SERVICE_ACCOUNT_FILE="/path/to/key.json"
acme.sh --issue --dns dns_gcloud -d example.com -d *.example.com
Commercial CAs
Most commercial CAs offer wildcard certificates:
- DigiCert: $295-2995/year
- Sectigo: $99-299/year
- GlobalSign: $249-1299/year
- GoDaddy: $300-500/year
Choosing a commercial CA makes sense when:
- You need 24/7 support
- You need insurance (warranty)
- Client requires specific CA
- You can’t use Let’s Encrypt (e.g., no DNS API access)
Web Server Configuration
Nginx
server {
listen 443 ssl http2;
server_name *.example.com example.com;
# Wildcard certificate
ssl_certificate /etc/ssl/certs/wildcard.example.com.crt;
ssl_certificate_key /etc/ssl/private/wildcard.example.com.key;
# Modern SSL configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# HSTS
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/ssl/certs/chain.pem;
# Routing based on subdomain
location / {
if ($host ~ ^([^.]+)\.example\.com$) {
set $subdomain $1;
proxy_pass http://backend-$subdomain;
}
if ($host = example.com) {
proxy_pass http://backend-main;
}
}
}
Apache
<VirtualHost *:443>
ServerName example.com
ServerAlias *.example.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/wildcard.example.com.crt
SSLCertificateKeyFile /etc/ssl/private/wildcard.example.com.key
SSLCertificateChainFile /etc/ssl/certs/chain.pem
# Modern SSL configuration
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder off
# HSTS
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
# OCSP Stapling
SSLUseStapling on
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"
# Routing
RewriteEngine On
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com$ [NC]
RewriteRule ^(.*)$ http://backend-%1$1 [P]
</VirtualHost>
Traefik (Docker/Kubernetes)
# docker-compose.yml
version: '3.8'
services:
traefik:
image: traefik:v2.10
command:
- "--providers.docker=true"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=cloudflare"
- "[email protected]"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
environment:
- [email protected]
- CF_API_KEY=your-cloudflare-api-key
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
ports:
- "443:443"
app:
image: myapp:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`*.example.com`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls.certresolver=letsencrypt"
- "traefik.http.routers.app.tls.domains[0].main=example.com"
- "traefik.http.routers.app.tls.domains[0].sans=*.example.com"
Common Problems and Solutions
Problem 1: Certificate Doesn’t Work for Main Domain
Symptom:
✅ https://blog.example.com - works
✅ https://api.example.com - works
❌ https://example.com - invalid certificate
Solution: Wildcard *.example.com doesn’t include the main domain. You must add both:
certbot certonly --dns-cloudflare \
-d example.com \
-d *.example.com
Problem 2: Second-Level Subdomain
Symptom:
✅ https://api.example.com - works
❌ https://v1.api.example.com - invalid certificate
Solution: Wildcard only works for one level. You need:
# Option 1: Add another wildcard
certbot certonly --dns-cloudflare \
-d *.example.com \
-d *.api.example.com
# Option 2: Multi-level wildcard (rarely supported)
# Some CAs offer multi-level wildcard
Problem 3: DNS Propagation
Symptom: DNS-01 challenge fails with timeout
Solution:
# Increase timeout for DNS propagation
certbot certonly --dns-cloudflare \
--dns-cloudflare-propagation-seconds 60 \
-d example.com \
-d *.example.com
# Check DNS before attempt
dig _acme-challenge.example.com TXT
Problem 4: API Rate Limits
Symptom: Let’s Encrypt returns “too many requests”
Solution:
# Test on staging
certbot certonly --dns-cloudflare \
--staging \
-d example.com \
-d *.example.com
# After tests use production
certbot certonly --dns-cloudflare \
-d example.com \
-d *.example.com
Monitoring Wildcard Certificates
Check Script
#!/bin/bash
# check-wildcard.sh
DOMAIN="*.example.com"
CERT_FILE="/etc/ssl/certs/wildcard.example.com.crt"
# Check expiration date
EXPIRY=$(openssl x509 -in "$CERT_FILE" -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
CURRENT_EPOCH=$(date +%s)
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $CURRENT_EPOCH) / 86400 ))
echo "Certificate for $DOMAIN expires in $DAYS_LEFT days"
if [ $DAYS_LEFT -lt 30 ]; then
echo "WARNING: Certificate expires soon!"
# Send alert
curl -X POST https://your-webhook.com/alert \
-d "Certificate $DOMAIN expires in $DAYS_LEFT days"
fi
# Check if certificate is wildcard
SUBJECT=$(openssl x509 -in "$CERT_FILE" -noout -subject)
if [[ $SUBJECT == *"CN = *.example.com"* ]]; then
echo "✓ Valid wildcard certificate"
else
echo "✗ Not a wildcard certificate!"
fi
# Check if main domain is included
SAN=$(openssl x509 -in "$CERT_FILE" -noout -text | grep -A1 "Subject Alternative Name")
if [[ $SAN == *"DNS:example.com"* ]]; then
echo "✓ Main domain included in SAN"
else
echo "✗ Main domain NOT in certificate"
fi
Prometheus Monitoring
# prometheus-rules.yaml
groups:
- name: wildcard-certificates
rules:
- alert: WildcardCertificateExpiring
expr: (ssl_certificate_expiry_seconds{cn="*.example.com"} - time()) / 86400 < 30
for: 24h
labels:
severity: warning
annotations:
summary: "Wildcard certificate expiring soon"
description: "Certificate for *.example.com expires in {{ $value }} days"
- alert: WildcardCertificateExpired
expr: (ssl_certificate_expiry_seconds{cn="*.example.com"} - time()) < 0
labels:
severity: critical
annotations:
summary: "Wildcard certificate EXPIRED"
description: "Certificate for *.example.com has expired!"
CrtMgr Integration
CrtMgr can monitor wildcard certificates:
- Add domain with wildcard:
*.example.com - CrtMgr automatically detects wildcard
- Monitors expiration date
- Sends alerts 30/14/7/1 days before expiration
- API integration for automation
Best Practices - Summary
✅ DO
- Use DNS-01 Challenge for wildcard certificates
- Add main domain to SAN
- Rotate keys regularly (every 3-6 months)
- Monitor expiration with alerts
- Limit access to private key
- Test on staging before production
- Document where certificate is used
- Backup certificates and keys (encrypted!)
❌ DON’T
- Don’t use wildcard for single domains
- Don’t share keys between environments
- Don’t store keys in plaintext in repo
- Don’t ignore expiring certificate alerts
- Don’t use the same key for years
- Don’t give key access to everyone
- Don’t forget to renew before expiration
- Don’t assume wildcard covers all subdomain levels
Deployment Checklist
Before deploying a wildcard certificate:
- Verify that wildcard is needed (vs multi-domain)
- Choose challenge method (DNS-01 for wildcard)
- Configure DNS API access
- Test on staging environment
- Add main domain to SAN
- Configure automatic renewal
- Set up monitoring and alerts
- Restrict permissions on private key
- Create backup of key (encrypted)
- Document configuration
- Test all subdomains
- Configure HSTS and OCSP stapling
Summary
Wildcard certificates are a powerful tool that can greatly simplify SSL/TLS management for multiple subdomains. Key points:
- Use wisely - not for everything, but where it makes sense
- Security first - wildcard increases compromise risk
- Automate - DNS-01 challenge with automatic renewal
- Monitor - one expired wildcard = all subdomains down
- Document - know where certificate is used
Need a simple tool to monitor wildcard certificates? Check out CrtMgr - automatically detects and monitors wildcard certificates with alerts before expiration.
Wildcard certificates - use wisely, monitor carefully, sleep peacefully.