Get your free server today! View Plans →
Home Plans Blog About Contact Panel Join Discord
Security

How to get a free SSL certificate with Let's Encrypt

A step by step guide to securing your site with a free Let's Encrypt certificate using Certbot and Nginx. Issue it in two minutes and let it renew itself.

How to get a free SSL certificate with Let's Encrypt

By the end of this guide you'll have a working HTTPS certificate on your domain, served by Nginx, and set to renew itself automatically so you never think about it again. It's written for anyone running their own Linux server, whether that's a small WordPress blog, a game panel, or a side project you put online last weekend. You don't need to be a sysadmin to follow along, just comfortable typing a few commands.

Why bother with HTTPS on a small site

It's easy to assume the padlock only matters for online stores and banks. That's not really true anymore. Browsers like Chrome and Firefox now flag plain HTTP pages as "Not Secure," which scares off visitors even if your site is harmless. Search engines also give a small ranking nudge to secure sites. And without HTTPS, anything typed into a form on your page, including login passwords, travels across the network in plain text that anyone in between can read.

So the short version is this. HTTPS protects your visitors, it removes the scary warning, and it costs you nothing. Let's Encrypt is a free, automated certificate authority, and Certbot is the tool that talks to it for you. Together they turn what used to be a paid, annual chore into a two minute job.

What you need before you start

A few things have to be in place, or the certificate request will fail. Check each one off before you run anything.

That last point about the domain is the one people trip on most. The certificate is tied to the name, so the name has to point at this exact server first. We'll cover that next.

Step 1: Point your domain at the server

Let's Encrypt uses something called the HTTP-01 challenge. In plain terms, it asks your server to place a small file at a known path, then it visits http://yourdomain/.well-known/acme-challenge/... to confirm the file is there. If your domain doesn't resolve to your server, that visit lands somewhere else and the whole thing fails.

So in your DNS settings (at your registrar or wherever you manage records), create an A record pointing your domain to your server's public IP. If you also want the www version covered, add a record for that too.

Type    Name    Value
A       @       203.0.113.45
A       www     203.0.113.45

Replace 203.0.113.45 with your real IP. DNS changes don't happen instantly. They can take anywhere from a couple of minutes to a few hours to spread. Check whether the record is live with dig:

dig +short example.com

If that prints your server's IP, you're ready. If it prints nothing or an old address, wait a bit and try again before moving on. Doing the rest of the steps before DNS is ready just wastes one of your daily certificate attempts.

Step 2: Install Certbot and the Nginx plugin

Certbot is the official client for Let's Encrypt. The Nginx plugin lets it read and edit your Nginx config automatically, which saves a lot of manual work. Update your package list first, then install both.

On Ubuntu or Debian:

sudo apt update
sudo apt install certbot python3-certbot-nginx

On a Red Hat style system like Rocky Linux, AlmaLinux, or Fedora, the commands look like this:

sudo dnf install certbot python3-certbot-nginx

Confirm it installed cleanly by checking the version:

certbot --version

You should see something like certbot 2.9.0. The exact number doesn't matter much, you just want a recent release.

A quick note on Snap

The Certbot team officially recommends installing through Snap on some systems, and you'll see that in their docs. The apt and dnf packages shown above are perfectly fine for most people and a bit simpler to manage. Pick one method and stick with it. Mixing two Certbot installs on one machine causes confusing renewal problems later.

Step 3: Run Certbot for your domain

This is the main event, and it's a single command. The --nginx flag tells Certbot to use the plugin, find the right server block, and wire everything up for you. Each -d adds a domain name to the certificate.

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

The first time you run Certbot, it asks a couple of questions. It wants an email address, which is used for expiry warnings and account recovery. Use a real one you check. It also asks you to agree to the terms of service. After that, it gets to work.

If all goes well you'll see output similar to this:

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/example.com/privkey.pem
This certificate expires on 2026-09-25.
Deploying certificate
Successfully deployed certificate for example.com to /etc/nginx/sites-enabled/example.com
Congratulations! You have successfully enabled HTTPS on https://example.com

Notice the certificate is valid for 90 days. That short window is on purpose. Let's Encrypt keeps lifetimes short to limit the damage if a key ever leaks, which is exactly why automatic renewal (Step 5) matters so much.

Step 4: Let Certbot add the HTTPS redirect

On older Certbot versions, after the certificate is issued it asks whether you want to redirect HTTP traffic to HTTPS. Recent versions usually set this up on their own. Either way, the goal is the same. You want anyone who types http:// to be bounced to the secure https:// version.

If you got the prompt, choose the redirect option. If you didn't, it's worth checking your Nginx config to confirm the redirect is there. Open your site's config file:

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

You're looking for a small server block that listens on port 80 and sends everything to HTTPS. Certbot adds lines that look roughly like this:

server {
    listen 80;
    server_name example.com www.example.com;

    if ($host = www.example.com) {
        return 301 https://$host$request_uri;
    }
    if ($host = example.com) {
        return 301 https://$host$request_uri;
    }
    return 404;
}

And your main block now listens on 443 with the certificate paths filled in:

server {
    listen 443 ssl;
    server_name example.com www.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # your existing location blocks stay here
    root /var/www/example.com;
    index index.html;
}

Whenever you edit Nginx by hand, test the config before reloading. This catches typos so you don't take the site down:

sudo nginx -t
sudo systemctl reload nginx

If nginx -t reports syntax is ok and test is successful, the reload is safe. Open https://example.com in a browser. You should see the padlock, and clicking it should show a certificate issued by Let's Encrypt.

Step 5: Set up automatic renewal

Because certificates only last 90 days, renewal is the part you really can't skip. The good news is the Certbot package sets this up for you. When it installs, it drops in a systemd timer (or a cron job on some systems) that runs twice a day and renews any certificate that's within 30 days of expiry. Most of the time it does nothing, because nothing is due yet, and that's fine.

You can confirm the timer is active:

sudo systemctl list-timers | grep certbot

You should see a certbot.timer entry with a next run time. Now test that renewal actually works, without touching your real certificate, using the dry run flag:

sudo certbot renew --dry-run

A healthy result ends with a line like this:

Congratulations, all simulations succeeded. The following certificates
are not due for renewal yet:
  /etc/letsencrypt/live/example.com/fullchain.pem (success)

If the dry run succeeds, real renewals will succeed too when the time comes. That's the whole point of the test. After a renewal, Certbot reloads Nginx for you so the new certificate is picked up without you doing anything. You can now genuinely forget about it.

A note on wildcard certificates

Everything above covers specific names like example.com and www.example.com. Sometimes you want a single certificate that covers every subdomain, for example app.example.com, blog.example.com, and any new one you add later. That's a wildcard certificate, written as *.example.com.

Wildcards can't use the HTTP-01 challenge. They require the DNS-01 challenge, which proves control by adding a special TXT record to your domain instead of serving a file over port 80. The command looks like this:

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

Certbot will pause and tell you to create a TXT record named _acme-challenge.example.com with a value it gives you. You add that record at your DNS provider, wait for it to spread, then press Enter to continue. If your DNS provider has a Certbot plugin (Cloudflare, for instance), you can automate this step so wildcard renewals happen on their own too. For a single site with one or two names, you usually don't need a wildcard at all. Stick with the simpler HTTP-01 method unless you have a real reason.

Troubleshooting

Most failures come down to one of a handful of causes. Here are the ones we run into most often and how to fix each.

Port 80 is blocked or already in use

The HTTP-01 challenge needs port 80 reachable from the outside. If Certbot times out trying to verify your domain, check your firewall. On a server using UFW:

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

Also remember your cloud provider may have its own firewall or security group. If you're on a VPS, open ports 80 and 443 in the provider's control panel too, not just in UFW. If Nginx itself won't start because something else holds port 80, find the culprit with sudo ss -tlnp | grep:80 and stop it.

DNS hasn't propagated yet

If Certbot says it couldn't verify the domain and the error mentions the wrong IP, your DNS record probably isn't live yet, or it points somewhere else. Run dig +short example.com again and confirm it returns this server's IP. New records and recent changes can take time, so wait and retry rather than hammering Certbot.

You hit a rate limit

Let's Encrypt limits how many certificates you can request for the same set of domains in a week. If you've been retrying a broken setup over and over, you might see a message about too many certificates already issued. The fix is patience, the limit resets on a rolling basis. To avoid burning attempts while you debug, use the staging environment, which has far looser limits and issues fake (untrusted) certificates:

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

Once the staging run succeeds end to end, remove --staging and run it for real. Just delete the staging certificate first so it doesn't get reused.

The certificate works but the browser still warns

If HTTPS loads but you get a mixed content warning, your page is probably pulling some images, scripts, or stylesheets over plain http://. Open your browser's developer console, find the offending URLs, and change them to https:// or to protocol relative paths. The certificate is fine, the page content just needs cleaning up.

Certbot can't find the right server block

The Nginx plugin needs a server_name line that matches the domain you passed with -d. If Certbot complains it couldn't find a matching block, open your config and make sure server_name example.com www.example.com; is present and spelled correctly. Run sudo nginx -t to confirm the config is valid, fix any reported errors, then run Certbot again.

Wrapping up

That's the full loop. You pointed your domain at the server, installed Certbot, issued a certificate with one command, confirmed the HTTP to HTTPS redirect, and proved that automatic renewal works with a dry run. From here your site stays secure with no recurring effort, because the renewal timer quietly handles the 90 day cycle on its own.

If you're hosting with us at Bytte.cloud, the same steps apply on any VPS, and our Discord is a good place to ask if a challenge fails or DNS gives you grief. Bookmark the two commands worth remembering, sudo certbot --nginx -d yourdomain.com to add a new site and sudo certbot renew --dry-run to check that renewal is healthy, and you're set.

Common questions

Is a Let's Encrypt certificate really free?

Yes, completely. Let's Encrypt is a non profit certificate authority, and Certbot is free open source software. There's no cost to issue or renew certificates, and no limit on how long you keep using them.

How long does a Let's Encrypt certificate last?

Each certificate is valid for 90 days. That short window is intentional. The Certbot package installs a renewal timer that runs twice a day and automatically renews any certificate within 30 days of expiry, so you don't have to track dates yourself.

Why did my certificate request fail with a verification error?

Almost always it's DNS or port 80. Make sure your domain's A record points at the server (check with dig +short yourdomain.com) and that port 80 is open in both your server firewall and your VPS provider's firewall, since the HTTP-01 challenge needs it.

Can I get one certificate for all my subdomains?

Yes, with a wildcard certificate written as *.example.com. Wildcards require the DNS-01 challenge instead of HTTP-01, which means adding a TXT record to your domain. For a single site with one or two names, the standard HTTP-01 method is simpler and usually all you need.

How do I check that automatic renewal is working?

Run sudo certbot renew --dry-run. It simulates a full renewal without touching your real certificate. If it ends with a success message, your real renewals will work too when they come due.

SA
Sofia Almeida
Systems Engineer at Bytte.cloud

Part of the Bytte.cloud team. We run game servers, bots and websites for a living, and we write these guides from what we see day to day in support and on our own servers.

Want to try this on real hardware?

Bytte.cloud has free plans for game servers, bots and websites. No credit card, set up in seconds.

Start for free See the plans