Programming Beginner 8 min

How to Get a Free SSL Certificate with Let's Encrypt

Let's Encrypt issues free, browser-trusted TLS certificates that auto-renew every 90 days. Certbot — the official client — configures your Nginx server block in one command. There is no excuse for HTTP-only sites in 2024.

Step-by-step

  1. 1

    Verify DNS is propagated first

    Certbot will fail if your domain does not resolve to this server. Check before you run anything — it saves debugging time.

    bash
    # Should return your server's public IP
    dig +short example.com
    dig +short www.example.com
    
    # Or use a web tool
    curl https://dns.google/resolve?name=example.com&type=A | python3 -m json.tool
  2. 2

    Install Certbot and the Nginx plugin

    The python3-certbot-nginx plugin is what lets Certbot read and rewrite your Nginx config automatically. Install both in one shot.

    bash
    sudo apt update
    sudo apt install -y certbot python3-certbot-nginx
  3. 3

    Run Certbot for your domain

    This single command does everything: obtains the certificate, edits your Nginx config to use it, redirects HTTP to HTTPS, and tests the reload. Answer the interactive prompts (email for renewal alerts, ToS agreement).

    bash
    sudo certbot --nginx -d example.com -d www.example.com
  4. 4

    Understand what Certbot changed

    Certbot rewrites your server block. Inspect what it added — knowing the file layout helps when you need to tweak things later.

    bash
    cat /etc/nginx/sites-available/myapp.conf
    
    # You'll see Certbot added:
    # - listen 443 ssl;
    # - ssl_certificate / ssl_certificate_key paths under /etc/letsencrypt/live/
    # - A new server block on port 80 that redirects to https
    # - include /etc/letsencrypt/options-ssl-nginx.conf (modern TLS settings)
    # - ssl_dhparam path
  5. 5

    Test the auto-renewal timer

    Certbot installs a systemd timer (or cron job on older systems) that runs twice a day and renews any certificate expiring within 30 days. Test the dry run to confirm it will work.

    bash
    # Simulate renewal without actually renewing
    sudo certbot renew --dry-run
    
    # Check the timer status
    sudo systemctl status certbot.timer
    
    # List active timers
    sudo systemctl list-timers | grep certbot
  6. 6

    Verify the certificate in a browser and CLI

    Hit your site over HTTPS. The padlock should show. Use OpenSSL from the command line to check the certificate details and expiry date.

    bash
    # Should show the full certificate chain and "Verify return code: 0 (ok)"
    echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
      | openssl x509 -noout -subject -issuer -dates
    
    # Quick check: just expiry
    echo | openssl s_client -connect example.com:443 2>/dev/null \
      | openssl x509 -noout -enddate
  7. 7

    Troubleshoot common failures

    If Certbot fails, the error message is usually clear. The two most common causes:

    • Port 80 blocked — check your firewall: sudo ufw allow 80 and check your cloud provider's security group/firewall rules
    • DNS not propagated — use dig +short example.com @8.8.8.8 to query Google DNS directly; if it returns the wrong IP, wait and retry
    • Nginx not reloading cleanly — run sudo nginx -t first; Certbot can't reload a broken config
    bash
    # Open port 80 if blocked
    sudo ufw allow 80
    sudo ufw allow 443
    sudo ufw reload
    
    # Check Certbot logs for the exact error
    sudo cat /var/log/letsencrypt/letsencrypt.log | tail -50
  8. 8

    Force HTTPS and check redirects

    Certbot usually adds the HTTP→HTTPS redirect automatically. Confirm it with curl — you want a 301 redirect from port 80 to 443, not a 200 on both.

    bash
    # Should return 301 Moved Permanently with Location: https://
    curl -I http://example.com
    
    # Should return 200 OK
    curl -I https://example.com
    
    # Follow redirects automatically
    curl -IL http://example.com

Tips & gotchas

  • Add the <code>--staging</code> flag while testing to avoid Let's Encrypt rate limits (5 failed cert requests per domain per hour).
  • Let's Encrypt certificates are valid for 90 days. The auto-renewal timer runs twice daily and renews at ~60 days — you should never need to renew manually.
  • Wildcard certificates (<code>*.example.com</code>) require DNS-01 challenge (a TXT record), not HTTP-01. Use: <code>sudo certbot certonly --manual --preferred-challenges dns -d '*.example.com'</code>
  • If your server is behind a load balancer or CDN, the HTTP-01 challenge won't work (the request won't reach your server). Use DNS-01 instead or certbot's webroot plugin.
  • Run <code>sudo certbot certificates</code> to list all certificates on the machine and their expiry dates.

Wrapping up

Your site is now on HTTPS with a certificate that renews itself. Between this guide and the Nginx reverse proxy guide before it, you have a production-grade setup: Nginx terminating TLS, proxying to your app, auto-renewing certificates every 90 days. The next step is locking down your security headers — HSTS, CSP, and X-Frame-Options.

#SSL #HTTPS #Linux
Back to all guides

Need Help With Your Project?

Book a free 30-minute consultation to discuss your technical challenges and explore solutions together.