Let's Encrypt on Ubuntu + Nginx Tutorial
Install, configure, and auto‑renew free SSL certificates to save costs on SSL infrastructure
I recently totally turned from commercially issued SSL certificates for different projects and switched completely to Let’s Encrypt way of handling SSL certificates for domains.
In this article I would like to share playbook how to install, configure and set up a process for auto-renewal (it’s actual because normal Let’s Encrypt certificate lifetime is 90 days).
But we jump deep in practical manual parts, let’s just do a quick refresher what is SSL and what is Let’s Encrypt.
What is SSL an why it’s important?
When people say SSL, they usually mean TLS (Transport Layer Security). It’s the technology that makes the connection between your browser and a server encrypted and verified. In practice, that means:
The server proves it’s really the site you wanted to reach (using a certificate and private key).
The browser checks that certificate against a trusted authority (Certificate Authority).
Once trust is established, all traffic is scrambled with encryption so nobody in between can read or change it.
So passwords, forms, payments, API calls — everything stays safe from eavesdropping or tampering. In 2025, you can’t run a serious site without it: browsers warn users, Google ranks HTTPS sites higher, and security compliance flat-out requires it.
What is Let’s Encrypt and why it’s free
Let’s Encrypt is a Certificate Authority (CA) — the trusted third party that hands out SSL/TLS certificates. Normally, companies like RapidSSL or DigiCert sell you a certificate for money every year. Let’s Encrypt flipped the model: it’s a non-profit, backed by Mozilla, EFF, and others, that gives certificates away for free.
Why? Because encrypted web traffic should be the default, not a luxury. Their funding comes from sponsors and donations, not from charging website owners.
And the really cool part here is automation: instead of filling out forms, emailing back and forth, and paying invoices, you run a simple tool (certbot), and within seconds your server gets a valid certificate. It also renews automatically, so you don’t wake up one morning with a broken “expired cert” warning.
Personally, dealing with SSL certificates was always a headache. You had to contact the client, explain what you needed, ask for credentials to log in to the issuer’s site and fill out forms. Or sometimes you’d just wait for the client to send you the freshly issued certificate — often in some unexpected format, and almost always with a file or two missing. Sounds familiar, doesn’t it?
So Let’s Encrypt not only save costs for you and for your clients, but also make the process of handling the certificates drastically simpler. And in the guide below, you’ll see how effortless it really is.
Let’s Encrypt installation and configuration guide
Below is the step-by-step instruction how to install and configure Let’s Encrypt certificates on your Ubuntu + Nginx server (probably the most common combination of server setup).
In this example let’s charge a certificate for domain labrodev.com.
Install Certbot and the Nginx plugin
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
Make sure Nginx has a matching server block
Certbot’s Nginx plugin needs to find your vhost by server_name. Minimal HTTP block:
# /etc/nginx/sites-available/labrodev.com
server {
listen 80;
listen [::]:80;
server_name labrodev.com www.labrodev.com;
root /var/www/labrodev; # your path
index index.html index.htm index.php;
}
Before issuing a new certificate for your domain, make sure you have an Nginx config in sites-available (and symlinked in sites-enabled) with a server_name that exactly matches the domain you’re requesting the certificate for.
If it’s not enabled yet (no symlink in sites-enabled), enable it before moving for next step:
sudo ln -s /etc/nginx/sites-available/labrodev.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Issue certificate
sudo certbot --nginx -d labrodev.com -d www.labrodev.com
What happens here:
Certbot serves an HTTP‑01 challenge via Nginx.
On success, it writes certs under /etc/letsencrypt/live/labrodev.com/.
It modifies your Nginx server block to add ssl_certificate and ssl_certificate_key, and (if you accept) an HTTP→HTTPS redirect.
So after the certificate is issued, your vhost for this domain with such server name will have automatically added record for ssl_certificate and ssl_certificate_key:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name labrodev.com www.labrodev.com;
ssl_certificate /etc/letsencrypt/live/labrodev.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/labrodev.com/privkey.pem;
root /var/www/labrodev;
index index.html index.htm index.php;
}
Configure auto-renewal process
Let’s verify the systemd timer exists.
Certbot (APT) installs a timer that runs renew checks twice daily:
systemctl list-timers | grep certbot
systemctl status certbot.timer
Dry‑run renewal
This command will simulate renewal (with —dry-run option) of certificates:
sudo certbot renew --dry-run
You should see something like “Congratulations, all simulated renewals succeeded!” message.
Reload Nginx automatically after real renewals
Create a post‑renew hook that syntax‑checks and reloads Nginx only when certs actually renew:
sudo tee /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh >/dev/null <<'EOF'
#!/bin/bash
# Only runs after a successful *real* renewal event.
# Validate config before reloading to avoid downtime.
if /usr/sbin/nginx -t; then
systemctl reload nginx
fi
EOF
sudo chmod +x /etc/letsencrypt/renewal-hooks/post/reload-nginx.sh
Simulate the end-to-end flow
I like to confirm the entire chain (renew → nginx test → reload) in one go:
sudo certbot renew --dry-run && sudo nginx -t && sudo systemctl reload nginx
Dry‑run won’t actually change certs, but you’ll see the path is healthy and your reload command works.
Double check the setup
There are some proof commands that feel you secure about whole setup and which you actually can use from time to time to check the state of certificates. Below there are some of these useful commands.
When does auto‑renew run next / when did it last run?
systemctl list-timers | grep certbot
systemctl status certbot.timer
journalctl -u certbot --since "3 days ago"
What version am I running / which binary?
certbot --version
which certbot
List all installed certificates and their expiry
sudo certbot certificates
Check the expiry of a specific PEM
sudo openssl x509 -enddate -noout -in /etc/letsencrypt/live/labrodev.com/fullchain.pem
# notAfter=Nov 17 11:05:44 2025 GMT
What about wildcard certificates?
A wildcard certificate is one that covers all subdomains under a given domain. For example, a cert for *.labrodev.com would automatically secure dev.labrodev.com, test.labrodev.com, api.labrodev.com, and so on — without you needing to issue separate certs for each one. This is handy if your product spins up subdomains dynamically (e.g. customer1.yourapp.com, customer2.yourapp.com), since managing dozens or hundreds of individual certificates would be a nightmare.
Let’s Encrypt can issue wildcard certificates, but there’s a catch: you need to prove ownership via DNS-01 validation (adding TXT records in your DNS). That adds complexity, because it means touching DNS settings rather than just letting Certbot hook into Nginx.
Personally, my approach is simpler: I just treat each subdomain I use as a separate domain with its own Nginx vhost and Let’s Encrypt certificate. So labrodev.com, dev.labrodev.com, and test.labrodev.com each have their own config and their own cert. It works perfectly fine if you only have a handful of subdomains.
Of course, if your platform generates subdomains on the fly dynamically, that’s when a wildcard makes sense — but that’s a bigger topic for another day and not for this article.
Conclusion
So nearly in ~10 minutes you can:
Install Let’s Encrypt on Ubuntu,
Issue trusted certs via the Nginx plugin,
Enable hands‑off auto‑renewal,
And wire a post‑renew hook so Nginx picks up fresh certs automatically.
Short‑lived certs + automated renewals are exactly how SSL should work in 2025: secure by default, zero manual babysitting, and no licensing friction. It’s simple, robust, and free.
I hope you enjoy this article!
Have a luck with this and keep your domains secure!
If you like it or find useful, you may share it with your audience.
If you like Labro:Dev blog and topics we cover here, we will glad to see your in our subscribers list. Let’s connect!
Preview image credit: https://unsplash.com/@franckinjapan