DeveloperBootstrap

Security

Free SSL Certificate with Let's Encrypt - Complete Guide

Install and configure free SSL certificates using Let's Encrypt with automatic renewal and security headers.

What you'll learn

  • Install and configure Certbot for Let's Encrypt
  • Obtain SSL certificates for single and multiple domains
  • Set up automatic certificate renewal
  • Configure security headers and HSTS
  • Implement SSL best practices (TLS 1.3, OCSP stapling)
  • Troubleshoot common SSL issues

Install Certbot

Bash
1# Ubuntu 24.04 — install via snap (recommended)
2sudo snap install --classic certbot
3sudo ln -s /snap/bin/certbot /usr/bin/certbot
4
5# Verify
6certbot --version

Obtain Certificate

Bash
1# Nginx — auto-configures the web server
2sudo certbot --nginx -d example.com -d www.example.com
3
4# Apache
5sudo certbot --apache -d example.com -d www.example.com
6
7# Standalone (no web server running)
8sudo certbot certonly --standalone -d example.com
9
10# Wildcard (requires DNS challenge)
11sudo certbot certonly --manual --preferred-challenges dns   -d example.com -d "*.example.com"
12# Add the TXT record shown, then press Enter
13
14# Certificates stored in:
15# /etc/letsencrypt/live/example.com/fullchain.pem
16# /etc/letsencrypt/live/example.com/privkey.pem

Nginx Configuration

NGINX
1# /etc/nginx/sites-available/example.com
2server {
3    listen 80;
4    server_name example.com www.example.com;
5    return 301 https://$host$request_uri;
6}
7
8server {
9    listen 443 ssl;
10    http2 on;
11    server_name example.com www.example.com;
12
13    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
14    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
15    include /etc/letsencrypt/options-ssl-nginx.conf;
16    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
17
18    # TLS 1.3 only
19    ssl_protocols TLSv1.3;
20    ssl_prefer_server_ciphers off;
21
22    # OCSP Stapling
23    ssl_stapling on;
24    ssl_stapling_verify on;
25    resolver 8.8.8.8 8.8.4.4 valid=300s;
26
27    root /var/www/example.com;
28    index index.html;
29    location / { try_files $uri $uri/ /index.html; }
30}
31
32sudo nginx -t && sudo systemctl reload nginx

Automatic Renewal

Bash
1# Certbot installs a systemd timer automatically
2sudo systemctl status certbot.timer
3
4# Test renewal (dry run)
5sudo certbot renew --dry-run
6
7# Manual renewal if needed
8sudo certbot renew
9
10# After renewal, reload Nginx
11# /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
12#!/bin/bash
13systemctl reload nginx

Security Headers

NGINX
1# Add to Nginx server block (HTTPS only)
2add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
3add_header X-Frame-Options "DENY" always;
4add_header X-Content-Type-Options "nosniff" always;
5add_header Referrer-Policy "strict-origin-when-cross-origin" always;
6add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
7
8# Test your SSL configuration:
9# https://www.ssllabs.com/ssltest/
10# Target: A+ rating

Troubleshooting

  • Port 80 blocked: Check firewall — sudo ufw allow 80/tcp and sudo ufw allow 443/tcp.
  • Rate limit hit: Let's Encrypt limits 5 certificate failures per hostname per hour. Wait before retrying.
  • Certificate not trusted: Use fullchain.pem (includes intermediates), not just cert.pem.
  • Mixed content warnings: Update all HTTP asset URLs to HTTPS in your application.