Back to tutorials
Tutorial

Let’s Encrypt setup guide tutorial (2026): Automatic SSL for Nginx & Apache on an Ubuntu VPS

Let’s Encrypt setup guide tutorial for Ubuntu VPS: install Certbot, issue SSL for Nginx/Apache, auto-renew, and fix common failures.

By Anurag Singh
Updated on Jul 25, 2026
Category: Tutorial
Share article
Let’s Encrypt setup guide tutorial (2026): Automatic SSL for Nginx & Apache on an Ubuntu VPS

Most SSL outages don’t come from “bad certificates.” They come from two predictable mistakes: issuing a cert for the wrong hostname, or letting renewal fail quietly.

This Let’s Encrypt setup guide tutorial shows a clean, repeatable way to set up SSL on an Ubuntu VPS with Nginx or Apache. It also makes renewal boring, so you’re not scrambling on day 90.

You’ll install Certbot, confirm DNS and firewall basics, apply a modern TLS baseline, and run a renewal dry-run you can trust.

This guide fits real hosting setups: a single site, multi-domain VPS deployments, and small agency servers.

What you’ll build (and what you need before you start)

By the end, your server will:

  • Serve HTTPS for one or more hostnames (Apex + www, or multiple domains).
  • Redirect HTTP → HTTPS safely (no redirect loops).
  • Renew certificates automatically with systemd timers.
  • Run a “dry-run” renewal check you can monitor.

Prerequisites:

  • An Ubuntu VPS (Ubuntu 24.04 LTS or newer is ideal) with root or sudo access.
  • A domain pointing to your VPS IP (A/AAAA records correct).
  • Ports 80 and 443 open to the internet (at least during issuance/renewal).

If you’re still choosing where to run this, a HostMyCode VPS is a solid fit for HTTPS, email, and multi-site hosting.

If you’d rather have patching and security maintenance handled alongside you, use managed VPS hosting instead.

Step 1: Confirm DNS points to the correct server

Let’s Encrypt only issues a certificate after it verifies you control the domain.

Start by confirming each hostname resolves to your VPS IP.

Check the apex domain and any additional names you plan to include (like www).

domain=example.com

# Check A/AAAA
dig +short A $domain
dig +short AAAA $domain

# Check both apex and www if you plan to cover them
dig +short A www.$domain

Expected: The returned IP(s) match your server.

If they don’t, fix DNS at your registrar or DNS provider before you touch Certbot. For domain registration and straightforward DNS management, you can use HostMyCode Domains.

TTL tip for production cutovers: If you’re moving an existing site, drop the TTL a few hours ahead of time (for example, 300 seconds).

Keep the old record handy so rollback takes seconds, not guesses.

Step 2: Open the right ports without weakening the server

HTTP-01 validation needs inbound access to port 80. HTTPS traffic needs port 443.

If you use UFW, allow both explicitly:

sudo ufw status
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

If you’re locking down a new VPS, don’t guess at firewall rules.

Follow our UFW firewall setup tutorial first. Then come back here.

Step 3: Install Certbot the right way on Ubuntu (no mystery builds)

On Ubuntu, the safest route is the packaged Certbot plus the plugin for your web server.

Update APT, then install the packages for your stack.

sudo apt update

# For Nginx
sudo apt install -y certbot python3-certbot-nginx

# For Apache (use this instead if you run Apache)
# sudo apt install -y certbot python3-certbot-apache

Confirm what you installed:

certbot --version

In 2026, plenty of older guides still copy/paste deprecated flags. Don’t.

Follow the current CLI output and use the plugin that matches your web server.

Step 4 (Nginx): Issue and install the certificate in one pass

Before you request a certificate, confirm Nginx is running.

Also confirm it serves the domain over plain HTTP.

sudo systemctl status nginx --no-pager
curl -I http://example.com

If you can’t connect, stop and fix Nginx or your firewall rules first.

Certbot can’t validate what the internet can’t reach.

Now issue the certificate and let Certbot update your server block:

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

During the prompts:

  • Use a real email address. It’s your last line of warning if renewal breaks.
  • Choose the redirect option (HTTP → HTTPS) unless you deliberately need HTTP.

