CrtMgr Blog - SSL/TLS Certificate Management Insights

Expert insights on SSL/TLS certificate management, types, deployment, and best practices

Wildcard SSL/TLS Certificates - Best Practices and Pitfalls

SSL TLS Wildcard Security Certificates DNS

Here’s a scenario that plays out more often than it should: a team deploys a wildcard certificate to cover their 50 microservice subdomains, saves themselves a ton of cert management overhead, and feels pretty clever about it. Then one developer’s laptop gets compromised. Suddenly, that single private key issue becomes a potential exposure across every single subdomain in production.

Wildcard certificates solve real problems — but they introduce real risks too. This guide is about knowing when to reach for a wildcard and when to step back and think twice. We’ll cover the good use cases, the security considerations, and the DNS-01 challenge mechanics that make automated wildcard issuance possible.

If you’re managing many certificates and wondering which tool to use for tracking them all, our guide to choosing the right certificate manager covers what features matter most at different scales.

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.com
  • blog.example.com
  • shop.example.com
  • api.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:

  1. Hardware Security Modules (HSM)
# Store keys in HSM
# Never export keys in plaintext
  1. Limited Access
# Permissions for private key
chmod 600 /etc/ssl/private/wildcard.key
chown root:root /etc/ssl/private/wildcard.key
  1. 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. If you’re running Kubernetes, cert-manager handles the entire DNS-01 flow automatically — including Cloudflare and Route53 integrations — which means you get wildcard renewal without touching a cron job.

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 admin@example.com \
  --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 admin@example.com \
  --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"
      - "--certificatesresolvers.letsencrypt.acme.email=admin@example.com"
      - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
    environment:
      - CF_API_EMAIL=admin@example.com
      - 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:

  1. Add domain with wildcard: *.example.com
  2. CrtMgr automatically detects wildcard
  3. Monitors expiration date
  4. Sends alerts 30/14/7/1 days before expiration
  5. API integration for automation

Best Practices

Use DNS-01 Challenge for wildcard certificates, add the main domain to SAN, rotate keys regularly (every 3-6 months), monitor expiration with alerts, limit access to private keys, test on staging before production, document where certificates are used, and backup certificates and keys in encrypted form.

Don’t use wildcards for single domains, share keys between environments, store keys in plaintext in repositories, ignore expiring certificate alerts, use the same key for years, give key access to everyone, forget to renew before expiration, or assume wildcards cover all subdomain levels.

Before deploying a wildcard certificate, verify that wildcard is truly needed (versus multi-domain), choose DNS-01 challenge method, 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 keys, create encrypted key backups, document configuration, test all subdomains, and configure HSTS and OCSP stapling.

Wildcard certificates are powerful tools for exactly the right situations — dev environments with dynamic subdomains, SaaS platforms with per-customer subdomains, CDN edge nodes. Used correctly, they dramatically simplify certificate management. Used carelessly, a single compromised key becomes everyone’s problem.

The rule of thumb: use wildcards where you genuinely have many unpredictable subdomains, use SAN certificates where you have a known, fixed list. Whatever you choose, automate the DNS-01 renewal and monitor the expiration — one expired wildcard is all your subdomains going dark simultaneously.

Need a simple tool to monitor wildcard certificates? Check out CrtMgr — it automatically detects wildcards and sends alerts well before expiration. One place to see everything, regardless of how many subdomains are covered.


Wildcard certificates — use wisely, monitor carefully, sleep peacefully.

Related Articles