How to Deploy SSL Certificates with Certbot - Complete Step by Step Guide

Mar 26, 2026

What is This Guide About?

This guide will help you use Certbot to get free SSL certificates for your website. Certbot is a simple, automatic tool that makes your website secure (the padlock icon in your browser) and keeps it that way with automatic renewals.

Before you start: Make sure you have already installed Certbot on your server. If you have not, you will need to complete the installation first.


Getting Your First SSL Certificate

Let's start by getting your first SSL certificate. This process will prove you own your domain and get you a trusted certificate.

Step 1: Load Your Credentials

First, you need to load your account information. This tells Certbot who you are:

source /root/.secrets/acme-eab.env

This command loads your certificate provider credentials from a secure location on your server.

Step 2: Request Your Certificate

Now, let's get your SSL certificate. Here is the command for a single domain:

certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
--dns-cloudflare-propagation-seconds 30 \
--server "$ACME_SERVER" \
--eab-kid "$EAB_KEY" \
--eab-hmac-key "$HMAC_KEY" \
--email "$EMAIL" \
--agree-tos \
--no-eff-email \
--non-interactive \
--issuance-timeout 600 \
-d demo.example.com

Replace demo.example.com with your actual domain name.

What this command does:

  • Uses Cloudflare to prove you own the domain
  • Loads your secure credentials
  • Requests the certificate from the SSL provider
  • Saves the certificate on your server

Step 3: Verify Success

If everything worked, you will see a success message like this:

Requesting a certificate for demo.example.com
Waiting for verification...
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/demo.example.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/demo.example.com/privkey.pem

Congratulations! You now have a valid SSL certificate.


Different Types of SSL Certificates

Depending on your needs, you can get different types of certificates:

Option 1: Multiple Domains in One Certificate

If you want one certificate to cover several related domains, add multiple -d flags:

certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
--dns-cloudflare-propagation-seconds 30 \
--server "$ACME_SERVER" \
--eab-kid "$EAB_KEY" \
--eab-hmac-key "$HMAC_KEY" \
--email "$EMAIL" \
--agree-tos \
--no-eff-email \
--non-interactive \
--issuance-timeout 600 \
-d example.com \
-d www.example.com \
-d mail.example.com

Use this when: You have a few specific domains that belong together.

Option 2: Wildcard Certificate

This covers ALL subdomains under your main domain automatically:

certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
--dns-cloudflare-propagation-seconds 30 \
--server "$ACME_SERVER" \
--eab-kid "$EAB_KEY" \
--eab-hmac-key "$HMAC_KEY" \
--email "$EMAIL" \
--agree-tos \
--no-eff-email \
--non-interactive \
--issuance-timeout 600 \
-d "*.example.com" \
-d example.com

Use this when: You have many subdomains or create them frequently.

Example: One certificate covers blog.example.com, shop.example.com, api.example.com, and any other subdomain you create.


Where Are Your Certificates Stored?

After getting a certificate, Certbot saves several files in a specific folder:

/etc/letsencrypt/live/demo.example.com/
??? cert.pem # Your certificate only
??? chain.pem # Intermediate certificates
??? fullchain.pem # Complete certificate (USE THIS!)
??? privkey.pem # Private key (KEEP SECRET!)
??? README # Information file

Important Files Explained

FileDescription
fullchain.pemTHIS IS THE ONE YOU WILL USE! Contains your complete certificate with all necessary parts. Use this for Apache, Nginx, and most web servers.
privkey.pemVERY IMPORTANT — KEEP THIS SECRET! This is your private key. NEVER share this with anyone. Do not upload it to public places. Keep permissions restricted (only readable by root).
cert.pemYour certificate only (without intermediate certificates).
chain.pemIntermediate certificates only (without your domain certificate).
???? Note These files are symbolic links (shortcuts) that point to the real certificates stored in /etc/letsencrypt/archive/. This system makes it easy to update certificates without changing your web server configuration.

Setting Up Automatic Renewal

SSL certificates expire after 90 days. Certbot can automatically renew them before they expire. You have two options:

Modern Linux systems use systemd timers. Certbot usually sets this up automatically during installation.

Step 1: Check if the Timer is Active

sudo systemctl status certbot.timer

This shows if automatic renewal is running.

Step 2: Enable the Timer (if not already active)

sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer

These commands turn on automatic renewal and start it running.

Step 3: View the Renewal Schedule

sudo systemctl list-timers certbot.timer

This shows when Certbot will next check for renewals. Expected output:

