Certbot’s Apache plugin obtains a free Let’s Encrypt certificate, writes the HTTPS virtual host and sets up renewal — all in one command. Here’s the complete process for Ubuntu and Debian, plus notes for AlmaLinux and Rocky.
Prerequisites
- Apache serving your site over HTTP with a virtual host whose
ServerName(andServerAlias) match your domain — see Apache virtual hosts. - DNS A (and AAAA, if used) records pointing to this server.
- Ports 80 and 443 open:
sudo ufw allow 'Apache Full'. mod_sslavailable (Certbot enables it if needed).
1. Install Certbot
Ubuntu / Debian:
sudo apt update
sudo apt install -y certbot python3-certbot-apache
AlmaLinux / Rocky (from EPEL):
sudo dnf install -y epel-release
sudo dnf install -y certbot python3-certbot-apache mod_ssl
2. Get the certificate
sudo certbot --apache -d example.com -d www.example.com
Certbot:
- Finds the virtual host for those names.
- Proves domain control via an HTTP-01 challenge on port 80.
- Creates an SSL virtual host — on Debian/Ubuntu a new file such as
/etc/apache2/sites-available/example.com-le-ssl.conf— and enables it. - Adds a redirect from HTTP to HTTPS in the port-80 virtual host (it asks on older versions; newer versions redirect by default).
Open https://example.com to check.
3. What the SSL virtual host looks like
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public_html
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
Settings you add to the HTTP virtual host later (rewrite rules, <Directory> blocks) must also go into this HTTPS one — they’re separate virtual hosts.
4. Renewal
Certificates last 90 days; Certbot renews them automatically from a systemd timer or cron job:
systemctl list-timers | grep -i certbot
sudo certbot renew --dry-run
A successful dry run means renewal will work. The Apache plugin reloads Apache after renewing.
5. Optional hardening
Enable HTTP/2 and HSTS in the SSL virtual host:
sudo a2enmod http2 headers
Protocols h2 http/1.1
Header always set Strict-Transport-Security "max-age=31536000"
HTTP/2 requires the event or worker MPM (not prefork with mod_php). See Apache MPM event with PHP-FPM. Read HSTS explained before enabling it.
sudo apache2ctl configtest && sudo systemctl reload apache2
Useful commands
sudo certbot certificates # list certs and expiry
sudo certbot --apache -d shop.example.com # another site
sudo certbot --apache --expand -d example.com -d www.example.com -d blog.example.com
sudo certbot delete --cert-name old.example.com
Troubleshooting
Unable to find a virtual host listening on port 80 which is currently needed for Certbot to prove to the CA that you control your domain — no enabled virtual host has a matching ServerName/ServerAlias. Fix the vhost, enable it, reload Apache, retry.
Timeout during connect (likely firewall problem) — port 80 isn’t reachable from the internet. Check UFW/firewalld and any provider firewall.
Invalid response … 404 — the challenge request reached a different virtual host or a rewrite rule intercepted /.well-known/acme-challenge/. Exclude that path from rewrites:
RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/
.htaccess rules not working on HTTPS — the SSL virtual host lacks AllowOverride All for the directory. Add the same <Directory> block as on port 80.
Mixed content warnings — the site loads images or scripts over http://. Update URLs in the application (for WordPress, see WordPress SSL/HTTPS).
Too many redirects — often Cloudflare in Flexible SSL mode plus Apache’s redirect. Use Cloudflare’s “Full (strict)” mode.
Wildcard certificates
*.example.com needs the DNS-01 challenge with a DNS plugin; the Apache plugin can then install it. See wildcard certificates with Certbot.
Using Nginx instead? See Let’s Encrypt with Certbot on Nginx. New to Apache? Start with installing Apache on Ubuntu.