# Free SSL with Let's Encrypt on a VPS: the complete 2026 guide

> How to get free SSL from Let's Encrypt on an Ubuntu or Debian VPS with Certbot or a panel: wildcards, auto-renewal, rate limits and fixes for common errors.

Source: https://zopanel.net/blog/free-ssl-lets-encrypt  
Updated: 2026-10-09

## Key takeaways

- Let's Encrypt issues free SSL certificates that currently last 90 days and must be renewed automatically.
- HTTP-01 validation only uses port 80; wildcard certificates require DNS validation.
- From 10 February 2027 default certificates last 64 days, and from 16 February 2028 just 45 days.
- Let's Encrypt stopped sending expiry reminder emails on 4 June 2025, so you need your own monitoring.

To get free SSL from Let's Encrypt on a VPS you need three things: a domain that points to the server's IP, port 80 open to the internet, and an ACME client such as Certbot to request and renew the certificate. On Ubuntu with nginx that means installing Certbot and running `sudo certbot --nginx`; with a control panel such as ZoPanel, the certificate is issued and renewed automatically when you create the website.

This guide covers both routes, explains how Let's Encrypt validates your domain, how to get a wildcard certificate, which rate limits to know, the important certificate lifetime changes coming in 2027 and 2028, and how to fix the errors that make issuance fail.

## How does Let's Encrypt work?

Let's Encrypt is a free, automated certificate authority (CA). Certificates are issued over the ACME protocol: a client on your server proves you control the domain, and Let's Encrypt issues a certificate that every major browser trusts.

There are two common ways to prove control, described in [Let's Encrypt's challenge types documentation](https://letsencrypt.org/docs/challenge-types/):

| Challenge | How it works | Pros | Cons |
| --- | --- | --- | --- |
| HTTP-01 | Serve a file at `http://domain/.well-known/acme-challenge/` | Simple, no DNS access needed | Port 80 only; no wildcards |
| DNS-01 | Create a `_acme-challenge` TXT record | Wildcards (`*.example.com`), no port 80 needed | Needs DNS API or control of the zone |

For ordinary websites HTTP-01 is all you need. Use DNS-01 only when you need a wildcard.

## Before you install free SSL from Let's Encrypt

1. **The domain points to the right IP.** Check:

```bash
dig +short example.com A
dig +short www.example.com A
dig +short example.com AAAA
```

If the domain has an **AAAA** (IPv6) record pointing somewhere else, validation can fail, because Let's Encrypt will try to connect over IPv6. Remove the wrong AAAA record or point it at the VPS's IPv6 address.

2. **Port 80 is open**, in UFW and in your provider's cloud firewall:

```bash
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
```

3. **nginx has a server block** with `server_name example.com www.example.com;` for the site.

If the domain is not pointed yet, see [how to point a domain to a VPS](/blog/point-domain-to-vps).

## Option 1: Install Let's Encrypt SSL by hand with Certbot

### Install Certbot

Certbot is the ACME client from the EFF. The [official Certbot instructions](https://certbot.eff.org/instructions?ws=nginx&os=snap) recommend the snap:

```bash
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot
```

On Debian 12 (no snap by default), or if you prefer apt packages, use the distribution's package:

```bash
sudo apt install certbot python3-certbot-nginx
```

Pick one method, not both.

### Get a certificate for nginx

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

Certbot asks for an email address and agreement to the terms, validates the domain over HTTP-01, then edits the nginx configuration to use the certificate and, if you choose, redirect HTTP to HTTPS. Files live in `/etc/letsencrypt/live/example.com/`.

To edit nginx yourself, run `sudo certbot certonly --nginx -d example.com` and add the `fullchain.pem` and `privkey.pem` paths to the server block.

### Check automatic renewal

Both the snap and the apt package install a systemd timer for renewal. Check it:

```bash
systemctl list-timers | grep -i certbot
sudo certbot renew --dry-run
```

If the dry run succeeds, renewal is automated.

### Wildcard certificates

Wildcards need DNS-01. `certbot certonly --manual --preferred-challenges dns` works, but it **does not renew by itself**: you would have to create a new TXT record by hand each time. In practice, use the Certbot DNS plugin for your DNS provider (Cloudflare, Route 53 and others) so Certbot creates the record through the provider's API.

## Option 2: Free SSL on autopilot with ZoPanel

Once you manage more than a handful of sites, doing this per domain gets tedious. In ZoPanel, Let's Encrypt is the default ([SSL docs](/docs/ssl)):

1. Set the **Administrator email** in **Settings** (Let's Encrypt registration needs it).
2. Create the site under **Websites → New website** with **Free SSL (Let's Encrypt)** on.
3. If the domain already points to the server, the certificate is issued straight away. If not, the site works over HTTP and ZoPanel re-checks DNS **every hour**; once the domain resolves to the server, the certificate is issued. After a failure, the next attempt waits 2, 4, 8 hours and so on, up to a day, so rate limits are never wasted.
4. On the website's **SSL** tab, turn on **Redirect HTTP to HTTPS**. ZoPanel also sends a one-year HSTS header, so only turn it on when you intend to keep HTTPS.

What ZoPanel adds:

- **Renewal:** hourly checks, renewal when fewer than 30 days remain, and retries after 1, 2, 4, then 8 days if renewal fails.
- **Alerts:** **SSL renewal failed** with the exact error goes to the administrator and the site owner, and **SSL expiring soon** is sent daily once a certificate has fewer than 14 days left.
- **Wildcards:** install the DNS server, create the domain's zone ([DNS](/docs/dns)) and tick **Also \*.example.com (wildcard)** on the **SSL** tab. ZoPanel validates over DNS and renews automatically.
- **Bought certificates:** paste the PEM certificate and key into **Custom certificate**; ZoPanel checks that the key matches, the domain is right and it has not expired.
- **Aliases that do not resolve yet** are left out so they cannot fail the whole order, and are added on the next issue.

## What is changing: shorter certificates and no reminder emails

Two changes make automation non-negotiable:

**Let's Encrypt stopped sending expiry reminder emails on 4 June 2025** ([announcement](https://letsencrypt.org/2025/01/22/ending-expiration-emails/)). If you relied on those emails to notice a failed renewal, you now need your own monitoring.

**Certificate lifetimes are shrinking.** According to [Let's Encrypt's plan](https://letsencrypt.org/2025/12/02/from-90-to-45/):

| Date | Change to the default profile |
| --- | --- |
| Today | 90-day certificates |
| 10 February 2027 | 64-day certificates; validation reuse drops to 10 days |
| 16 February 2028 | 45-day certificates; validation reuse drops to 7 hours |

Let's Encrypt recommends ACME Renewal Information (ARI) where your client supports it, or renewing about two-thirds of the way through a certificate's life. A fixed "renew every 60 days" cron job will stop working. Make sure your client schedules renewals from the real expiry date.

## Let's Encrypt rate limits

From the [rate limits page](https://letsencrypt.org/docs/rate-limits/):

| Limit | Value |
| --- | --- |
| New certificates per registered domain | 50 per 7 days |
| Duplicate certificates (identical set of names) | 5 per 7 days |
| Failed validations per name, per account | 5 per hour |
| New orders per account | 300 per 3 hours |

The usual way to hit a limit is re-running the command while DNS is still wrong and running into the 5-failures-per-hour limit. When experimenting, use `--dry-run` or the staging environment (`--test-cert`).

## Common SSL errors and how to fix them

| Symptom | Usual cause | Fix |
| --- | --- | --- |
| `Timeout during connect` | Port 80 blocked in UFW or the cloud firewall | Open port 80 in both |
| `NXDOMAIN` or wrong IP | Domain not pointed yet, DNS not propagated | Check with `dig`, wait for the TTL |
| Validation fails although IPv4 is right | Wrong AAAA record | Remove or fix the AAAA record |
| `CAA record prevents issuance` | CAA allows only another CA | Add `0 issue "letsencrypt.org"` |
| Site behind Cloudflare not issued automatically | Domain resolves to Cloudflare's IPs | Issue manually or use a Cloudflare Origin certificate |
| Browser says "not secure" after SSL | Mixed content (`http://` images or scripts) | Update URLs in the database or theme to `https://` |

To check the certificate actually being served:

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

For sites behind Cloudflare, see [using Cloudflare with a VPS](/blog/cloudflare-with-vps).

## Conclusion

Free SSL from Let's Encrypt is easy: point the domain, open port 80, run Certbot and confirm renewal with `--dry-run`. What matters over the next few years is **automation and monitoring**, because certificates will get shorter and Let's Encrypt no longer emails you before they expire.

If you look after many sites, [ZoPanel](/pricing) issues, renews and alerts on SSL for every website automatically, including on the Free plan (10 websites, 10 databases). The details are in the [SSL docs](/docs/ssl).

## Frequently asked questions

### Is Let's Encrypt SSL really free?

Yes. Let's Encrypt is a non-profit certificate authority whose certificates are trusted by all major browsers, at no cost. You only need an ACME client such as Certbot, or a control panel that has one built in.

### How long do Let's Encrypt certificates last?

The default is currently 90 days. Under the published plan, default certificates drop to 64 days from 10 February 2027 and to 45 days from 16 February 2028, so renewal has to be automated.

### Can I get a wildcard certificate from Let's Encrypt?

Yes, but only with DNS validation (DNS-01), not HTTP. Use the Certbot DNS plugin for your DNS provider, or a panel that hosts the DNS zone, such as ZoPanel, so renewals stay automatic.

### Why does Certbot time out during validation?

Usually port 80 is blocked by the server's firewall or the provider's cloud firewall, or the domain does not point to the right IP yet. Check with `dig` and open port 80 in both UFW and the cloud firewall.

### Should I use a free or a paid SSL certificate?

For most sites, including online shops, a Let's Encrypt (DV) certificate encrypts traffic just as well as a paid DV certificate. Paid OV or EV certificates are only needed when your organisation or a contract requires validated company details.
