SSL/TLS CERTIFICATE AUTOMATION WITH CERTBOT Your Server Certbot Nginx / Apache ACME Client auto-renew cron 1. Request Let's Encrypt ACME Protocol Domain Validation HTTP-01 / DNS-01 Challenge 2. Challenge 3. Issue Cert Certificate fullchain.pem privkey.pem Visitors HTTPS Secure Certificates auto-renew every 60-90 days via systemd timer or cron Free, automated SSL/TLS certificates for every domain

Every website serving traffic over the internet should use HTTPS. Beyond encrypting data in transit between your visitors and your server, HTTPS is a ranking factor for search engines, a requirement for modern web APIs like HTTP/2 and service workers, and a trust signal that browsers display prominently. Let’s Encrypt has removed the cost barrier entirely by providing free, automated SSL/TLS certificates, and Certbot is the most widely used tool to obtain and manage them.

This guide covers everything you need to know to set up Certbot with Nginx or Apache, automate certificate renewal, obtain wildcard certificates, and harden your HTTPS configuration with security headers.

Prerequisites

Before you begin, make sure you have:

  • An Ubuntu server (22.04 or 24.04) with a public IP address
  • A registered domain name with DNS A records pointing to your server
  • Nginx or Apache installed and serving your website
  • Terminal access with sudo privileges
  • Port 80 (HTTP) and port 443 (HTTPS) open in your firewall

Why HTTPS Matters

Here is why every system administrator should prioritize HTTPS:

  • Encryption: HTTPS encrypts all traffic between the client and server, protecting login credentials, personal data, and session cookies from eavesdropping
  • Authentication: SSL/TLS certificates verify that visitors are communicating with your actual server, not an impersonator
  • Data integrity: HTTPS prevents man-in-the-middle attackers from modifying data in transit
  • SEO ranking: Google uses HTTPS as a ranking signal. Sites without HTTPS are at a disadvantage in search results
  • Browser trust: Modern browsers display “Not Secure” warnings on HTTP pages, especially those with forms
  • Compliance: Many regulations (GDPR, PCI DSS, HIPAA) require encryption of data in transit

What Is Let’s Encrypt?

Let’s Encrypt is a free, automated, and open Certificate Authority (CA) operated by the Internet Security Research Group (ISRG). It issues Domain Validation (DV) certificates that are trusted by all major browsers and operating systems.

Key characteristics:

  • Free: No cost for certificates
  • Automated: Certificates can be obtained and renewed without manual intervention
  • Short-lived: Certificates are valid for 90 days, encouraging automated renewal and reducing the impact of key compromise
  • Rate limited: There are limits on how many certificates you can request per domain per week (50 certificates per registered domain per week)

Installing Certbot

Certbot is the official Let’s Encrypt client. The recommended installation method is via snap, which ensures you always have the latest version:

# Remove any OS-packaged certbot to avoid conflicts
sudo apt-get remove certbot

# Install Certbot via snap
sudo snap install --classic certbot

# Create a symbolic link so certbot is available in your PATH
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Verify the installation:

certbot --version

Obtaining Certificates for Nginx

Certbot can automatically obtain the certificate and modify your Nginx configuration to enable HTTPS. This is the simplest approach:

sudo certbot --nginx -d knowledgexchange.xyz -d www.knowledgexchange.xyz

Certbot will:

  1. Verify you control the domain by placing a challenge file on your server
  2. Obtain the certificate from Let’s Encrypt
  3. Modify your Nginx server block to enable SSL/TLS
  4. Set up an HTTP-to-HTTPS redirect

You will be prompted to enter your email address (for renewal notifications) and agree to the terms of service.

After completion, your Nginx configuration will be updated automatically. You can verify the changes:

sudo nginx -t
sudo systemctl reload nginx

Tip: Always run nginx -t to test configuration syntax before reloading. A syntax error can take your site offline.

What Certbot Adds to Your Nginx Configuration

Certbot adds lines similar to these to your server block:

server {
    listen 443 ssl;
    server_name knowledgexchange.xyz www.knowledgexchange.xyz;

    ssl_certificate /etc/letsencrypt/live/knowledgexchange.xyz/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/knowledgexchange.xyz/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    # ... your existing configuration
}

server {
    listen 80;
    server_name knowledgexchange.xyz www.knowledgexchange.xyz;
    return 301 https://$host$request_uri;
}

For more details on Nginx configuration, see our articles on installing Nginx and improving SSL performance in Nginx.

Certonly Mode (Manual Configuration)

If you prefer to configure Nginx yourself, use the certonly subcommand to obtain the certificate without modifying any configuration:

