How to Set Up HTTPS for WordPress with Let’s Encrypt

Let’s Encrypt provides free, automated SSL/TLS certificates that are trusted by all major browsers. Combined with Certbot, you can go from HTTP to HTTPS in under ten minutes — and the certificate will auto-renew before expiry.

Problem: How do you add a free SSL certificate to a WordPress site running on a VPS and redirect all traffic from HTTP to HTTPS?

Solution: Use Certbot to obtain a certificate from Let's Encrypt, configure Nginx or Apache to serve it on port 443, add a server-level redirect from HTTP, then update WordPress to use HTTPS in Settings → General and update any hardcoded URLs in the database.

Install Certbot and obtain a certificate on Ubuntu with Nginx:

sudo apt update
sudo apt install certbot python3-certbot-nginx

# Obtain and install the certificate (Certbot edits nginx.conf automatically)
sudo certbot --nginx -d example.com -d www.example.com

# Test auto-renewal
sudo certbot renew --dry-run

After the certificate is installed, update WordPress URLs in wp-config.php:

define( 'WP_HOME',    'https://example.com' );
define( 'WP_SITEURL', 'https://example.com' );

Add an HTTPS redirect in .htaccess (Apache) to force all traffic over SSL:

RewriteEngine On

# Redirect HTTP to HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

# Redirect www to non-www (optional)
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,R=301]

Or the Nginx equivalent:

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}

Update the database to replace http:// with https:// in all serialized and plain-text fields:

wp search-replace 'http://example.com' 'https://example.com' --skip-columns=guid

NOTE: After switching to HTTPS, check for mixed-content warnings in the browser DevTools — any resource (image, script, stylesheet) still loaded over http:// will trigger a warning and degrade your security score. The WP-CLI search-replace command handles serialized data correctly, which manual SQL REPLACE() does not.