Skip to content

Let's Encrypt SSL: Free Certificate Setup Guide

DodaTech Updated 2026-06-23 7 min read

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.com using 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:

  1. Install Certbot with the Cloudflare DNS plugin
  2. Obtain a wildcard certificate for *.dodatech.com
  3. Configure NGINX to use the certificate with modern TLS and HSTS
  4. Set up auto-renewal with a post-renewal hook
  5. Create a monitoring script that checks certificate expiry daily
  6. 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

Is Let's Encrypt safe to use in production?

Yes. Let's Encrypt is a trusted Certificate Authority whose certificates are included in all major browser trust stores. It is used by millions of production websites.

Can I use Let's Encrypt for internal (non-public) domains?

Let's Encrypt only validates public domain names that you control via DNS or HTTP. For internal domains, use a private CA or self-signed certificates.

What happens if I miss the renewal window?

The certificate expires and browsers show security warnings. Users will see "Your connection is not private" errors. Renew the certificate immediately and check why auto-renewal failed.

Does Let's Encrypt support ECDSA certificates?

Yes. Certbot can request ECDSA certificates with --key-type ecdsa --elliptic-curve secp384r1. ECDSA keys are smaller and faster than RSA for TLS handshakes.

How do I revoke a compromised certificate?

Run sudo certbot revoke --cert-path /etc/letsencrypt/live/example.com/cert.pem followed by sudo certbot delete --cert-name example.com to clean up.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro