Set up a free SSL certificate with Let’s Encrypt and Certbot on Ubuntu

HTTPS is no longer optional — browsers mark HTTP sites as “Not Secure”, Google uses HTTPS as a ranking signal, and many browser APIs including service workers and the Geolocation API require a secure context. Let’s Encrypt provides free, trusted SSL certificates that are valid for 90 days and can be renewed automatically. Certbot is the official Let’s Encrypt client that handles obtaining the certificate, proving domain ownership via the ACME protocol, and installing the certificate into your web server configuration. The domain validation (DV) certificates that Let’s Encrypt issues are identical in encryption strength to paid DV certificates — the difference is that Let’s Encrypt does not offer Organisation Validation (OV) or Extended Validation (EV) certificates. For a WordPress site on a VPS running Nginx or Apache on Ubuntu, the process is: install Certbot and the appropriate web server plugin, run certbot --nginx or certbot --apache, select your domain, and Certbot automatically obtains the certificate and rewrites your virtual host configuration to enable HTTPS and redirect HTTP to HTTPS. The certificate and private key are stored in /etc/letsencrypt/live/yourdomain.com/. Certbot installs a systemd timer (on Ubuntu 20.04+) or a cron job that runs certbot renew twice daily — the renewal only acts if the certificate is within 30 days of expiry. After enabling HTTPS, update the WordPress and site address URLs in Settings → General to use https://, and check the HTTP security headers guide to add HSTS and other headers. Test the certificate with SSL Labs at ssllabs.com/ssltest to ensure the grade is A or A+.

Problem: Your WordPress site runs on HTTP and you need to install a trusted SSL certificate and configure automatic renewal without paying for a commercial certificate.

Solution: Install Certbot, obtain a Let’s Encrypt certificate, and verify the automatic renewal timer:

# Install Certbot and the Nginx plugin (Ubuntu 20.04 / 22.04)
sudo apt update
sudo apt install certbot python3-certbot-nginx -y

# Obtain and install the certificate for your domain
# Certbot will edit your Nginx config automatically
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

# For Apache instead:
# sudo apt install python3-certbot-apache -y
# sudo certbot --apache -d yourdomain.com -d www.yourdomain.com

# Test renewal (dry run — does not change anything)
sudo certbot renew --dry-run

# Check the systemd timer that runs automatic renewal
sudo systemctl status certbot.timer
sudo systemctl list-timers --all | grep certbot

# View certificate expiry dates
sudo certbot certificates

# After obtaining the cert, update WordPress URLs in wp-config.php
# (or in Settings > General if the site already loads over HTTPS)
#
# define('WP_HOME',    'https://yourdomain.com');
# define('WP_SITEURL', 'https://yourdomain.com');

# /etc/nginx/sites-available/yourdomain.com
# Certbot adds the SSL block automatically — this is the resulting config

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

server {
    listen 443 ssl;
    server_name yourdomain.com www.yourdomain.com;

    ssl_certificate     /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    include             /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam         /etc/letsencrypt/ssl-dhparams.pem;

    # Add HSTS header (1 year)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    root  /var/www/html/wordpress;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

NOTE: Let’s Encrypt enforces a rate limit of 50 certificates per registered domain per week — use the --staging flag during testing to avoid hitting this limit: sudo certbot --nginx --staging -d yourdomain.com. After switching WordPress to HTTPS, run a search-and-replace to update any hardcoded http:// URLs in the database with the WP-CLI search-replace guide. Also update any hardcoded image or asset URLs in theme files and theme.json to use https:// to avoid mixed-content warnings.