I still remember the panic when a client called saying their website showed a security warning
instead of their homepage. Their SSL certificate had expired—not because they forgot, but because
the renewal process they’d set up somehow failed silently. That site was down for paying customers
for three hours while we sorted it out.

HTTPS is non-negotiable today. Browsers display prominent warnings for HTTP sites. Search engines
penalize them. Users have learned to look for the padlock. And with Let’s Encrypt providing free
certificates and automated renewal, there’s no technical or financial barrier to proper HTTPS.

This guide covers everything you need to know about SSL/TLS certificates for web servers. You’ll
understand what certificates do, how to obtain free ones from Let’s Encrypt using Certbot, how to
configure your web server for optimal security and performance, and how to troubleshoot the common
issues that trip people up. By the end, you’ll have HTTPS running smoothly with automated
renewal—the way it should be.

Understanding SSL/TLS Fundamentals

Before diving into setup, understand what you’re implementing and why it matters.

What Certificates Actually Do

SSL/TLS certificates serve three security functions. First, encryption—they establish encrypted
connections between browsers and servers, protecting data in transit from eavesdropping. Anyone
intercepting the traffic sees encrypted garbage rather than login credentials or personal
information.

Second, authentication—certificates prove your server is who it claims to be. When a browser connects
to yoursite.com, the certificate confirms it’s actually your server, not an attacker pretending to
be you. This prevents man-in-the-middle attacks where attackers intercept and modify traffic.

Third, integrity—TLS connections detect if data was modified during transmission. Any tampering
invalidates the cryptographic signature, alerting the browser that something’s wrong.

Certificate Types Explained

Certificates come in three validation levels, which describe how thoroughly the issuer verified the
certificate requester.

Domain Validation (DV) certificates verify you control the domain name. The issuer confirms you can
create a file on the server or add a DNS record—proof of domain control. DV certificates are issued
automatically in minutes. Let’s Encrypt provides DV certificates, and they’re sufficient for the
vast majority of websites.

Organization Validation (OV) certificates verify your organization’s identity in addition to domain
control. The issuer checks business registration records and contacts the organization. OV takes
days rather than minutes and costs money. The extra validation shows in certificate details but
provides no additional technical security.

Extended Validation (EV) certificates involve rigorous verification of organizational identity,
physical address, and operational status. Years ago, browsers displayed company names in a green
address bar for EV certificates. Modern browsers have removed these visual indicators—EV looks
identical to DV to users. Given the cost and effort without user-visible benefit, EV is rarely worth
it today.

Why Let’s Encrypt Changed Everything

Before Let’s Encrypt, SSL certificates cost $50-200+ per year from commercial certificate
authorities. Many small sites ran without HTTPS because of cost and complexity. Let’s Encrypt,
launched in 2015, provides free, automated, trusted certificates to anyone.

Let’s Encrypt certificates are trusted by all major browsers. They’re functionally equivalent to paid
DV certificates. The only difference is 90-day validity (versus 1-2 years for paid certificates),
but automated renewal makes this irrelevant—Certbot handles renewal automatically.

There’s no legitimate technical reason to pay for DV certificates anymore. Let’s Encrypt made HTTPS
free and accessible for everyone.

Installing Certbot

Certbot is the official Let’s Encrypt client and the recommended way to obtain certificates. It
handles the entire process: domain validation, certificate issuance, server configuration, and
renewal.

Ubuntu and Debian Installation

On Ubuntu 20.04+, Certbot is available through apt. Install the base package plus the plugin for your
web server. For Nginx: sudo apt update followed by sudo apt install certbot python3-certbot-nginx.
For Apache: sudo apt install certbot python3-certbot-apache.

The web server plugins allow Certbot to automatically modify your server configuration—adding
certificate paths, configuring HTTPS, and setting up redirects.

CentOS and RHEL Installation

Enable the EPEL repository first: sudo yum install epel-release. Then install Certbot: sudo yum
install certbot python3-certbot-nginx for Nginx servers.

Manual Installation via Pip

If packages aren’t available or are outdated, install via pip: sudo pip3 install certbot
certbot-nginx. This gets the latest version directly from PyPI.

Obtaining Your First Certificate

With Certbot installed, obtaining a certificate takes one command.

Nginx Automatic Configuration

For Nginx with automatic configuration: sudo certbot –nginx -d example.com -d www.example.com

Certbot prompts for an email address (for expiration warnings), agreement to terms of service, and
whether to redirect HTTP to HTTPS (say yes unless you have specific reasons not to).

Behind the scenes, Certbot proves domain control by placing a temporary file in your web root that
Let’s Encrypt’s servers access, obtains the certificate, installs it in
/etc/letsencrypt/live/example.com/, modifies your Nginx configuration to use it, and sets up
automatic renewal.

Apache Automatic Configuration

Apache works similarly: sudo certbot –apache -d example.com -d www.example.com. Certbot modifies
Apache configuration and enables necessary modules.

Certificate-Only Mode