Where files land:

  • Certificates: /etc/letsencrypt/live/example.com/
  • Renewal configs: /etc/letsencrypt/renewal/

Reload Nginx, then verify what’s being served:

sudo nginx -t
sudo systemctl reload nginx

# Confirm the certificate chain and hostname match
echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -subject -issuer -dates

Step 4 (Apache): Issue and install the certificate with the Apache plugin

On Apache, the flow is the same.

First confirm it’s listening on port 80 and serving the right virtual host.

sudo systemctl status apache2 --no-pager
curl -I http://example.com

Then issue the certificate and let Certbot update your vhost config:

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

Reload and confirm Apache is happy with the config:

sudo apachectl configtest
sudo systemctl reload apache2

Step 5: Fix the two most common causes of failed issuance

Most issuance failures come from the same few problems.

Run through this list before you retry Certbot.

  • DNS points elsewhere: dig +short A example.com doesn’t match your VPS.
  • Port 80 blocked: firewall, security group, or upstream provider rule blocks inbound HTTP.
  • Wrong virtual host / server block: the domain serves a default site, not your vhost.
  • Redirect loop: a global HTTP→HTTPS redirect exists before the challenge location is reachable.

If you suspect a redirect loop or vhost confusion, back off aggressive redirects temporarily. Then retry Certbot.

On Nginx, dump the active config and search for your domain:

sudo nginx -T | sed -n '1,200p'

Find the block with server_name example.com www.example.com;.

Confirm it listens on 80. Also confirm it doesn’t force HTTPS before the ACME challenge can be served.

Step 6: Set a modern TLS baseline (without breaking clients)

Certbot gets you HTTPS. It doesn’t guarantee sensible TLS defaults.

Keep the baseline simple: TLS 1.2/1.3, no odd cipher tuning, and a few safe headers.

On Nginx, Certbot may generate snippets for you. You can also maintain a small baseline include.

Create /etc/nginx/snippets/ssl-params.conf:

sudo nano /etc/nginx/snippets/ssl-params.conf
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;

# OCSP stapling helps latency and improves some client checks
ssl_stapling on;
ssl_stapling_verify on;

resolver 1.1.1.1 1.0.0.1 8.8.8.8 valid=300s;
resolver_timeout 5s;

# Basic hardening headers (adjust per app)
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options SAMEORIGIN always;
add_header Referrer-Policy strict-origin-when-cross-origin always;

Then include it in your HTTPS server block:

include /etc/nginx/snippets/ssl-params.conf;

If you want a deeper header set that stays compatible with common apps (including WordPress), follow our Nginx security headers configuration tutorial.

Step 7: Make renewal boring (systemd timer + a real test)

On Ubuntu, Certbot usually installs a systemd timer that runs twice per day.

Verify the timer exists and is active:

systemctl list-timers | grep -E 'certbot|letsencrypt'
systemctl status certbot.timer --no-pager

Next, run a dry-run renewal. This is the fastest way to prove renewals will work later.

sudo certbot renew --dry-run

What “success” looks like: Certbot completes the challenge and reports no errors.

If it fails, treat it like an incident you can fix in daylight.

The failures that happen quietly at 2 a.m. are the ones that turn into tickets.

If you want a focused playbook for the issues you’ll actually run into (blocked HTTP-01, broken chain, wrong webroot, stale DNS), keep this internal guide close: TLS certificate renewal troubleshooting tutorial.

Step 8: Multi-site VPS? Issue separate certs cleanly

On a multi-site VPS, resist the urge to bundle unrelated domains into one certificate.

It makes troubleshooting harder. It also increases the blast radius of a single bad vhost change.

Issue one certificate per site:

# Site 1
sudo certbot --nginx -d site-one.com -d www.site-one.com

# Site 2
sudo certbot --nginx -d site-two.com -d www.site-two.com

See what Certbot is managing:

sudo certbot certificates

Pitfall: If two server blocks both declare the same server_name, Certbot may edit the wrong file.

Remove duplicates, reload Nginx, then re-run Certbot.