sudo certbot certonly --nginx -d knowledgexchange.xyz -d www.knowledgexchange.xyz

The certificates will be saved to /etc/letsencrypt/live/knowledgexchange.xyz/ and you can reference them in your Nginx configuration manually.

Obtaining Certificates for Apache

The process for Apache is nearly identical. Install the Certbot Apache plugin if it is not already available:

sudo apt install -y python3-certbot-apache

Then run Certbot with the --apache flag:

sudo certbot --apache -d knowledgexchange.xyz -d www.knowledgexchange.xyz

Certbot will:

  1. Verify domain ownership
  2. Obtain the certificate
  3. Update your Apache virtual host configuration
  4. Enable the SSL module and create a redirect

Verify and reload Apache:

sudo apachectl configtest
sudo systemctl reload apache2

For certonly mode with Apache:

sudo certbot certonly --apache -d knowledgexchange.xyz -d www.knowledgexchange.xyz

Standalone Mode

If you are not running Nginx or Apache, or if you want to obtain certificates independently of any web server, use standalone mode. Certbot will temporarily start its own web server on port 80:

sudo certbot certonly --standalone -d knowledgexchange.xyz -d www.knowledgexchange.xyz

Important: Port 80 must be available. If Nginx or Apache is running, stop it first:

sudo systemctl stop nginx  # or apache2
sudo certbot certonly --standalone -d knowledgexchange.xyz
sudo systemctl start nginx  # or apache2

Standalone mode is particularly useful for non-web services that need TLS certificates, such as mail servers or VPN endpoints.

Setting Up Auto-Renewal

Let’s Encrypt certificates expire after 90 days, so automated renewal is essential. The good news is that Certbot installs a systemd timer (or cron job) automatically that runs twice per day and renews any certificates that are within 30 days of expiration.

Verify the timer is active:

sudo systemctl status certbot.timer

You should see active (waiting) in the output. You can also list the scheduled timers:

sudo systemctl list-timers | grep certbot

Testing Auto-Renewal

Always test that renewal will work correctly before relying on it:

sudo certbot renew --dry-run

This simulates the renewal process without actually obtaining new certificates. If the dry run succeeds, your auto-renewal is properly configured.

Post-Renewal Hooks

After a certificate is renewed, your web server needs to reload the new certificate. Certbot handles this automatically for Nginx and Apache plugins, but if you used certonly mode, you need to add a renewal hook:

sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh << 'EOF'
#!/bin/bash
systemctl reload nginx
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

For Apache:

sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-apache.sh << 'EOF'
#!/bin/bash
systemctl reload apache2
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-apache.sh

Wildcard Certificates with DNS Challenge

Wildcard certificates cover all subdomains of a domain (e.g., *.knowledgexchange.xyz). They can only be obtained using the DNS-01 challenge, which requires you to create a specific DNS TXT record.

Manual DNS Challenge

sudo certbot certonly --manual --preferred-challenges dns \
  -d knowledgexchange.xyz -d "*.knowledgexchange.xyz"

Certbot will display a TXT record you need to add to your DNS configuration:

Please deploy a DNS TXT record under the name:
_acme-challenge.knowledgexchange.xyz

with the following value:
dGhpcyBpcyBhIHRlc3Qgc3RyaW5n

Before continuing, verify the record is deployed.

Add the TXT record through your DNS provider’s control panel, wait for propagation (usually 1-5 minutes), then press Enter to continue.

Note: Manual DNS challenges cannot be renewed automatically. For automated wildcard renewal, use a DNS plugin.

Automated DNS Challenge with Plugins

Certbot has plugins for many DNS providers that automate the TXT record creation. For example, with Cloudflare:

# Install the Cloudflare DNS plugin
sudo snap set certbot trust-plugin-with-root=ok
sudo snap install certbot-dns-cloudflare

Create a credentials file:

sudo mkdir -p /etc/letsencrypt/cloudflare
sudo tee /etc/letsencrypt/cloudflare/credentials.ini << 'EOF'
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
EOF
sudo chmod 600 /etc/letsencrypt/cloudflare/credentials.ini

Obtain the wildcard certificate:

sudo certbot certonly --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini \
  -d knowledgexchange.xyz -d "*.knowledgexchange.xyz"

This method supports fully automated renewal since Certbot can create and clean up the DNS records programmatically.

Certificate Monitoring

It is important to monitor your certificates to catch renewal failures before they cause outages.

Check Certificate Expiration

# Check all managed certificates
sudo certbot certificates