If you prefer to configure your server manually, obtain just the certificate: sudo certbot certonly
–webroot -w /var/www/html -d example.com -d www.example.com

This creates certificates without modifying server configuration. You’ll find them at
/etc/letsencrypt/live/example.com/fullchain.pem (certificate plus chain) and privkey.pem (private
key).

Standalone Mode

If no web server is running, Certbot can temporarily start its own for validation: sudo certbot
certonly –standalone -d example.com. This requires port 80 to be available during the process.

Configuring Nginx for Optimal TLS

Certbot’s automatic configuration works, but manual optimization achieves better security and
performance.

Modern TLS Configuration

A production Nginx HTTPS configuration should use only TLS 1.2 and 1.3 (disabling older vulnerable
protocols), modern cipher suites prioritizing forward secrecy and AEAD, OCSP stapling for efficient
certificate validation, session caching for performance, and HSTS to enforce HTTPS.

Key settings include ssl_protocols TLSv1.2 TLSv1.3 (no older versions), ssl_prefer_server_ciphers off
(use client preferences for TLS 1.3 compatibility), and ssl_stapling on with ssl_stapling_verify on
for OCSP stapling.

HTTP to HTTPS Redirect

All HTTP traffic should redirect to HTTPS. Configure a separate server block listening on port 80
that returns 301 redirect to the HTTPS URL. Certbot often adds this automatically, but verify it’s
present.

Using Mozilla’s SSL Configuration Generator

Mozilla maintains an SSL Configuration Generator at ssl-config.mozilla.org that produces server
configurations for various web servers and security profiles. The “Modern” profile works for most
sites with recent browser support; “Intermediate” supports older clients.

The generator produces complete, tested configurations. Rather than guessing at cipher suites, use
their recommendations—Mozilla updates them as cryptographic best practices evolve.

Automatic Certificate Renewal

Let’s Encrypt certificates expire after 90 days. This seems short but intentionally encourages
automation—if renewal is manual, 90 days isn’t long and you’ll eventually forget. Automated renewal
makes the short validity irrelevant.

Testing Renewal

Before relying on automatic renewal, test that it works: sudo certbot renew –dry-run. This simulates
the renewal process without actually renewing. If successful, you’ll see messages indicating which
certificates would be renewed.

Common dry-run failures include port 80 blocked by firewall (needed for HTTP validation), web root
path changed since initial certificate issuance, or permission issues accessing certificate files.

How Automatic Renewal Works

Modern Certbot installations include a systemd timer or cron job that checks for renewals twice
daily. Certbot only renews certificates expiring within 30 days, so daily checks don’t cause
unnecessary load on Let’s Encrypt.

Check if the systemd timer is active: sudo systemctl status certbot.timer. If it’s not enabled, start
it: sudo systemctl enable certbot.timer followed by sudo systemctl start certbot.timer.

Post-Renewal Hooks

After renewal, your web server must reload to use the new certificate. Configure renewal hooks: sudo
certbot renew –deploy-hook “systemctl reload nginx”. The deploy hook runs only after successful
renewal, reloading Nginx to pick up the new certificate.

You can make hooks permanent by adding them to /etc/letsencrypt/renewal-hooks/deploy/ as executable
scripts, or adding renew_hook = systemctl reload nginx to the renewal configuration.

Migrating WordPress to HTTPS

Installing a certificate is half the job. WordPress needs configuration updates to fully use HTTPS.

Updating WordPress URLs

