We may earn a referral fee at no additional cost to you when you shop through the links on this page.
Debian 12 (Bookworm), released June 2023, is a stable release with approximately five years of security support. This guide uses Certbot with the Nginx plugin to obtain and configure a free Let’s Encrypt SSL certificate, bringing encrypted HTTPS connections to your Nginx web server.
The following steps cover installing Certbot, obtaining a free Let’s Encrypt SSL certificate for your domain, configuring Nginx for HTTPS with automatic HTTP redirection, enabling HSTS security headers, and setting up automatic certificate renewal.
Prerequisites
Before you begin, ensure you have:
- A server running Debian 12 (Bookworm) with a non-root user that has
sudoprivileges. See our initial server setup guide for Debian 12 (Bookworm) if needed. - Nginx installed with a server block configured. Follow our How to Install Nginx on Debian 12 (Bookworm) guide first.
- A registered domain name with its DNS A record pointing to your server’s public IP address. Both
example.comandwww.example.comshould resolve to the server. Let’s Encrypt does not issue certificates for bare IP addresses. - Ports 80 and 443 open in your firewall. If you followed the Nginx guide and allowed
Nginx Fullin UFW, both ports are already open.
Installing Certbot
Certbot is the official Let’s Encrypt client that automates certificate issuance and Nginx configuration. Install it along with the Nginx plugin:
sudo apt update && sudo apt install -y certbot python3-certbot-nginx
Verify the installation:
certbot --version
You should see the Certbot version number in the output, confirming a successful installation.
Obtaining an SSL Certificate
Before requesting a certificate, verify that your domain resolves to your server’s IP address:
host example.com
The output should show your server’s public IP. If it doesn’t, update your DNS A record at your domain registrar and wait for propagation before continuing.
Run Certbot with the Nginx plugin to obtain and install your certificate. Replace example.com with your actual domain:
sudo certbot --nginx -d example.com -d www.example.com
www subdomain), omit the second -d flag. You can also secure multiple subdomains by adding additional -d flags (e.g., -d blog.example.com). Certbot will prompt you for the following:
- Email address — for certificate expiry notifications and account recovery. Enter a valid email.
- Terms of Service — you must agree (Y) to proceed.
- EFF mailing list — optional. Enter Y or N based on your preference.
If successful, you will see output confirming the certificate was issued and deployed:
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/example.com/privkey.pem
This certificate expires on 2026-05-20.
Deploying certificate
Successfully deployed certificate for example.com
Successfully deployed certificate for www.example.com
Congratulations! You have successfully enabled HTTPS on
https://example.com and https://www.example.com
- Obtained a trusted certificate from Let’s Encrypt via an HTTP-01 challenge
- Added
listen 443 ssland certificate paths to your Nginx server block - Configured HTTP-to-HTTPS redirection with a separate
serverblock on port 80 - Applied recommended TLS settings from
/etc/letsencrypt/options-ssl-nginx.conf - Reloaded Nginx to apply all changes
- Domain not resolving: Verify your DNS A record points to this server’s IP
- Port 80 blocked: Ensure
sudo ufw statusshowsNginx Fullallowed - No matching server block: Certbot needs an Nginx server block with a
server_namematching your domain - Nginx config error: Run
sudo nginx -tto check for syntax errors before retrying - Rate limit exceeded: Let’s Encrypt allows 5 duplicate certificates per domain per week. Wait and retry later.
Verifying HTTPS
Open your browser and visit https://example.com. You should see your site served over HTTPS with a padlock icon in the address bar.
From the command line, verify the HTTPS response headers:
curl -sI https://example.com
You should see HTTP/2 200 (or HTTP/1.1 200 OK) at the top of the response.
Next, verify that HTTP requests are automatically redirected to HTTPS:
curl -sI http://example.com
You should see a 301 Moved Permanently response with a Location header pointing to https://example.com/. This confirms that all HTTP traffic is being redirected to the secure HTTPS version.
Strengthening SSL Security
Certbot’s default configuration provides solid SSL security, including modern TLS protocols and cipher suites managed via /etc/letsencrypt/options-ssl-nginx.conf. To further protect your site, enable HTTP Strict Transport Security (HSTS), which instructs browsers to always use HTTPS even if a user types http:// in the address bar.
Open the Nginx server block that Certbot modified:
sudo nano /etc/nginx/sites-available/example.com
Find the server block that listens on port 443 (the one Certbot added the SSL directives to) and add the HSTS header inside it:
server {
listen 443 ssl; # managed by Certbot
server_name example.com www.example.com;
root /var/www/example.com;
# HSTS — force browsers to use HTTPS for one year
add_header Strict-Transport-Security "max-age=31536000" always;
# ... rest of your configuration ...
}
Save and exit (press CTRL + X, press Y, then press ENTER)
Test the configuration and reload Nginx:
sudo nginx -t && sudo systemctl reload nginx
Verify the HSTS header is present:
curl -sI https://example.com | grep -i strict
You should see:
strict-transport-security: max-age=31536000
max-age=31536000 value tells browsers to remember the HTTPS-only policy for one year (31,536,000 seconds). Once your site is stable on HTTPS, you can optionally add includeSubDomains and submit your domain to the HSTS preload list for browser-level enforcement. Only do this when you are certain all subdomains support HTTPS. Automatic Certificate Renewal
Let’s Encrypt certificates are valid for 90 days. Certbot installs a systemd timer that automatically checks for renewal twice daily and renews any certificate within 30 days of expiry.
Verify the renewal timer is active:
sudo systemctl status certbot.timer
You should see active (waiting) in the output, along with the next scheduled run time.
Test the renewal process with a dry run (simulates renewal without making any changes):
sudo certbot renew --dry-run
If the dry run completes without errors, automatic renewal is working correctly. You should see Congratulations, all simulated renewals succeeded in the output.
Important File Locations
Key paths for managing SSL certificates on Debian 12 (Bookworm):
- Certificate (full chain):
/etc/letsencrypt/live/example.com/fullchain.pem— The complete certificate chain sent to browsers. - Private Key:
/etc/letsencrypt/live/example.com/privkey.pem— Your certificate’s private key. Keep this secure. - Nginx Server Block:
/etc/nginx/sites-available/example.com— Your site configuration with Certbot’s SSL additions. - Renewal Configuration:
/etc/letsencrypt/renewal/example.com.conf— Settings used for automatic renewal. - SSL Options:
/etc/letsencrypt/options-ssl-nginx.conf— Certbot-maintained TLS protocol and cipher settings. - Certbot Log:
/var/log/letsencrypt/letsencrypt.log— Detailed log for troubleshooting certificate operations.
Conclusion
Your Debian 12 (Bookworm) server is now secured with a free Let’s Encrypt SSL certificate, automatic HTTP-to-HTTPS redirection, HSTS security headers, and automated 90-day certificate renewal.
With SSL in place, your LEMP stack is production-ready. Your site benefits from encrypted connections, improved search engine rankings, and browser trust indicators. Consider deploying your application (WordPress, Laravel, or another PHP framework) or exploring advanced configurations such as HTTP/2, OCSP stapling, and Content Security Policy headers.
Comments