Wildcard SSL Certificates with Let's Encrypt
Wildcard SSL certificates secure multiple subdomains with a single certificate. Let's Encrypt provides free wildcard certificates through its ACME (Automated Certificate Management Environment) protocol. This guide covers obtaining wildcard certificates, DNS-based validation, automation with Certbot and Cloudflare, and renewal strategies.
Table of Contents
- Prerequisites
- Understanding Wildcard Certificates
- Installing Certbot
- DNS Challenge Overview
- Cloudflare DNS Integration
- Route53 Integration
- Wildcard Certificate Renewal
- Nginx Configuration
- Apache Configuration
- Troubleshooting
- Conclusion
Prerequisites
Before obtaining wildcard certificates, ensure you have:
- Domain name with DNS control
- Certbot installed on your server
- Root or sudo access
- Understanding of DNS records
- Web server (Nginx, Apache) configured
- Access to DNS provider API (Cloudflare, Route53)
Understanding Wildcard Certificates
A wildcard certificate for *.example.com secures:
api.example.commail.example.comcdn.example.comshop.example.com- And all other subdomains
However, it does NOT secure example.com (base domain). For both, request a certificate for both *.example.com and example.com.
Wildcard certificates require DNS validation (CNAME/TXT record challenges) since multiple hosts can't all verify the same HTTP challenge.
Installing Certbot
Install Certbot on Ubuntu/Debian:
sudo apt-get update
sudo apt-get install -y certbot python3-certbot-nginx python3-certbot-apache
Install DNS plugin for your provider. For Cloudflare:
sudo apt-get install -y python3-certbot-dns-cloudflare
For Route53:
sudo apt-get install -y python3-certbot-dns-route53
For other providers, install the appropriate plugin:
# Generic installation
pip3 install certbot-dns-plugin-name
Verify Certbot installation:
certbot --version
certbot plugins
DNS Challenge Overview
Let's Encrypt validates wildcard domain ownership by requesting DNS TXT record modifications. The process:
- Certbot creates a unique authorization token
- Certbot creates a TXT record:
_acme-challenge.example.com - Let's Encrypt validates the TXT record exists
- Certificate is issued
- TXT record can be removed
For automated DNS updates, use DNS provider plugins.
Cloudflare DNS Integration
Integrate Certbot with Cloudflare for automated DNS validation. Create Cloudflare API credentials first.
Log in to Cloudflare dashboard and create an API token:
- Go to Account Settings > API Tokens
- Create Token > Edit zone DNS
- Grant permissions for specific zone
- Copy the token
Store credentials in ~/.cloudflare/cloudflare.ini:
mkdir -p ~/.cloudflare
nano ~/.cloudflare/cloudflare.ini
Add credentials:
dns_cloudflare_api_token = your_api_token_here
Set proper permissions:
chmod 600 ~/.cloudflare/cloudflare.ini
Request wildcard certificate with Cloudflare validation:
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials ~/.cloudflare/cloudflare.ini \
-d "*.example.com" \
-d "example.com" \
--agree-tos \
--email [email protected]
Certbot will:
- Contact Let's Encrypt for challenge
- Create TXT record in Cloudflare DNS
- Validate the record
- Remove the TXT record
- Issue certificate
For production, use non-interactive mode:
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials ~/.cloudflare/cloudflare.ini \
-d "*.example.com" \
-d "example.com" \
--agree-tos \
--email [email protected] \
--non-interactive
Verify certificate installation:
ls -la /etc/letsencrypt/live/example.com/
Output should show:
cert.pem -> ../../../archive/example.com/cert1.pem
chain.pem -> ../../../archive/example.com/chain1.pem
fullchain.pem -> ../../../archive/example.com/fullchain1.pem
privkey.pem -> ../../../archive/example.com/privkey1.pem
Route53 Integration
For AWS Route53 DNS, create an IAM user with DNS permissions.
Create IAM policy for Route53:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"route53:GetChange",
"route53:ChangeResourceRecordSets",
"route53:ListResourceRecordSets"
],
"Resource": [
"arn:aws:route53:::hostedzone/*",
"arn:aws:route53:::change/*"
]
},
{
"Effect": "Allow",
"Action": "route53:ListHostedZonesByName",
"Resource": "*"
}
]
}
Install certbot-dns-route53:
sudo apt-get install -y python3-certbot-dns-route53
Create AWS credentials file ~/.aws/credentials:
mkdir -p ~/.aws
nano ~/.aws/credentials
Add credentials:
[default]
aws_access_key_id = your_access_key
aws_secret_access_key = your_secret_key
Set permissions:
chmod 600 ~/.aws/credentials
Request certificate with Route53:
sudo certbot certonly \
--dns-route53 \
-d "*.example.com" \
-d "example.com" \
--agree-tos \
--email [email protected]
Certbot automatically handles DNS record creation and removal through Route53.
Wildcard Certificate Renewal
Certbot automatically renews certificates before expiration through a systemd timer.
Check renewal status:
sudo certbot renew --dry-run
For automated renewal with Cloudflare, ensure credentials are available to root:
sudo cp ~/.cloudflare/cloudflare.ini /root/.cloudflare/
sudo chmod 600 /root/.cloudflare/cloudflare.ini
Create a renewal hook to restart web servers after renewal. Create /etc/letsencrypt/renewal-hooks/post/restart-webserver.sh:
#!/bin/bash
sudo systemctl restart nginx
sudo systemctl restart apache2
Make executable:
sudo chmod +x /etc/letsencrypt/renewal-hooks/post/restart-webserver.sh
Check systemd timer:
sudo systemctl list-timers | grep certbot
Manual renewal:
sudo certbot renew --force-renewal
Renew with Cloudflare credentials:
sudo certbot renew \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.cloudflare/cloudflare.ini
Nginx Configuration
Configure Nginx to use wildcard certificates.
Create Nginx server block at /etc/nginx/sites-available/example.com:
sudo nano /etc/nginx/sites-available/example.com
Add configuration:
server {
listen 80;
listen [::]:80;
server_name example.com *.example.com;
# Redirect HTTP to HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com *.example.com;
# SSL certificate paths
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# SSL protocols and ciphers
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# HSTS header
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Server configuration
root /var/www/example.com;
index index.html index.htm;
location / {
try_files $uri $uri/ =404;
}
}
Enable the site:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
Test Nginx configuration:
sudo nginx -t
Restart Nginx:
sudo systemctl restart nginx
Apache Configuration
Configure Apache to use wildcard certificates.
Enable SSL module:
sudo a2enmod ssl
sudo a2enmod headers
sudo a2enmod rewrite
Create Apache VirtualHost at /etc/apache2/sites-available/example.com.conf:
sudo nano /etc/apache2/sites-available/example.com.conf
Add configuration:
<VirtualHost *:80>
ServerName example.com
ServerAlias *.example.com
# Redirect HTTP to HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</VirtualHost>
<VirtualHost *:443>
ServerName example.com
ServerAlias *.example.com
# SSL certificates
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
# SSL configuration
SSLProtocol TLSv1.2 TLSv1.3
SSLCipherSuite HIGH:!aNULL:!MD5
SSLHonorCipherOrder on
# HSTS header
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
# Document root
DocumentRoot /var/www/example.com
<Directory /var/www/example.com>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
Enable the site:
sudo a2ensite example.com.conf
Test Apache configuration:
sudo apache2ctl configtest
Restart Apache:
sudo systemctl restart apache2
Troubleshooting
Check certificate validity:
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -text -noout
Verify certificate covers the domain:
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -text | grep -A5 "Subject Alternative Name"
Test SSL configuration:
# Using SSL Labs
curl https://www.ssllabs.com/api/v3/analyze?host=example.com
# Using OpenSSL
openssl s_client -connect example.com:443 -showcerts
# Using testssl.sh
bash testssl.sh --severity HIGH https://example.com
Debug Certbot issues:
# Enable verbose logging
sudo certbot certonly -v --dns-cloudflare ...
# Check logs
sudo tail -f /var/log/letsencrypt/letsencrypt.log
Verify DNS challenge:
# Check TXT record (during renewal)
dig _acme-challenge.example.com TXT
Conclusion
Wildcard SSL certificates from Let's Encrypt provide a cost-effective way to secure multiple subdomains with a single certificate. This guide covered obtaining wildcard certificates using DNS-based validation with Cloudflare and Route53, automating renewal, and configuring Nginx and Apache. For production deployments, automate renewal through systemd timers, monitor certificate expiration, test SSL configurations regularly with tools like SSL Labs, and establish backup renewal procedures. Wildcard certificates excel for multi-subdomain applications, microservices architectures, and dynamic hosting environments.


