Post

Complete Guide to Certbot - Automatic SSL Certificate Renewal

Certbot is a free, open-source tool that helps you automate the process of obtaining and renewing SSL/TLS certificates from Let's Encrypt, a Certificate Authority (CA) that provides free certificates for secure HTTPS.

Complete Guide to Certbot - Automatic SSL Certificate Renewal

Certbot Setup and Implemenetation Guide

Table of Contents

  1. Introduction
  2. Prerequisites
  3. Installing Certbot
  4. Obtaining Your First Certificate
  5. Setting Up Automatic Renewal
  6. Verifying Automatic Renewal
  7. Advanced Configuration
  8. Troubleshooting
  9. Security Best Practices
  10. Additional Resources

Introduction

This guide will walk you through the process of installing Certbot, obtaining your first certificate, and setting up automatic renewals to ensure your site maintains secure HTTPS connections without manual intervention.

Prerequisites

Before getting started with Certbot, you’ll need:

  • A registered domain name pointing to your server
  • A web server (Apache, Nginx, etc.) installed and configured
  • Root or sudo access to your server
  • Basic command line knowledge
  • Port 80 or 443 open in your firewall (for domain validation)

Installing Certbot

Installation methods vary by operating system and web server. Here are the most common methods:

Debian/Ubuntu

1
2
3
4
5
6
7
8
9
10
11
12
# Update package lists
sudo apt update

# Install Certbot and web server plugins
# For Apache:
sudo apt install certbot python3-certbot-apache

# For Nginx:
sudo apt install certbot python3-certbot-nginx

# For standalone:
sudo apt install certbot

CentOS/RHEL 7

1
2
3
4
5
6
7
8
9
10
11
12
# Enable EPEL repository
sudo yum install epel-release

# Install Certbot
sudo yum install certbot

# Install web server plugins
# For Apache:
sudo yum install python-certbot-apache

# For Nginx:
sudo yum install python-certbot-nginx

CentOS/RHEL 8 and Later

1
2
3
4
5
6
7
8
9
# Install Certbot
sudo dnf install certbot

# Install web server plugins
# For Apache:
sudo dnf install python3-certbot-apache

# For Nginx:
sudo dnf install python3-certbot-nginx

Other Systems

For other operating systems or package managers, visit the official Certbot website to find installation instructions specific to your environment: https://certbot.eff.org/instructions

Obtaining Your First Certificate

The easiest way to obtain certificates is to use Certbot’s plugin for your web server, which automatically configures your server to use the certificate.

For Apache:

1
sudo certbot --apache -d example.com -d www.example.com

For Nginx:

1
sudo certbot --nginx -d example.com -d www.example.com

Using Standalone Mode

If you don’t have a web server running or prefer to configure it manually:

1
sudo certbot certonly --standalone -d example.com -d www.example.com

This temporarily starts its own web server for domain validation.

Using Webroot Mode

If you have a working web server and want Certbot to place validation files in its document root:

1
sudo certbot certonly --webroot -w /var/www/html -d example.com -d www.example.com

Interactive Mode

For a guided experience:

1
sudo certbot

Follow the prompts to select your web server and domains.

Common Parameters Explained

  • --apache or --nginx: Use the respective web server plugin
  • certonly: Obtain certificate without modifying your web server configuration
  • -d domain.com: Specify domain(s) to include in the certificate
  • --webroot -w /path/to/webroot: Use webroot authentication method
  • --email [email protected]: Register with the specified email
  • --agree-tos: Automatically agree to terms of service
  • --non-interactive: Run without user interaction
  • --dry-run: Test the certificate process without making actual changes

Setting Up Automatic Renewal

Certbot installs a timer and service that runs twice daily and automatically renews certificates that are within 30 days of expiration. This happens by default on most installations.

Verifying the Renewal Timer

To check if the automatic renewal service is active:

On systemd-based systems (most modern Linux distributions):

1
sudo systemctl status certbot.timer

If not active, enable and start it:

1
2
sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer

Manual Cron Setup (Alternative)

If the automatic timer isn’t available on your system, create a cron job:

1
sudo crontab -e

Add the following line to run renewal check twice daily:

1
0 */12 * * * certbot renew --quiet

Verifying Automatic Renewal

Testing the Renewal Process

To test if automatic renewal works correctly (without actually renewing):

1
sudo certbot renew --dry-run

If successful, you’ll see confirmation that the test ran without errors.

Checking Certificate Expiration

To check when your certificates expire:

1
sudo certbot certificates

Forcing a Renewal (For Testing)

To force a renewal regardless of expiration date:

1
sudo certbot renew --force-renewal

Note: Don’t use --force-renewal regularly as it may lead to rate limiting.

Detailed Web Server Configurations

Nginx Configuration

