Let's Encrypt SSL: Free Certificate Setup Guide
In this tutorial, you'll learn about Let's Encrypt SSL: Free Certificate Setup Guide. We cover key concepts, practical examples, and best practices.
Let's Encrypt is a free, automated, and open Certificate Authority that provides SSL/TLS certificates trusted by all major browsers. Its Certbot client automates the entire process of obtaining, installing, and renewing certificates with zero cost.
In this tutorial, you will learn to install and run Certbot, obtain certificates for single and multiple domains, configure auto-renewal, set up wildcard certificates with DNS challenges, integrate certificates with NGINX and Apache, and troubleshoot common renewal failures. DodaTech uses Let's Encrypt to secure Doda Browser update servers, DodaZIP download portals, and Durga Antivirus Pro API endpoints.
What You'll Learn
By the end of this guide, you will obtain and configure free SSL certificates for any domain, automate certificate renewal, set up wildcard certificates covering all subdomains, and verify your HTTPS configuration is correct and secure.
Why Let's Encrypt Matters
HTTPS is no longer optional. Browsers mark HTTP sites as "Not Secure," search engines rank HTTPS sites higher, and many browser APIs require a secure context. Let's Encrypt made HTTPS free and accessible to everyone, encrypting over 300 million websites. Every Web Servers administrator and DevOps engineer should know how to use Let's Encrypt. See also SSL/TLS certificate guide for deeper protocol knowledge.
Let's Encrypt Learning Path
flowchart LR
A[Certbot Installation] --> B[Obtain Certificate]
B --> C[Web Server Integration]
C --> D[Auto-Renewal]
D --> E[Wildcard Certificates]
E --> F{You Are Here}
style F fill:#f90,color:#fff
Installing Certbot
# Ubuntu / Debian
sudo apt update && sudo apt install certbot python3-certbot-nginx python3-certbot-apache -y
# RHEL / CentOS / Fedora
sudo dnf install certbot python3-certbot-nginx -y
# Verify installation
certbot --version
Expected output
certbot 2.11.0
Obtaining a Certificate (HTTP Challenge)
Certbot validates domain ownership by serving a token file on port 80:
# For NGINX (automatically modifies config)
sudo certbot --nginx -d example.com -d www.example.com
# For Apache (automatically modifies config)
sudo certbot --apache -d example.com -d www.example.com
# Certificate only (manual web server configuration)
sudo certbot certonly --webroot -w /var/www/example.com -d example.com -d www.example.com
Expected output
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for example.com and www.example.com
Performing the following challenges: http-01 for example.com, http-01 for www.example.com
Waiting for verification...
Cleaning up challenges
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/example.com/privkey.pem
Configuring Auto-Renewal
Let's Encrypt certificates expire after 90 days. Certbot installs a systemd timer automatically:
# Test renewal (dry run - does not actually renew)
sudo certbot renew --dry-run
# Check the renewal timer
sudo systemctl status certbot.timer
# Check the renewal service
sudo systemctl status certbot.service
# Manual renewal (if needed)
sudo certbot renew
Expected renewal test output
Certbot failed to authenticate some domains (timed out)
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- Congratulations! All certificate renewals passed: example.com
- Congratulations! All certificate renewals passed: www.example.com
For custom renewal hooks (e.g., reloading services):
# Create renewal hook directory
sudo mkdir -p /etc/letsencrypt/renewal-hooks/post
# Add a hook to reload NGINX after renewal
cat << 'EOF' | sudo tee /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh
#!/bin/bash
systemctl reload nginx
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh
Wildcard Certificates
Wildcard certificates cover all subdomains with one certificate:
# DNS challenge is required for wildcard certificates
sudo certbot certonly --manual --preferred-challenges dns \
-d *.example.com -d example.com
Certbot prompts you to add a DNS TXT record:
Please deploy a DNS TXT record under the name:
_acme-challenge.example.com
with the following value:
abcdef1234567890
Add the record and verify:
# Add this DNS record at your DNS provider (type: TXT)
# Name: _acme-challenge
# Value: abcdef1234567890
# TTL: 300
# Wait for propagation (usually 30-300 seconds)
# Verify with dig
dig _acme-challenge.example.com TXT +short
Expected output
"abcdef1234567890"
Automated DNS challenge with a provider API
Using a DNS automation plugin (example with Cloudflare):
# Install Cloudflare DNS plugin
sudo apt install python3-certbot-dns-cloudflare -y
# Create Cloudflare API credentials file
mkdir -p ~/.secrets/certbot
cat << 'EOF' > ~/.secrets/certbot/cloudflare.ini
dns_cloudflare_api_token = your-cloudflare-api-token
EOF
chmod 600 ~/.secrets/certbot/cloudflare.ini
# Obtain wildcard certificate
sudo certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \
-d *.example.com -d example.com
NGINX Integration
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
# HSTS
add_header Strict-Transport-Security "max-age=63072000" always;
root /var/www/example.com;
index index.html;
}
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
Verification and Testing
# Check certificate details
sudo certbot certificates
# Verify certificate with openssl
openssl s_client -connect example.com:443 -servername example.com \
< /dev/null 2>/dev/null | openssl x509 -text -noout | grep -E "Subject:|Not "
# Test HTTPS with curl
curl -I https://example.com
# Check SSL Labs rating (command-line)
# Quick check for certificate expiry
sudo openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem \
-noout -enddate
Expected output
Subject: CN = example.com
Not Before: Jun 23 00:00:00 2026 GMT
Not After : Sep 21 00:00:00 2026 GMT
Common Errors
1. Port 80 Blocked
Certbot validates domains via port 80. Open the firewall: sudo ufw allow 80/tcp. Check with sudo ss -tlnp | grep :80.
2. DNS Not Propagated (Wildcard)
DNS challenge requires the TXT record to be propagated. Wait and verify with dig or nslookup. Use a DNS propagation checker tool.
3. Too Many Certificate Requests
Let's Encrypt rate limits: 50 certificates per registered domain per week. Use one certificate with multiple domains (-d domain1.com -d domain2.com) instead of separate certificates.
4. Renewal Fails Due to Expired Token
Certbot stores renewal configuration. If the webroot path changed, renewal fails. Run sudo certbot renew --dry-run and fix the configuration in /etc/letsencrypt/renewal/.
5. Permission Denied on Private Key
Certbot certificates are readable only by root. Ensure your web server user can access them: sudo chmod 755 /etc/letsencrypt/{live,archive}.
6. Certificate Name Mismatch
The certificate does not cover the domain used. Verify with openssl x509 -in /path/to/cert.pem -text -noout | grep DNS.
Practice Questions
1. How long do Let's Encrypt certificates remain valid? 90 days. This short lifespan encourages automation. Certbot's systemd timer renews certificates that expire within 30 days.
2. What is the difference between the HTTP and DNS challenge methods? The HTTP challenge serves a token file on port 80 to prove domain control. The DNS challenge requires a TXT record. DNS is required for wildcard certificates and works when port 80 is unavailable.
3. How do you verify that auto-renewal is configured correctly?
Run sudo certbot renew --dry-run to simulate renewal. Check sudo systemctl status certbot.timer to ensure the timer is active. Verify logs in /var/log/letsencrypt/.
4. Challenge: Fully automated multi-domain SSL deployment
Write a script that:
- Obtains a wildcard certificate for
*.dodatech.comusing the DNS challenge with Cloudflare - Configures NGINX with the certificate, modern TLS settings, and HSTS
- Sets up auto-renewal with a post-renewal hook that reloads NGINX
- Verifies the certificate with openssl and curl
Mini Project: End-to-End SSL Automation
Build a complete SSL automation pipeline:
- Install Certbot with the Cloudflare DNS plugin
- Obtain a wildcard certificate for
*.dodatech.com - Configure NGINX to use the certificate with modern TLS and HSTS
- Set up auto-renewal with a post-renewal hook
- Create a monitoring script that checks certificate expiry daily
- Test the setup by visiting the site and checking the SSL Labs rating
# Monitoring script (run daily via cron)
#!/bin/bash
DOMAIN="dodatech.com"
CERT_FILE="/etc/letsencrypt/live/$DOMAIN/fullchain.pem"
WARN_DAYS=14
EXPIRY=$(openssl x509 -in "$CERT_FILE" -noout -enddate | cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
if [ $DAYS_LEFT -lt $WARN_DAYS ]; then
echo "WARNING: Certificate for $DOMAIN expires in $DAYS_LEFT days"
# Send alert (email, Slack, etc.)
else
echo "OK: Certificate for $DOMAIN expires in $DAYS_LEFT days"
fi
This automation is used by DodaTech to ensure Doda Browser, DodaZIP, and Durga Antivirus Pro services never experience certificate-related downtime.
FAQ
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro