Security

SSL/TLS Certificates with Let's Encrypt

Updated December 2025
16 min read
25.1K views

SSL/TLS certificates encrypt traffic between your server and visitors, protecting sensitive data and improving search engine rankings. This comprehensive guide shows you how to obtain free SSL certificates from Let's Encrypt and configure them for Nginx or Apache with automatic renewal.

1

What is SSL/TLS?

SSL (Secure Sockets Layer) and its successor TLS (Transport Layer Security) encrypt data transmitted between web servers and browsers.

Without SSL (HTTP)

  • ✗ Data sent in plain text
  • ✗ Vulnerable to interception
  • ✗ Passwords visible to attackers
  • ✗ "Not Secure" browser warning
  • ✗ Lower search rankings
  • ✗ Customer trust issues

With SSL (HTTPS)

  • ✓ All data encrypted
  • ✓ Protection from eavesdropping
  • ✓ Secure password transmission
  • ✓ Padlock icon in browser
  • ✓ Better SEO rankings
  • ✓ Customer confidence

Why SSL is Essential

Security:

Encrypts sensitive data like passwords, credit cards, and personal information

Trust:

Browsers display "Not Secure" warnings for HTTP sites, damaging credibility

SEO:

Google prioritizes HTTPS sites in search results

Compliance:

Required for PCI DSS, HIPAA, and other regulations

Industry Standard: As of 2025, over 95% of websites use HTTPS. Running an HTTP-only site is no longer acceptable for any production website.
2

Understanding Let's Encrypt

Let's Encrypt is a free, automated Certificate Authority that provides SSL/TLS certificates trusted by all major browsers.

Why Let's Encrypt?

100% Free

No cost, forever. No hidden fees.

Automated

Auto-renews every 90 days

Trusted

Recognized by all browsers

How Let's Encrypt Works

1.
Domain Validation: Proves you control the domain

Certbot places a file on your web server that Let's Encrypt verifies

2.
Certificate Issuance: Receives signed certificate

Let's Encrypt issues a certificate valid for 90 days

3.
Auto-Configuration: Configures web server

Certbot automatically updates Nginx/Apache configuration

4.
Auto-Renewal: Renews before expiration

Certbot runs twice daily to check and renew if needed

Prerequisites

  • A domain name pointing to your server's IP address
  • Web server (Nginx or Apache) installed and running
  • Port 80 and 443 open in your firewall
  • Root/sudo access to your server
Important: Your domain must be publicly accessible on port 80 for Let's Encrypt validation to work. Make sure DNS is properly configured and firewall allows HTTP traffic before proceeding.
3

Installing Certbot for Nginx

Certbot is the official Let's Encrypt client that automates certificate installation and renewal.

Step 1: Install Certbot

# Ubuntu/Debian
sudo apt update
sudo apt install certbot python3-certbot-nginx -y

# CentOS/RHEL 8/9
sudo dnf install certbot python3-certbot-nginx -y

# Verify installation
certbot --version

Step 2: Configure Nginx

Ensure your Nginx server block is properly configured:

# Example: /etc/nginx/sites-available/example.com
server {
    listen 80;
    server_name example.com www.example.com;

    root /var/www/example.com/html;
    index index.html index.htm index.php;

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

# Enable the site (Ubuntu/Debian)
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

# Test configuration
sudo nginx -t

# Reload Nginx
sudo systemctl reload nginx

Step 3: Obtain SSL Certificate

# Automatic installation (recommended)
sudo certbot --nginx -d example.com -d www.example.com

# You'll be prompted to:
# 1. Enter email address (for renewal notifications)
# 2. Agree to Terms of Service
# 3. Choose whether to redirect HTTP to HTTPS (choose option 2)
Success! Certbot automatically:
  • • Obtained and installed the certificate
  • • Configured Nginx for HTTPS
  • • Set up automatic redirect from HTTP to HTTPS
  • • Scheduled automatic renewal

Step 4: Verify SSL Configuration

# Check certificate details
sudo certbot certificates

# Test your site
curl -I https://example.com

# Check SSL rating (should be A+ after optimization)
# Visit: https://www.ssllabs.com/ssltest/analyze.html?d=example.com

Manual Certificate Only (No Auto-Config)

If you prefer to configure Nginx manually:

# Get certificate without modifying Nginx config
sudo certbot certonly --nginx -d example.com -d www.example.com

# Certificate files will be saved to:
# /etc/letsencrypt/live/example.com/fullchain.pem
# /etc/letsencrypt/live/example.com/privkey.pem

# Then manually configure Nginx:
sudo nano /etc/nginx/sites-available/example.com

Example Nginx SSL configuration:

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;

    # Security headers
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';

    root /var/www/example.com/html;
    index index.html;

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

# Redirect HTTP to HTTPS
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}
4

Installing Certbot for Apache

Step 1: Install Certbot

# Ubuntu/Debian
sudo apt update
sudo apt install certbot python3-certbot-apache -y

# CentOS/RHEL 8/9
sudo dnf install certbot python3-certbot-apache mod_ssl -y

Step 2: Configure Apache Virtual Host

# Example: /etc/apache2/sites-available/example.com.conf (Ubuntu/Debian)
# or /etc/httpd/conf.d/example.com.conf (CentOS/RHEL)


    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/example.com/html

    
        AllowOverride All
        Require all granted
    

    ErrorLog ${APACHE_LOG_DIR}/example.com_error.log
    CustomLog ${APACHE_LOG_DIR}/example.com_access.log combined


# Enable the site (Ubuntu/Debian)
sudo a2ensite example.com.conf

# Test configuration
sudo apachectl configtest

# Reload Apache
sudo systemctl reload apache2   # Ubuntu/Debian
# sudo systemctl reload httpd   # CentOS/RHEL

Step 3: Obtain SSL Certificate

# Automatic installation
sudo certbot --apache -d example.com -d www.example.com

# Certbot will:
# - Obtain the certificate
# - Create a new VirtualHost on port 443
# - Configure SSL settings
# - Set up HTTP to HTTPS redirect

Step 4: Verify Installation

# Check Apache SSL configuration
sudo apachectl -S

# Verify certificate
sudo certbot certificates

# Test HTTPS
curl -I https://example.com
Apache Modules: Certbot automatically enables required Apache modules (ssl, rewrite, headers). On Ubuntu/Debian, you may need to manually enable them: sudo a2enmod ssl rewrite headers
5

Wildcard Certificates

Wildcard certificates cover all subdomains (*.example.com) with a single certificate.

DNS Challenge Method

Wildcard certificates require DNS validation (not HTTP validation):

# Request wildcard certificate
sudo certbot certonly \
  --manual \
  --preferred-challenges dns \
  -d example.com \
  -d *.example.com

# Certbot will instruct you to:
# 1. Create a TXT record in your DNS
# 2. Wait for DNS propagation
# 3. Press Enter to continue

# Example TXT record:
# _acme-challenge.example.com  TXT  "abc123..."

Automated DNS Validation

For automatic renewal, use DNS API plugins:

# Install Cloudflare plugin (if using Cloudflare)
sudo apt install python3-certbot-dns-cloudflare -y

# Create credentials file
sudo mkdir -p /etc/letsencrypt
sudo nano /etc/letsencrypt/cloudflare.ini

# Add your Cloudflare API token:
dns_cloudflare_api_token = YOUR_API_TOKEN

# Secure the credentials file
sudo chmod 600 /etc/letsencrypt/cloudflare.ini

# Request wildcard certificate with auto-renewal
sudo certbot certonly \
  --dns-cloudflare \
  --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
  -d example.com \
  -d *.example.com
DNS Plugins Available: Certbot supports plugins for Cloudflare, DigitalOcean, Route53, Google Cloud DNS, and many others. Check the official documentation for your DNS provider.
6

Automatic Renewal

Let's Encrypt certificates expire after 90 days. Certbot automatically sets up renewal.

Check Auto-Renewal Status

# Test renewal process (dry run - doesn't actually renew)
sudo certbot renew --dry-run

# Check renewal timer (systemd)
sudo systemctl status certbot.timer

# View renewal configuration
sudo cat /etc/cron.d/certbot

Manual Renewal

# Renew all certificates that are due for renewal
sudo certbot renew

# Force renew specific certificate
sudo certbot renew --cert-name example.com --force-renewal

# Renew and reload web server
sudo certbot renew --post-hook "systemctl reload nginx"

Renewal Hooks

Run commands before/after renewal:

# Create renewal hook script
sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-services.sh

# Add content:
#!/bin/bash
systemctl reload nginx
systemctl reload php8.1-fpm

# Make executable
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-services.sh

# This script runs automatically after successful renewal

Monitoring Renewal

# Check certificate expiration dates
sudo certbot certificates

# Output shows:
# Certificate Name: example.com
#   Domains: example.com www.example.com
#   Expiry Date: 2026-03-05 12:34:56+00:00 (VALID: 89 days)
#   Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem
#   Private Key Path: /etc/letsencrypt/live/example.com/privkey.pem
Set It and Forget It: Certbot renews certificates automatically 30 days before expiration. You'll receive email notifications if renewal fails, giving you plenty of time to fix issues.
7

Troubleshooting Common Issues

❌ "Connection Refused" Error

Certbot can't connect to your web server on port 80.

Solutions:

# Check if web server is running
sudo systemctl status nginx  # or apache2/httpd

# Check if port 80 is open
sudo netstat -tlnp | grep :80

# Check firewall
sudo ufw status
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Test local access
curl -I http://localhost

❌ "Too Many Requests" Error

Hit Let's Encrypt rate limits (5 failures per hour).

Solutions:

  • Wait 1 hour and try again
  • Use --dry-run for testing
  • Use staging environment: --test-cert

❌ "Domain Verification Failed"

Let's Encrypt can't verify domain ownership.

Solutions:

# Check DNS propagation
dig example.com
nslookup example.com

# Verify domain points to your server
curl -I http://example.com

# Check web server configuration
sudo nginx -t
sudo apachectl configtest

# Check server_name/ServerName directive matches your domain

❌ Certificate Not Trusted in Browser

Browser shows security warning.

Solutions:

# Check certificate chain
openssl s_client -connect example.com:443 -showcerts

# Verify you're using fullchain.pem (not cert.pem)
# Nginx: ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem
# Apache: SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem

# Clear browser cache and test in incognito mode

❌ Automatic Renewal Failing

Certificates not renewing automatically.

Solutions:

# Test renewal
sudo certbot renew --dry-run

# Check renewal timer
sudo systemctl status certbot.timer

# Check logs
sudo tail -f /var/log/letsencrypt/letsencrypt.log

# Manually renew to see errors
sudo certbot renew --force-renewal

# Ensure web server config hasn't changed
# Renewal uses same method as initial issuance
8

SSL Best Practices

Security Hardening

Use Strong Cipher Suites

Disable weak ciphers. Use only TLS 1.2 and 1.3.

Enable HSTS

Force HTTPS for all future visits with HTTP Strict Transport Security.

Enable HTTP/2

Improve performance with HTTP/2 protocol.

OCSP Stapling

Speed up SSL handshake and improve privacy.

Optimized Nginx SSL Configuration

# /etc/nginx/snippets/ssl-params.conf
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';
ssl_ecdh_curve secp384r1;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;

# HSTS (force HTTPS for 1 year)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

# 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;

# Then in your server block:
server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    include /etc/nginx/snippets/ssl-params.conf;

    # ... rest of configuration
}

Test Your SSL Configuration

# Online tools (aim for A+ rating):
# https://www.ssllabs.com/ssltest/
# https://securityheaders.com/

# Command line testing
openssl s_client -connect example.com:443 -tls1_2
curl -I https://example.com
SSL Labs A+ Rating: Following the configuration above should give you an A+ rating on SSL Labs. This represents the highest level of SSL/TLS security configuration.