Basic SSL Configuration with Certbot

When you run certbot --nginx, Certbot automatically modifies your Nginx configuration files to enable SSL. However, understanding the changes and how to optimize them is important.

A typical Nginx SSL server block created by Certbot looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
server {
    listen 80;
    server_name example.com www.example.com;
    
    # Redirect HTTP to HTTPS
    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name example.com www.example.com;
    
    # SSL certificate paths (added by Certbot)
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
    
    # Your website root and other configurations
    root /var/www/example.com;
    index index.html index.htm;
    
    location / {
        try_files $uri $uri/ =404;
    }
    
    # Additional website configurations
}

Enhanced SSL Security Settings

For improved security, add these configurations to your Nginx server block:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
server {
    # Existing SSL configurations
    
    # Improved SSL settings
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;
    
    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
    
    # HTTP Strict Transport Security
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    
    # Other security headers
    add_header X-Content-Type-Options nosniff;
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-XSS-Protection "1; mode=block";
}

Auto-Renewal Configuration for Nginx

For Certbot renewals to work smoothly with Nginx:

  1. Ensure Nginx configuration files are writable by the user running Certbot:
    1
    2
    
    sudo chown -R root:www-data /etc/nginx/sites-available/
    sudo chmod -R 750 /etc/nginx/sites-available/
    
  2. Add a post-renewal hook to reload Nginx:
    1
    2
    
    sudo mkdir -p /etc/letsencrypt/renewal-hooks/post
    sudo nano /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh
    

    Add this content:

    1
    2
    
    #!/bin/bash
    nginx -t && systemctl reload nginx
    

    Make it executable:

    1
    
    sudo chmod +x /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh
    

Testing Nginx Configuration

Always test your Nginx configuration before applying changes:

1
sudo nginx -t

If successful, reload Nginx:

1
sudo systemctl reload nginx

Apache2 Configuration

Basic SSL Configuration with Certbot

When you run certbot --apache, Certbot modifies your Apache configuration to enable SSL. The changes typically look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    
    # Redirect all HTTP to HTTPS
    RewriteEngine on
    RewriteCond %{SERVER_NAME} =example.com [OR]
    RewriteCond %{SERVER_NAME} =www.example.com
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    
    DocumentRoot /var/www/example.com
    
    # SSL Configuration (added by Certbot)
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
    Include /etc/letsencrypt/options-ssl-apache.conf
    
    # Other Apache configurations
    <Directory /var/www/example.com>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>
    
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

Enhanced SSL Security Settings for Apache

For improved security, add these configurations to your Apache SSL VirtualHost:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<VirtualHost *:443>
    # Existing SSL configurations
    
    # Improved SSL settings
    SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
    SSLHonorCipherOrder on
    SSLCompression off
    SSLSessionTickets off
    
    # Strong cipher suite
    SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
    
    # OCSP Stapling
    SSLUseStapling on
    SSLStaplingCache "shmcb:logs/stapling-cache(150000)"
    SSLStaplingResponseMaxAge 900
    
    # HTTP Strict Transport Security
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    
    # Other security headers
    Header always set X-Content-Type-Options nosniff
    Header always set X-Frame-Options SAMEORIGIN
    Header always set X-XSS-Protection "1; mode=block"
</VirtualHost>

Enabling Required Apache Modules

Make sure all required modules are enabled for optimal SSL functionality:

1
2
3
4
5
sudo a2enmod ssl
sudo a2enmod headers
sudo a2enmod rewrite
sudo a2enmod socache_shmcb  # For OCSP stapling
sudo systemctl restart apache2

Auto-Renewal Configuration for Apache

For Certbot renewals to work smoothly with Apache:

  1. Ensure Apache configuration files are accessible to Certbot:
    1
    2
    
    sudo chown -R root:www-data /etc/apache2/sites-available/
    sudo chmod -R 750 /etc/apache2/sites-available/
    
  2. Add a post-renewal hook to reload Apache:
    1
    2
    
    sudo mkdir -p /etc/letsencrypt/renewal-hooks/post
    sudo nano /etc/letsencrypt/renewal-hooks/post/apache-reload.sh
    

    Add this content:

    1
    2
    
    #!/bin/bash
    apache2ctl configtest && systemctl reload apache2
    

    Make it executable:

    1
    
    sudo chmod +x /etc/letsencrypt/renewal-hooks/post/apache-reload.sh
    

Testing Apache Configuration

Always test your Apache configuration before applying changes:

1
sudo apache2ctl configtest

If successful, reload Apache:

1
sudo systemctl reload apache2

Handling Multiple Domains and Subdomains

Both Nginx and Apache can host multiple domains using separate SSL certificates, or using a single certificate covering multiple domains.

Multiple Domains with One Certificate

