Do It Now: HTTPS for Your Domain in 5 Minutes
If you’re reading this because your browser just showed “Not Secure” on your website — don’t worry, it’s fixable in a few minutes. Let’s jump straight to the commands.
Install Certbot on Ubuntu/Debian:
sudo apt update
sudo apt install certbot python3-certbot-nginx -y
Issue a certificate for your domain (replace yourdomain.com with your actual domain):
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Certbot will ask for your email to send expiration warnings, then automatically update your Nginx config to enable HTTPS. That’s it. The browser padlock appears right away.
Verify that automatic renewal is running:
sudo certbot renew --dry-run
If you see Congratulations, all simulated renewals succeeded, you’re all set.
Why You Need SSL — and Why Let’s Encrypt Changes Everything
After auditing security on more than 10 servers, I kept seeing the same pattern: plain HTTP, no encryption. Data traveling across the network in plaintext — login forms, session cookies, even WordPress admin passwords. Anyone on the same network with Wireshark can capture it, whether at a coffee shop or an office running an unmanaged switch.
SSL/TLS encrypts all traffic between the browser and the server. Simple concept. The problem was that certificates used to cost $50–$200 per year with manual setup — enough friction that many people just skipped it entirely.
Let’s Encrypt blew that logic apart: free certificates, automated, trusted by every major browser. Certbot is the official tool — it handles everything from domain validation and certificate issuance to web server configuration and scheduled renewal. After the initial setup, you never have to touch it again.
Understanding How It Works (So You Can Debug When Things Break)
Certbot verifies that you actually own the domain using one of two methods:
HTTP-01 Challenge (Most Common)
Let’s Encrypt sends a request to http://yourdomain.com/.well-known/acme-challenge/<token>. Certbot creates that file on the server. If the file returns the correct content — validation is complete.
Port 80 must be open, and the domain must point to the correct server IP. This is the root cause of 90% of errors — either the firewall is blocking port 80, or DNS hasn’t finished propagating.
DNS-01 Challenge (When You Don’t Have a Web Server)
Instead of creating a file on the server, Certbot creates a TXT record in the domain’s DNS. This method is useful when the server isn’t exposed to the internet, or when you need a wildcard certificate (*.yourdomain.com).
# Issue a wildcard certificate via DNS challenge
sudo certbot certonly --manual --preferred-challenges dns \
-d "*.yourdomain.com" -d yourdomain.com
This command requires you to manually add a TXT record to your DNS before validation can proceed.
Common Real-World Scenarios
Server Running Apache Instead of Nginx
sudo apt install certbot python3-certbot-apache -y
sudo certbot --apache -d yourdomain.com
No Web Server (Standalone Mode)
If you’re running an app directly on port 80/443 — Node.js, Python Flask, Go — use standalone mode. Certbot temporarily takes over the port for validation, then releases it:
# Stop the service using port 80 first
sudo systemctl stop myapp
sudo certbot certonly --standalone -d yourdomain.com
sudo systemctl start myapp
Multiple Domains at Once
sudo certbot --nginx \
-d yourdomain.com \
-d www.yourdomain.com \
-d api.yourdomain.com \
-d admin.yourdomain.com
All domains are covered by a single certificate via Subject Alternative Names — more convenient than issuing separate certs for each one.
List Your Existing Certificates
sudo certbot certificates
The output shows the domain, expiration date, and path to the certificate files.
Automatic Renewal — Don’t Let It Slip Through the Cracks
Let’s Encrypt certificates expire after 90 days. That’s shorter than commercial certs (1–2 years) by design: Let’s Encrypt wants to force automation from the start, rather than issuing 2-year certs that people forget about until their site goes red.
Installing Certbot via apt automatically creates a systemd timer that checks for renewal twice a day. Check its status:
sudo systemctl status certbot.timer
# Or check the cronjob (if using cron instead of systemd)
cat /etc/cron.d/certbot
More importantly: after renewal, Nginx must be reloaded to pick up the new certificate. Check your deploy hook:
cat /etc/letsencrypt/renewal-hooks/deploy/
No hook yet? Add one now:
cat > /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh << 'EOF'
#!/bin/bash
systemctl reload nginx
EOF
chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
Practical Tips from Real Operational Experience
1. Inspect Certificates with openssl
# Check expiration date
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com \
< /dev/null 2>/dev/null | openssl x509 -noout -dates
# View full certificate details
openssl s_client -connect yourdomain.com:443 < /dev/null 2>/dev/null \
| openssl x509 -noout -text | grep -A 2 "Subject Alternative"
2. Fixing Common Errors
“Connection refused” or timeout when Certbot runs
→ Check your firewall: sudo ufw status and make sure port 80 is open.
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
“Too many certificates already issued for exact set of domains”
→ Let’s Encrypt limits you to 5 certificates per domain per week. Test with --staging first:
sudo certbot --nginx --staging -d yourdomain.com
Nginx still using the old certificate after renewal
→ Reload Nginx manually: sudo nginx -s reload. Then add a deploy hook as described above so it doesn’t happen again.
3. Back Up Your Certificates
Certificates live in /etc/letsencrypt/ — back up this directory before migrating your server:
sudo tar -czf letsencrypt-backup-$(date +%Y%m%d).tar.gz /etc/letsencrypt/
4. Revoke a Certificate When You No Longer Need It
sudo certbot revoke --cert-name yourdomain.com
sudo certbot delete --cert-name yourdomain.com
5. Automated Monitoring
This cron job emails you the renewal log every morning — handy for catching errors without having to manually log into the server:
# Add to crontab: check daily at 9 AM
0 9 * * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload nginx" 2>&1 | mail -s "Certbot renew log" [email protected]
Pair this with UptimeRobot or Uptime Kuma for external monitoring — you’ll know about certificate issues before users complain, not after.
