Setting up a free SSL certificate with Let's Encrypt and Certbot

Published on Updated on 5 min read

A free SSL certificate for your Linux server: install Certbot on Debian and Ubuntu, issue a Let's Encrypt certificate for Apache and let it renew itself automatically.

An SSL certificate from Let's Encrypt costs nothing, takes a few minutes to set up and is accepted by every common browser. In this guide you enable HTTPS on your own Linux server running Apache: on Debian 13, Debian 12, Ubuntu 24.04 LTS and Ubuntu 22.04 LTS.

Certbot, the official ACME client from the Electronic Frontier Foundation, takes care of the issuing. It requests the certificate, adds it to the Apache configuration and then renews it on its own through a systemd timer.

Requirements

  • A domain whose A record (plus the AAAA record if you use IPv6) points to your VPS or root server.
  • A running Apache2 web server with a VirtualHost for that domain.
  • Root access over SSH.
  • Port 80 and port 443 have to be reachable from outside. Let's Encrypt validates the domain over port 80.

First check that the domain really points to your server. Enter your domain at https://check-host.net/. If the IP address of your server shows up there, you can continue. If DNS still points to an old target, wait for the update to go through, otherwise the issuing fails.

Updating the system

Bring the package list and the installed packages up to date first:

apt update && apt upgrade -y

Installing Certbot

There are two common routes. The distribution package is the simplest one and is perfectly sufficient for most servers. The snap package always ships the newest Certbot version and is the one the Electronic Frontier Foundation officially recommends.

Option 1: Certbot from the distribution repository

On Debian and Ubuntu, Certbot and the Apache plugin sit right in the package sources:

apt install certbot python3-certbot-apache -y

The once widespread package "python-certbot-apache" belonged to Python 2 and no longer exists. On all current Debian and Ubuntu versions, "python3-certbot-apache" is the correct package name.

Option 2: Installing Certbot through snap

If you want the newest Certbot version, for example for DNS plugins or wildcard certificates, install Certbot as a snap. Remove any existing package installation first so the two do not get in each other's way:

apt remove certbot -y
snap install core
snap refresh core
snap install --classic certbot
ln -s /snap/bin/certbot /usr/bin/certbot

Issuing the certificate and wiring it into Apache

The quickest route is the Apache plugin. Certbot reads the existing VirtualHosts, requests the certificate and writes the matching SSL configuration itself:

certbot --apache -d MeineDomain.de -d www.MeineDomain.de

If you would rather keep control of the Apache configuration yourself, you can run the domain validation through the webroot directory. Point it at exactly the directory that the VirtualHost uses as its DocumentRoot:

certbot --authenticator webroot --installer apache -w /var/www/MeineDomain.de -d MeineDomain.de -d www.MeineDomain.de

If your website sits in the default directory, the command is:

certbot --authenticator webroot --installer apache -w /var/www/html/ -d MeineDomain.de -d www.MeineDomain.de

The questions Certbot asks

On the first run, Certbot asks a few questions:

  • Email address: Give an address you actually read. Let's Encrypt uses it to warn you when a renewal does not happen.
  • Terms of service: Press "A" to agree.
  • Electronic Frontier Foundation newsletter: "Y" for yes, "N" for no. This is optional and has no effect on the certificate.
  • Redirect to HTTPS: Pick the "Redirect" option so that Apache sends every HTTP request to HTTPS automatically.

Certbot then shows the path to the certificate. The files live under /etc/letsencrypt/live/MeineDomain.de/. Do not edit these files by hand, they get rewritten on every renewal.

Checking the automatic renewal

A certificate from Let's Encrypt is valid for 90 days. Certbot renews it automatically as soon as fewer than 30 days are left. The package ships a systemd timer for exactly that. Check whether it is active:

systemctl list-timers certbot.timer

If the timer is not active, enable it:

systemctl enable --now certbot.timer

Then test the procedure as a dry run. Nothing gets issued, Certbot only rehearses the renewal:

certbot renew --dry-run

So that Apache really uses the new certificate after a renewal, add a deploy hook once:

certbot renew --deploy-hook "systemctl reload apache2"

Listing and removing certificates

For an overview of every certificate managed on the server, run:

certbot certificates

Remove a certificate you no longer need like this, so that Certbot stops trying to renew it:

certbot delete --cert-name MeineDomain.de

Common errors

  • "Could not bind to port 80": Another service occupies port 80. Stop it or use the webroot method, which works with the running Apache.
  • "Invalid response from http://.../.well-known/acme-challenge/...": The domain does not point to this server, a firewall blocks port 80, or the webroot directory you gave does not match the VirtualHost.
  • "The requested apache plugin does not appear to be installed": The package "python3-certbot-apache" is missing.
  • "too many certificates already issued": You have run into a rate limit at Let's Encrypt. From now on, test configurations with --dry-run before you request a real certificate.
  • The browser keeps showing a warning: Clear the browser cache and check whether Apache got reloaded after the certificate was issued.

Redirecting HTTP to HTTPS permanently

If you did not switch the redirect on when Certbot asked, you can add it at any time. We describe how that works with a .htaccess file in a separate post on redirecting HTTP to HTTPS.

Frequently asked questions

What does an SSL certificate from Let's Encrypt cost?
Nothing. Let's Encrypt is a non-profit certificate authority and issues certificates free of charge. There are no one-off fees and no running fees.
How long is a Let's Encrypt certificate valid?
90 days. Certbot renews it automatically as soon as fewer than 30 days are left. The systemd timer that takes care of this is set up during the installation.
Do I have to renew the certificate by hand?
No. Run certbot renew --dry-run once to confirm that the renewal goes through cleanly. After that, Certbot handles it on its own in the background.
Does Let's Encrypt work for subdomains as well?
Yes. Simply append further names to the command with additional -d parameters. A wildcard certificate additionally requires validation through a DNS record, and therefore a matching DNS plugin for Certbot.
Why does the domain validation fail?
In almost every case the A record of the domain does not point to this server, or a firewall blocks port 80. Let's Encrypt then cannot reach the server and aborts the issuing.

Lets-Encrypt Certbot SSL Certificate HTTPS Apache Debian Ubuntu