Let's Encrypt SSL with Certbot for Nginx: Full Guide

Run on the server with one command (check the script contents below first):

curl -sSL https://cp.lv/scripts/besplatnyj-ssl-lets-encrypt.sh | sudo bash

…or with wget:

wget -qO- https://cp.lv/scripts/besplatnyj-ssl-lets-encrypt.sh | sudo bash

Script contents besplatnyj-ssl-lets-encrypt.sh:

#!/usr/bin/env bash
# Issue a Let's Encrypt certificate for Nginx
set -e
export DEBIAN_FRONTEND=noninteractive

DOMAIN=example.com
[email protected]

# 1. Open ports 80 and 443
sudo ufw allow 'Nginx Full' || true

# 2. Install certbot with the Nginx plugin
sudo apt-get update
sudo apt-get install -y certbot python3-certbot-nginx

# 3. Issue the certificate and set up the HTTPS redirect (non-interactive)
sudo certbot --nginx -d ${DOMAIN} -d www.${DOMAIN} \
  --non-interactive --agree-tos -m ${EMAIL} --redirect

# 4. Check the Nginx config and automatic renewal
sudo nginx -t && sudo systemctl reload nginx
sudo certbot renew --dry-run

echo "Done: HTTPS is enabled for ${DOMAIN}, automatic renewal is configured."

Let’s Encrypt is a non-profit certificate authority that issues TLS certificates at no charge: the certificate itself costs nothing, and the certbot utility issues and renews it automatically. Here is how to enable HTTPS for an Nginx site in a few minutes.

What you need first

  • A domain whose A record points to your server IP.
  • A working Nginx server block with the correct server_name.
  • Open ports 80 and 443:
sudo ufw allow 'Nginx Full'

Port 80 is mandatory — Let’s Encrypt uses it to verify domain ownership (the HTTP-01 challenge).

If the server block does not exist yet, open the config in an editor (nano, vim or mcedit):

sudo nano /etc/nginx/sites-available/example.com

A minimal HTTP config for the domain validation (certbot will add the HTTPS part later):

server {
    listen 80;
    server_name example.com www.example.com;
    root /var/www/example.com;
    index index.html;
}

Or write the whole config with a single command — copy it and paste it into the console (the quotes around 'EOF' matter, so that Nginx $ variables are left alone):

sudo tee /etc/nginx/sites-available/example.com > /dev/null << 'EOF'
server {
    listen 80;
    server_name example.com www.example.com;
    root /var/www/example.com;
    index index.html;
}
EOF
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Step 1. Install certbot

The recommended way is snap — it always carries a current version:

sudo snap install core && sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

The apt alternative (if snap is unavailable):

sudo apt install certbot python3-certbot-nginx -y

Step 2. Issue the certificate

The Nginx plugin finds the right server block itself, issues the certificate and writes the HTTPS settings:

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

Certbot asks for an email (for expiry notices) and for agreement with the terms. When asked about the redirect, choose the option that redirects HTTP to HTTPS. After a successful issue, the certificate is stored in /etc/letsencrypt/live/example.com/.

Step 3. What certbot adds to the config

After the issue, these lines appear in the server block:

listen 443 ssl;
ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

Plus a separate block redirecting port 80 to HTTPS. Verify and reload:

sudo nginx -t
sudo systemctl reload nginx

Step 4. Check auto-renewal

Let’s Encrypt certificates are valid for 90 days. Certbot installs a systemd timer that renews them automatically. Check the timer and run a renewal rehearsal:

systemctl list-timers | grep certbot
sudo certbot renew --dry-run

If --dry-run finishes without errors, the real renewal will work too. Nothing has to be done by hand.

Step 5. Verify HTTPS

Open https://example.com — a padlock appears in the address bar. You can check the chain and the expiry date from the console:

echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates

Useful certbot commands

Task Command
List certificates sudo certbot certificates
Renew now sudo certbot renew
Revoke a certificate sudo certbot revoke --cert-name example.com
Add a domain sudo certbot --nginx -d example.com -d shop.example.com

FAQ

Is a Let’s Encrypt certificate really issued at no cost? Yes, the Let’s Encrypt authority issues and renews certificates without payment — that is its model. You only pay for the server the site runs on.

What do I do if certbot says “challenge failed”? Most often the domain A record does not point to the server yet, or port 80 is closed. Check DNS (dig example.com) and the firewall rules.

A 90-day certificate — do I have to renew it manually? No. Certbot installs a renewal timer. Verify it with certbot renew --dry-run and that is enough.

Can I issue a wildcard certificate (*.example.com)? Yes, but it requires the DNS-01 challenge and a plugin for your DNS provider, because the HTTP check does not work for subdomains.

HTTPS is mandatory for any site today: it affects both user trust and rankings. You can deploy a site with a certificate on the plans from the VPS hosting page, and for shops and CMSes there is WordPress VPS.

Kristaps Bērziņš