WordPress stores site URLs in the database. Update them via wp-config.php by adding define(‘WP_HOME’,
‘https://yoursite.com’) and define(‘WP_SITEURL’, ‘https://yoursite.com’). This overrides database
values.

Alternatively, update directly in the database by changing the siteurl and home options in wp_options
from http to https.

Updating Content URLs

Content created before HTTPS migration contains http:// URLs for images, links, and embedded media.
These cause mixed content warnings—HTTPS pages loading HTTP resources.

Use WP-CLI to search and replace URLs across the database: wp search-replace ‘http://yoursite.com’
‘https://yoursite.com’ –all-tables

The –all-tables flag includes all tables, not just core WordPress tables. The –dry-run flag shows
what would change without making changes—use it first.

If you prefer a GUI, the Better Search Replace plugin provides the same functionality.

Forcing HTTPS in WordPress

Add define(‘FORCE_SSL_ADMIN’, true) to wp-config.php to ensure all admin pages load over HTTPS.

If WordPress runs behind a proxy or load balancer that terminates SSL, WordPress might not know the
connection is HTTPS. Add code to check for X-Forwarded-Proto headers and set $_SERVER[‘HTTPS’]
accordingly.

Troubleshooting Common SSL Issues

Most SSL problems fall into predictable categories with known solutions.

Mixed Content Errors

Symptoms: Browser shows a warning instead of the secure padlock. Developer console shows “Mixed
Content” errors.

Cause: The HTTPS page loads resources (images, scripts, stylesheets) via HTTP. Browsers block or warn
about this because HTTP resources could be modified by attackers.

Diagnosis: Open browser developer tools, go to the Console tab, and look for mixed content warnings.
They specify which resources are problematic.

Solutions: Update hardcoded HTTP URLs to HTTPS in your content, theme, and plugins. Use
protocol-relative URLs (//example.com/image.jpg) that inherit the page’s protocol. Run
search-replace on the database. Check for third-party resources—external scripts or images that
don’t support HTTPS need alternatives.

Certificate Not Trusted

Symptoms: Browser displays “Not Secure” despite HTTPS, or shows certificate errors.

Causes: Certificate expired, missing intermediate chain, or self-signed certificate.

Diagnosis: Click the padlock and examine certificate details. Check expiration date and issuer. Or
use command line: echo | openssl s_client -connect yoursite.com:443 | openssl x509 -noout -dates

Solutions: For expired certificates, renew with certbot renew –force-renewal. For chain issues,
ensure you’re using fullchain.pem (which includes intermediates) rather than just cert.pem. For
self-signed certificates, use Let’s Encrypt instead.

Redirect Loops

Symptoms: “Too many redirects” error when loading the site.

Causes: Multiple redirect rules conflicting. Common when HTTP redirects to HTTPS but something else
redirects back to HTTP.

Diagnosis: Use curl -IL yoursite.com to see the redirect chain. Identify where the loop occurs.

Solutions: Check for conflicting redirects in server configuration, .htaccess, WordPress settings,
and any caching/CDN layers. Behind load balancers, ensure the proper headers (X-Forwarded-Proto) are
passed and WordPress is configured to trust them.

Port 443 Problems

Symptoms: Certbot or Nginx fails to start, reporting port 443 is in use.

Diagnosis: Check what’s using the port with sudo lsof -i :443 or sudo netstat -tlpn | grep 443.

Solutions: Stop conflicting services. Common culprits include Apache running alongside Nginx, old
processes that didn’t terminate, or other services that bound to 443.

Wildcard Certificates

Wildcard certificates secure all subdomains with one certificate: *.example.com covers
blog.example.com, shop.example.com, and any other subdomain.

When to Use Wildcards

Wildcards are useful when you have many subdomains or create them dynamically. They simplify
certificate management—one certificate instead of many.

For sites with few, stable subdomains, individual certificates are simpler. Each subdomain gets its
own certificate automatically through normal Certbot commands.

Obtaining Wildcard Certificates

Let’s Encrypt wildcard certificates require DNS validation rather than HTTP validation. You must add
a TXT record to prove domain control.

Manual process: Run sudo certbot certonly –manual –preferred-challenges=dns -d example.com -d
*.example.com. Certbot displays the TXT record to add (_acme-challenge.example.com with a specific
value). Add it at your DNS provider, wait for propagation, then press Enter to continue.

This manual process doesn’t automate well—you’d need to repeat it every 90 days.

Automated DNS Validation

For automated wildcard renewal, use DNS plugins that automatically manage TXT records. Certbot has
plugins for major DNS providers: Cloudflare, Route53, DigitalOcean, and others.

Install the plugin (e.g., sudo apt install python3-certbot-dns-cloudflare), create a credentials file
with your API token, then run Certbot with DNS validation: sudo certbot certonly –dns-cloudflare
–dns-cloudflare-credentials /path/to/cloudflare.ini -d example.com -d *.example.com

Renewal works automatically because Certbot can manage TXT records through the API.

Testing and Monitoring

SSL Labs Testing

Qualys SSL Labs (ssllabs.com/ssltest) provides the most thorough public SSL test. It examines your
certificate chain, protocol support, cipher suites, and known vulnerabilities, producing a grade
from A+ to F.

Aim for A or A+. Common issues that reduce grades include old protocol versions enabled (TLS
1.0/1.1), weak cipher suites, missing HSTS header, or certificate chain problems.

Monitoring Certificate Expiration

Even with automatic renewal, monitor expirations. Renewal can fail silently due to server changes,
DNS issues, or firewall problems.

Set calendar reminders for two weeks before expiration. Use monitoring services like Let’s Encrypt’s
expiry emails (sent to the email used during certificate creation), external monitoring services
that check certificate validity, or cron jobs that check expiration and alert on problems.

Periodic Configuration Review

TLS best practices evolve. What was secure configuration two years ago might be outdated today.
Quarterly reviews with SSL Labs catch configuration drift—protocols or ciphers that should now be
disabled, new features like TLS 1.3 that should be enabled.

Conclusion

SSL/TLS configuration is foundational web security. Let’s Encrypt and Certbot have made certificate
management straightforward—free certificates, automated renewal, simple tooling. There’s no excuse
for running HTTP in production.

Set up Certbot, obtain your certificate, configure modern TLS settings, automate renewal, and verify
everything works. Then monitor for expiration and periodically review your configuration against
current best practices.

The initial setup takes an hour. The automated renewal runs indefinitely with minimal maintenance.
The security benefit—encrypted, authenticated connections for all your users—is well worth it.