# Check a specific domain's certificate from the outside
echo | openssl s_client -servername knowledgexchange.xyz -connect knowledgexchange.xyz:443 2>/dev/null | openssl x509 -noout -dates

Set Up Expiration Alerts

Create a simple monitoring script:

sudo tee /usr/local/bin/check-certs.sh << 'SCRIPT'
#!/bin/bash
THRESHOLD_DAYS=14
ALERT_EMAIL="[email protected]"

for cert_dir in /etc/letsencrypt/live/*/; do
    domain=$(basename "$cert_dir")
    expiry_date=$(openssl x509 -enddate -noout -in "${cert_dir}fullchain.pem" | cut -d= -f2)
    expiry_epoch=$(date -d "$expiry_date" +%s)
    current_epoch=$(date +%s)
    days_remaining=$(( (expiry_epoch - current_epoch) / 86400 ))

    if [ "$days_remaining" -lt "$THRESHOLD_DAYS" ]; then
        echo "WARNING: Certificate for $domain expires in $days_remaining days" | \
            mail -s "SSL Certificate Expiration Warning: $domain" "$ALERT_EMAIL"
    fi
done
SCRIPT
sudo chmod +x /usr/local/bin/check-certs.sh

Add it to cron to run daily:

echo "0 8 * * * root /usr/local/bin/check-certs.sh" | sudo tee /etc/cron.d/check-ssl-certs

Adding Security Headers

Having HTTPS is only part of the equation. You should also configure security headers to maximize protection. Add these to your Nginx server block:

# HTTP Strict Transport Security - tells browsers to always use HTTPS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# Prevent MIME type sniffing
add_header X-Content-Type-Options "nosniff" always;

# Prevent clickjacking
add_header X-Frame-Options "SAMEORIGIN" always;

# Enable XSS filter in older browsers
add_header X-XSS-Protection "1; mode=block" always;

# Control referrer information
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# Content Security Policy (customize for your site)
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" always;

# Permissions Policy
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

For Apache, add equivalent headers in your virtual host or .htaccess:

Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"

Important: Before enabling HSTS with preload, make sure your entire domain works over HTTPS. Once preloaded, browsers will refuse to connect over HTTP, and removing your domain from the preload list takes months.

Troubleshooting Common Issues

Port 80 Is Blocked

Certbot’s HTTP-01 challenge requires port 80 to be accessible from the internet. If it is blocked:

# Check if port 80 is open in UFW
sudo ufw status | grep 80

# Allow port 80 if blocked
sudo ufw allow 80/tcp

# Check if something else is using port 80
sudo ss -tlnp | grep :80

If your hosting provider or ISP blocks port 80, use the DNS challenge method instead.

DNS Not Propagated

If Certbot fails with a DNS-related error, your domain’s A record may not be pointing to the server yet:

# Check DNS resolution
dig +short knowledgexchange.xyz
nslookup knowledgexchange.xyz

# The returned IP should match your server's public IP
curl -s https://ifconfig.me

DNS changes can take up to 48 hours to propagate globally, though most propagation happens within minutes. Wait and try again.

Rate Limit Exceeded

If you have exceeded Let’s Encrypt rate limits, you will receive an error. There is no way to reset the limit. You must wait until the limit window resets (typically one week). To avoid hitting rate limits:

  • Use --dry-run for testing
  • Use the staging environment for development: --staging
  • Consolidate multiple subdomains into a single certificate using -d flags or a wildcard

Certificate Renewal Fails Silently

If auto-renewal is not working, check the Certbot logs:

sudo cat /var/log/letsencrypt/letsencrypt.log

Common causes:

  • Port 80 is no longer accessible (firewall or web server configuration changed)
  • DNS records were modified
  • Certbot snap is outdated: sudo snap refresh certbot

Testing Your SSL Configuration

After setting up HTTPS, test your configuration using external tools:

# Quick test from the command line
curl -vI https://knowledgexchange.xyz 2>&1 | grep -E "(SSL|subject|expire|issuer)"

For a comprehensive analysis, visit SSL Labs Server Test and enter your domain. Aim for an A+ rating by enabling HSTS and using strong cipher suites.

Conclusion

Let’s Encrypt and Certbot have made SSL/TLS certificates accessible to everyone. With automated issuance and renewal, there is no excuse for serving any website over plain HTTP. By following this guide, you have set up free, automatically renewing certificates and hardened your HTTPS configuration with security headers.

For related topics, check out our articles on moving an Nginx website to HTTPS/SSL, improving SSL performance in Nginx, and creating self-signed certificates on Ubuntu for development environments. If you need to understand which web server to choose, see our comparison of Apache vs. Nginx.