When generating the certificate, include all domains:

1
sudo certbot --nginx -d example.com -d www.example.com -d blog.example.com

Or for Apache:

1
sudo certbot --apache -d example.com -d www.example.com -d blog.example.com

Wildcard Certificates

For covering all subdomains with one certificate:

1
sudo certbot certonly --manual --preferred-challenges dns -d example.com -d *.example.com

Managing Certificate Renewals with Complex Web Server Setups

For servers running both Nginx and Apache, or running in containers:

  1. Create a specific renewal configuration:
    1
    
    sudo nano /etc/letsencrypt/renewal/example.com.conf
    
  2. Configure custom hooks for each server type:
    1
    
    renew_hook = /path/to/your/custom-renewal-script.sh
    
  3. Create the custom script:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    #!/bin/bash
    # Reload all web servers
    nginx -t && systemctl reload nginx
    apache2ctl configtest && systemctl reload apache2
       
    # Additional actions like container restarts
    docker restart web-container
       
    # Notification
    echo "Certificate for example.com renewed on $(date)" | mail -s "Certificate Renewal" [email protected]
    

Advanced Configuration

Pre-Renewal and Post-Renewal Hooks

You can execute commands before and after renewal with hooks:

1
sudo certbot renew --pre-hook "command to run before" --post-hook "command to run after"

To make these hooks permanent, create a configuration file:

1
sudo mkdir -p /etc/letsencrypt/renewal-hooks/pre /etc/letsencrypt/renewal-hooks/post /etc/letsencrypt/renewal-hooks/deploy

Add executable scripts to these directories to run automatically.

Custom Configuration File

For advanced configurations, create/edit the renewal configuration:

1
sudo nano /etc/letsencrypt/renewal/example.com.conf

Example configuration with hooks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# renew_before_expiry = 30 days
version = 1.21.0
archive_dir = /etc/letsencrypt/archive/example.com
cert = /etc/letsencrypt/live/example.com/cert.pem
privkey = /etc/letsencrypt/live/example.com/privkey.pem
chain = /etc/letsencrypt/live/example.com/chain.pem
fullchain = /etc/letsencrypt/live/example.com/fullchain.pem

# Options and hooks
authenticator = nginx
installer = nginx
pre_hook = service nginx stop
post_hook = service nginx start
renew_hook = systemctl reload nginx

DNS Challenge for Wildcard Certificates

To issue wildcard certificates (e.g., *.example.com), you’ll need to use the DNS challenge:

1
sudo certbot certonly --manual --preferred-challenges dns -d example.com -d *.example.com

For automated DNS validation, use a DNS plugin appropriate for your provider:

1
2
# Example for Cloudflare
sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials /path/to/credentials.ini -d example.com -d *.example.com

Troubleshooting

Common Issues and Solutions

Rate Limiting

Let’s Encrypt enforces rate limits. If you hit them, wait before trying again or use the staging environment for testing:

1
sudo certbot --staging ...

Port 80/443 Not Available

If another service is using ports 80/443:

  1. Temporarily stop the service
  2. Use DNS validation instead
  3. Configure your web server to forward validation requests to Certbot

Permission Issues

Ensure Certbot has appropriate permissions:

1
2
sudo chmod -R 0755 /etc/letsencrypt/
sudo chown -R root:root /etc/letsencrypt/

Renewal Failures

Check renewal logs:

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

Debugging Commands

Use verbose output for troubleshooting:

1
sudo certbot --verbose ...

Test renewal with debug output:

1
sudo certbot renew --dry-run --debug

Security Best Practices

File Permissions

Secure your certificate private keys:

1
2
sudo chmod -R 0600 /etc/letsencrypt/archive
sudo chmod -R 0600 /etc/letsencrypt/live

OCSP Stapling

Enable OCSP stapling in your web server for improved performance and privacy.

For Nginx:

1
2
3
4
5
6
server {
    # Other configurations
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
}

For Apache:

1
2
3
4
5
<VirtualHost *:443>
    # Other configurations
    SSLUseStapling on
    SSLStaplingCache "shmcb:logs/stapling-cache(150000)"
</VirtualHost>

HSTS (HTTP Strict Transport Security)

Implement HSTS to enforce HTTPS connections:

For Nginx:

1
2
3
4
server {
    # Other configurations
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}

For Apache:

1
2
3
4
<VirtualHost *:443>
    # Other configurations
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</VirtualHost>

Additional Resources


Remember that SSL/TLS certificates from Let’s Encrypt are valid for 90 days, but with automatic renewal correctly configured, you shouldn’t need to worry about manual renewals again. The short certificate lifetime is a security feature, ensuring that compromised keys have a limited validity period.

This post is licensed under CC BY 4.0 by the author.