NEXT                        LEFT      LAST                        PASSED    UNIT
Sun 2026-02-10 00:00:00 UTC 13h left Sat 2026-02-09 00:00:00 UTC 11h ago certbot.timer
Sun 2026-02-10 12:00:00 UTC 1h left Sat 2026-02-09 12:00:00 UTC 23h ago certbot.timer

This shows Certbot runs twice daily to check for certificates that need renewal.

Step 4: Test the Renewal Process

Before relying on automatic renewal, test it to make sure it works:

sudo certbot renew --dry-run

The --dry-run flag means "test mode" — it will not actually renew anything, just checks that renewal would work.

Option 2: Cron Job (Alternative Method)

If your system does not use systemd, you can use a traditional cron job:

Step 1: Open the Cron Editor

sudo crontab -e

This opens a text editor where you can add scheduled tasks.

Step 2: Add the Renewal Command

Add this line to run renewal twice daily (at 2:30 AM and 2:30 PM):

30 2,14 * * * /usr/bin/certbot renew --quiet --deploy-hook "/usr/local/bin/deploy-cert.sh"

What this means:

  • 30 2,14 * * * — Run at 2:30 AM and 2:30 PM every day
  • --quiet — Do not show output unless there is an error
  • --deploy-hook — Run a script after renewal to update your web server

Automatic Deployment After Renewal

When Certbot renews a certificate, you need to tell your web server to use the new certificate. A deployment script does this automatically.

Creating the Deployment Script

Step 1: Create the Script File

This creates a script that will run automatically after each renewal:

sudo tee /usr/local/bin/deploy-cert.sh > /dev/null << 'EOF'
#!/bin/bash
# Automatically update web servers after certificate renewal

LOG_FILE="/var/log/cert-deploy.log"

log() {
echo "$(date '%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# Get the renewed domain name
PRIMARY_DOMAIN=$(echo "$RENEWED_DOMAINS" | awk '{print $1}')
log "Certificate renewed for: $PRIMARY_DOMAIN"

# Restart Apache (if installed)
if command -v apache2ctl &> /dev/null; then
systemctl reload apache2
log "Apache reloaded"
fi

# Restart Nginx (if installed)
if command -v nginx &> /dev/null; then
systemctl reload nginx
log "Nginx reloaded"
fi

log "Deployment completed"
EOF

This script does the following:

  • Writes a log entry showing which certificate was renewed
  • Reloads Apache if it is installed
  • Reloads Nginx if it is installed
  • Records everything in a log file

Step 2: Make the Script Executable

sudo chmod +x /usr/local/bin/deploy-cert.sh

This gives the script permission to run.

Step 3: Test the Script

Before trusting automatic deployment, test the script manually:

export RENEWED_DOMAINS="demo.example.com"
export RENEWED_LINEAGE="/etc/letsencrypt/live/demo.example.com"
sudo /usr/local/bin/deploy-cert.sh

Check the log file to see if it worked:

sudo tail /var/log/cert-deploy.log

Installing Certificates on Your Web Server

Now that you have a certificate, you need to configure your web server to use it.

For Apache Web Server

Step 1: Create SSL Configuration

sudo tee /etc/apache2/sites-available/demo.example.com-ssl.conf > /dev/null << 'EOF'
<VirtualHost *:443>
ServerName demo.example.com
ServerAdmin admin@demo.example.com
DocumentRoot /var/www/demo.example.com

# SSL Configuration
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/demo.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/demo.example.com/privkey.pem

# Modern SSL configuration (Mozilla Intermediate)
SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
SSLHonorCipherOrder off
SSLSessionTickets off

# HSTS (optional but recommended)
Header always set Strict-Transport-Security "max-age=63072000"

<Directory /var/www/demo.example.com>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>

ErrorLog ${APACHE_LOG_DIR}/demo.example.com-error.log
CustomLog ${APACHE_LOG_DIR}/demo.example.com-access.log combined
</VirtualHost>
EOF
? Important Replace demo.example.com with your actual domain name throughout the configuration.

Step 2: Enable SSL Module and Site

sudo a2enmod ssl headers
sudo a2ensite demo.example.com-ssl

These commands enable SSL support and activate your secure site.

Step 3: Test and Apply Configuration

sudo apache2ctl configtest
sudo systemctl reload apache2

The first command checks for errors. The second applies the changes.

For Nginx Web Server

Step 1: Create SSL Configuration

sudo tee /etc/nginx/sites-available/demo.example.com > /dev/null << 'EOF'
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;

server_name demo.example.com;
root /var/www/demo.example.com;
index index.html index.php;

# SSL Configuration
ssl_certificate /etc/letsencrypt/live/demo.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/demo.example.com/privkey.pem;

# Modern SSL configuration (Mozilla Intermediate)
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 10m;
ssl_session_tickets off;

# HSTS (optional but recommended)
add_header Strict-Transport-Security "max-age=63072000" always;

# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;

location / {
try_files $uri $uri/ =404;
}

# PHP processing (if needed)
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}

access_log /var/log/nginx/demo.example.com-access.log;
error_log /var/log/nginx/demo.example.com-error.log;
}

# HTTP to HTTPS redirect
server {
listen 80;
listen [::]:80;
server_name demo.example.com;
return 301 https://$host$request_uri;
}
EOF
???? Note The second server block automatically redirects HTTP to HTTPS, ensuring all visitors use the secure connection.

Step 2: Enable Site and Test

sudo ln -s /etc/nginx/sites-available/demo.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

What these commands do:

  1. Create a link to enable the site
  2. Test the configuration for errors
  3. Apply the changes

Advanced Deployment Scenarios

For more complex setups, you can customize how certificates are deployed after renewal. These advanced scenarios cover multiple servers, different services, and cloud integrations.

Scenario 1: Multiple Domains with Different Web Servers

If you have different domains that need different services restarted, you can create a smart deployment script that handles each domain appropriately.

Use this when:

  • You have multiple websites on one server
  • Different domains use different web servers (Apache, Nginx)
  • Some domains are for email servers (Postfix, Dovecot)

What this script does:

  • Identifies which domain was renewed
  • Restarts only the appropriate service for that domain
  • Handles unknown domains gracefully

Scenario 2: Load Balancer / Multiple Backend Servers

If you use a load balancer or have multiple web servers, you need to copy renewed certificates to all backend servers automatically.

Use this when:

  • You have multiple web servers behind a load balancer
  • You need high availability with server redundancy
  • All servers need the same SSL certificate

Prerequisites:

  • SSH access to all backend servers
  • SSH keys configured for password-less login

What this script does:

  • Loops through each backend server
  • Copies the new certificate files via SCP (secure copy)
  • Remotely reloads the web server on each server
  • Ensures all servers have identical, current certificates
???? Pro Tip: Setting Up SSH Keys To enable password-less copying, run this once on your main server:

ssh-keygen (press Enter for all prompts)

Then copy the key to each backend:
ssh-copy-id root@server1.example.com

Scenario 3: Azure Cloud Integration

If you use Microsoft Azure services, you can automatically upload renewed certificates to Azure Key Vault for use with Application Gateway, App Services, or other Azure resources.

Use this when:

  • You use Azure Application Gateway
  • You have Azure App Services requiring SSL certificates
  • You want centralized certificate management in Azure

Prerequisites:

  • Azure CLI installed (az command)
  • Azure account authenticated (az login)
  • Azure Key Vault created

What this script does:

  • Converts the certificate to PFX format (required by Azure)
  • Uploads the certificate to your Azure Key Vault
  • Cleans up temporary files for security
  • Makes the certificate available to all Azure services

Important customization:

  • Replace mykeyvault with your actual Key Vault name
  • Replace YourSecurePassword123! with a strong password
  • Update CERT_NAME to match your certificate naming convention

Monitoring Your Certificates

Regular monitoring ensures your certificates stay valid and your site remains secure.

Check All Your Certificates

sudo certbot certificates

This shows all certificates managed by Certbot, including expiry dates. Example output:

Certificate Name: demo.example.com
Serial Number: 123456789abcdef
Domains: demo.example.com
Expiry Date: 2026-05-10 10:00:00+00:00 (VALID: 89 days)
Certificate Path: /etc/letsencrypt/live/demo.example.com/fullchain.pem
Private Key Path: /etc/letsencrypt/live/demo.example.com/privkey.pem

View Renewal Logs

Check what Certbot has been doing:

sudo tail -f /var/log/letsencrypt/letsencrypt.log

This shows real-time activity from Certbot.

Test Your SSL Configuration Online

Use online tools to verify your SSL is properly configured:

ToolURL
SSL Labs Testhttps://www.ssllabs.com/ssltest/
Security Headers Checkhttps://securityheaders.com/

End of Certbot SSL Deployment Guide


Have any Questions

Call HTTPS

If you have any questions, feel free to call us