Step 9: If you can’t expose port 80, use DNS validation (manual, but workable)

Some environments keep port 80 closed. Others route HTTP somewhere other than your origin.

In either case, HTTP-01 won’t validate.

DNS-01 works without opening ports. It’s often manual unless your DNS provider supports API automation.

Provider plugins vary, so here’s the universal manual approach:

sudo certbot certonly --manual --preferred-challenges dns -d example.com -d www.example.com

Certbot will ask you to create a TXT record like this:

_acme-challenge.example.com  TXT  "random-token"

After you add it, confirm it has propagated:

dig +short TXT _acme-challenge.example.com

Reality check: Manual DNS validation won’t auto-renew unless you repeat the process each time.

If you need hands-off renewal, keep port 80 reachable for the origin or use a DNS provider with supported automation.

Step 10: Quick checklist for SSL troubleshooting on a VPS

When a browser throws a certificate warning, work the basics in order.

Don’t guess.

  1. Confirm the hostname: Is the user visiting www but you only issued example.com?
  2. Confirm the serving IP: Is DNS pointing at the right VPS, or an old shared hosting box?
  3. Check the active certificate:
    echo | openssl s_client -servername example.com -connect example.com:443 2>/dev/null | openssl x509 -noout -subject -issuer -dates
  4. Check the web server config test:
    • Nginx: sudo nginx -t
    • Apache: sudo apachectl configtest
  5. Check renewal logs: /var/log/letsencrypt/letsencrypt.log

If you run cPanel and need to troubleshoot AutoSSL (which fails differently than Certbot), bookmark our cPanel-specific guide: cPanel AutoSSL troubleshooting tutorial.

Step 11: Operational hardening that pays off (small changes, fewer incidents)

A handful of habits will cut SSL-related tickets fast:

  • Put SSL expiry into monitoring: alert if a cert has less than 14 days remaining.
  • Log your renewal attempts: dry-run monthly via cron/systemd and alert on non-zero exit.
  • Keep HTTP-01 path reachable: don’t blanket-block /.well-known/ unless you know why.
  • Document where certs live: note /etc/letsencrypt/live/ and the vhost paths for each site.

For a practical monitoring baseline (uptime, resource alerts, and log checks), see our server monitoring tutorial.

Summary: a repeatable SSL setup you can trust

On a VPS, HTTPS should behave the same way every time.

Confirm DNS first. Keep ports 80/443 reachable (or choose DNS validation on purpose).

Install Certbot with the right plugin and treat renewal as part of the deployment.

Once --dry-run renewals pass, SSL stops being a quarterly fire drill.

If you want a stable platform for multiple domains, renewals, and routine maintenance, start with a HostMyCode VPS.

If you’d rather offload updates, hardening, and recovery planning, managed VPS hosting keeps the ops load lighter while you keep control of your apps.

If you deploy SSL across several client sites, infrastructure quality shows up fast: disk performance, network consistency, and clean admin access matter. HostMyCode offers VPS plans for single sites through multi-tenant stacks, plus managed VPS hosting if you want help with updates, hardening, and recovery planning.

FAQ

Do I need both example.com and www.example.com on the certificate?

If users can reach both hostnames, yes. Add both -d example.com -d www.example.com. Then redirect one to the other so you don’t serve the same site from two URLs.

How do I confirm auto-renewal is actually running?

Check systemctl status certbot.timer and run sudo certbot renew --dry-run.

Also review /var/log/letsencrypt/letsencrypt.log to confirm recent renewal attempts.

Why does Let’s Encrypt fail even though my site loads?

Your browser can load the site over HTTPS while HTTP-01 validation still fails.

The usual culprits are a blocked port 80, a redirect loop, or DNS still pointing at an older server.

Should I use Certbot or cPanel AutoSSL?

If you run cPanel/WHM, AutoSSL is usually simpler because it integrates with accounts and vhosts.

On a plain Nginx/Apache VPS, Certbot is the cleaner default.

Where are the certificate files stored on Ubuntu?

Look under /etc/letsencrypt/live/your-domain/. That directory contains symlinks to the current full chain and private key used by your web server.