Nginx and a free Let's Encrypt certificate with certbot
Nginx is the fastest and most common web server and reverse proxy on Linux. In this tutorial you install Nginx, create a server block for your domain, and get a free Let's Encrypt SSL certificate with certbot that renews itself automatically.
Prerequisites
- A cloud server or VPS with Ubuntu 24.04 (or 22.04) and a sudo user (first SSH login and hardening)
- A domain, for example
example.com, with an A record pointing to the server's IPv4 (and, if the server has IPv6, an AAAA record pointing to its IPv6). Create records forwwwtoo. - Ports 80 and 443 open in the cloud firewall and ufw
Replace example.com with your domain in every command.
1. Install Nginx
sudo apt update
sudo apt install -y nginx
sudo ufw allow 'Nginx Full'
curl -I http://SERVER_IP should return HTTP/1.1 200 OK and Server: nginx.
2. Create the site folder
sudo mkdir -p /var/www/example.com/html
echo '<h1>example.com works</h1>' | sudo tee /var/www/example.com/html/index.html
sudo chown -R www-data:www-data /var/www/example.com
3. Create a server block
sudo tee /etc/nginx/sites-available/example.com > /dev/null <<'EOF'
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
EOF
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
nginx -t must print syntax is ok and test is successful.
4. Check DNS
Before requesting a certificate, make sure the domain reaches this server:
dig +short example.com A
dig +short example.com AAAA
curl -s http://example.com
If you have an AAAA record that points elsewhere (or the server has no IPv6), Let's Encrypt may try over IPv6 and fail. Remove the wrong AAAA record.
5. Get the certificate with certbot
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com \
--redirect --agree-tos -m you@example.com
certbot proves domain ownership with the HTTP-01 method, stores the certificate in /etc/letsencrypt/live/example.com/, updates the server block for port 443 and, with --redirect, sends every HTTP request to HTTPS. The email is for important Let's Encrypt notices.
6. Automatic renewal
Let's Encrypt certificates are valid for 90 days. The certbot package installs a systemd timer that renews certificates close to expiry twice a day:
systemctl list-timers | grep certbot
sudo certbot renew --dry-run
If --dry-run finishes without errors, automatic renewal works.
Final check
curl -I http://example.com # 301 to https://example.com/
curl -I https://example.com # HTTP/1.1 200 OK
sudo certbot certificates # domains and expiry date
Common errors
| Error | Fix |
|---|---|
Timeout during connect (likely firewall problem) | Port 80 is closed from the internet. Check the cloud firewall and sudo ufw status. |
DNS problem: NXDOMAIN or wrong IP | The A record is not created or not propagated yet. Wait a few minutes and check again with dig. |
too many certificates already issued | You hit Let's Encrypt's duplicate certificate limit (5 certificates for the same set of names in 7 days). Use --staging for testing. |
nginx: [emerg] ... conflicting server name | The same server_name is in two files. Check /etc/nginx/sites-enabled/. |
502 Bad Gateway after adding a proxy | The application behind Nginx is not running or uses another port: sudo ss -tlnp. |
Nginx as a reverse proxy
If your application (for example a Docker container) listens on 127.0.0.1:8080, write location / like this, then run nginx -t and reload again:
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Next steps
- Install WordPress on a VPS with LEMP
- Arianet cloud load balancer in front of two web servers
- Reverse DNS for your server IP in the cloud panel guide
Create your server
Create an Arianet cloud server with public IPv4 and IPv6 and have your site on HTTPS in minutes. In the Arianet panel, start from Cloud server / Cloud Computing → New server; billing is hourly.