2026年11月12日
2026年11月12日
Enable SSL/TLS (HTTPS) on Apache with Let’s Encrypt and Certbot
This article is a localized edition of the Japanese original. Read the Japanese original
To use HTTPS with Apache HTTP Server, you obtain a server certificate, enable mod_ssl, and configure the certificate in a VirtualHost on port 443. The usual approach is to use a free Let's Encrypt certificate and Certbot, the client Let's Encrypt recommends, to obtain and renew it.
Older guides obtained certificates with a package and command named letsencrypt. That is Certbot's former name; today you use the certbot package and the certbot command. Using Apache 2.4 on Ubuntu / Debian as the example, this article covers obtaining a certificate with Certbot, configuring Apache, checking automatic renewal, and changing the settings on the WordPress side. Differences on RHEL-based systems (AlmaLinux, Rocky Linux, and so on) are summarized in a later section.
Prerequisites and preparation
Before you start, confirm the following.
- The A / AAAA records for the domain (for example
example.comandwww.example.com) point to this server's IP address - Ports 80 and 443 are reachable from outside (Let's Encrypt validates over port 80)
- The site loads over HTTP (port 80), and its VirtualHost has a
ServerName
If you use ufw as your firewall, open Apache's ports 80 and 443.
sudo ufw allow 'Apache Full'
Here is an example port 80 VirtualHost. Put it in /etc/apache2/sites-available/example.com.conf and enable it with sudo a2ensite example.com.conf.
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example
<Directory /var/www/example>
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/example-error.log
CustomLog ${APACHE_LOG_DIR}/example-access.log combined
</VirtualHost>
AllowOverride All lets WordPress use its .htaccess (permalinks). You don't need it if you aren't hosting WordPress.
Install Certbot
On Ubuntu / Debian, you can install Certbot and its Apache plugin as packages.
sudo apt update
sudo apt install certbot python3-certbot-apache
The official Certbot site also describes installing it via snap. Use only one of the two; don't install both.
Method A: Let Certbot configure Apache too
The quickest way is to use the Apache plugin (--apache) to obtain the certificate and configure Apache in one go.
sudo certbot --apache -d example.com -d www.example.com
The first time, you're asked for an email address and to agree to the terms of service. Certbot finds the target from the ServerName / ServerAlias of the port 80 VirtualHost and does the following.
- Saves the certificate in
/etc/letsencrypt/live/example.com/ - Creates a VirtualHost for port 443 (for example
/etc/apache2/sites-available/example.com-le-ssl.conf) and enablesmod_ssl - Sets up a redirect from HTTP to HTTPS (recent Certbot versions do this by default)
When it finishes, open https://example.com/ in a browser to check. If you'd rather manage the configuration yourself, use Method B below.
Method B: Obtain only the certificate and configure Apache by hand
Obtain the certificate
With certonly and --webroot, Certbot obtains only the certificate without touching the Apache configuration. For -w, specify the DocumentRoot of the port 80 VirtualHost.
sudo certbot certonly --webroot -w /var/www/example -d example.com -d www.example.com \
--deploy-hook "systemctl reload apache2"
--deploy-hook is a command that runs when the certificate has been renewed successfully. It's saved in the renewal configuration file (/etc/letsencrypt/renewal/example.com.conf), so Apache loads the new certificate after every automatic renewal.
Once obtained, the following files exist.
| File | Contents |
|---|---|
/etc/letsencrypt/live/example.com/fullchain.pem |
Server certificate and intermediate certificate |
/etc/letsencrypt/live/example.com/privkey.pem |
Private key |
Enable mod_ssl
sudo a2enmod ssl
Create the port 443 VirtualHost
Create /etc/apache2/sites-available/example.com-ssl.conf.
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
<Directory /var/www/example>
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/example-ssl-error.log
CustomLog ${APACHE_LOG_DIR}/example-ssl-access.log combined
</VirtualHost>
On Apache 2.4.8 and later, if you point SSLCertificateFile at fullchain.pem, which includes the intermediate certificate, you don't need SSLCertificateChainFile. If the intermediate certificate is missing, some browsers and curl report a certificate error.
Enable the site, check the syntax, then reload.
sudo a2ensite example.com-ssl.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
If apache2ctl configtest doesn't return Syntax OK, fix the line it reports before reloading.
Redirect HTTP to HTTPS
Replace the port 80 VirtualHost with one that only forwards to HTTPS.
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / https://example.com/
</VirtualHost>
Certificate renewal keeps working with this setup. Let's Encrypt's validation requests (/.well-known/acme-challenge/) are forwarded to HTTPS, and if the port 443 DocumentRoot is the same directory you passed with -w, they can be answered there. If you change DocumentRoot, update the webroot setting in /etc/letsencrypt/renewal/example.com.conf to match.
Specify the TLS versions
The old TLS 1.0 / 1.1 no longer work in major browsers. In the server-wide configuration (/etc/apache2/mods-available/ssl.conf on Ubuntu / Debian), allow only TLS 1.2 and 1.3.
SSLProtocol -all +TLSv1.2 +TLSv1.3
For detailed recommendations such as cipher suites, use Mozilla's "SSL Configuration Generator" and enter your server and OpenSSL versions. After making changes, run sudo apache2ctl configtest and sudo systemctl reload apache2.
Check automatic renewal
As of October 2026, Let's Encrypt certificates are valid for 90 days. Let's Encrypt has announced that it will shorten the validity period in stages: default certificates are scheduled to become 64 days from February 2027 and 45 days from February 2028. Manual renewal becomes impractical, so make sure automatic renewal is working.
# Is the renewal timer registered?
systemctl list-timers | grep certbot
# Test the renewal process without actually renewing
sudo certbot renew --dry-run
# List obtained certificates and their expiry dates
sudo certbot certificates
Certbot installed with apt uses certbot.timer, and the snap version uses snap.certbot.renew.timer; both check twice a day whether renewal is needed. If --dry-run fails, check that port 80 isn't closed, that DNS hasn't changed, and that the webroot path is correct.
Let's Encrypt stopped sending expiration notice emails in 2025, so it's a good idea to set up your own expiry monitoring.
Switch WordPress to HTTPS
Once the server responds over HTTPS, change the site URLs in WordPress as well.
- In the admin area, go to "Settings" → "General" (設定 → 一般 in the Japanese UI), change "WordPress Address (URL)" and "Site Address (URL)" to URLs starting with
https://, and save. - Replace any
http://URLs left in content and settings. If you can use WP-CLI, first check the count with--dry-run, then run it for real.
wp search-replace 'http://example.com' 'https://example.com' --skip-columns=guid --dry-run
wp search-replace 'http://example.com' 'https://example.com' --skip-columns=guid
Back up the database before you start. If images or scripts are still loaded over http://, browsers warn about or block them as "mixed content".
Verify it works
# Check the response headers
curl -I https://example.com/
# Check that HTTP redirects
curl -I http://example.com/
# Check the certificate's subject and expiry dates
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates
Also open https://example.com/ and https://www.example.com/ in a browser and confirm there are no certificate errors.
Differences on RHEL-based systems (AlmaLinux, Rocky Linux)
| Item | Ubuntu / Debian | RHEL-based |
|---|---|---|
| SSL module | sudo a2enmod ssl |
sudo dnf install mod_ssl |
| Configuration files | /etc/apache2/sites-available/ |
/etc/httpd/conf.d/*.conf |
| Certbot | apt install certbot python3-certbot-apache |
Enable EPEL, then dnf install certbot python3-certbot-apache |
| Service name | apache2 |
httpd |
| Syntax check | apache2ctl configtest |
apachectl configtest |
| Firewall | ufw allow 'Apache Full' |
firewall-cmd --permanent --add-service=https, then firewall-cmd --reload |
When you use Certbot from EPEL on RHEL-based systems, the renewal timer (certbot-renew.timer) may not be enabled automatically. Enable it with sudo systemctl enable --now certbot-renew.timer and confirm with systemctl list-timers. Also change the reload command in --deploy-hook to systemctl reload httpd.
Common problems
- Obtaining the certificate fails: typical causes are DNS still pointing to another server, port 80 being closed, or a proxy such as Cloudflare preventing the validation request from arriving. Check whether the URL in the error can be opened from outside.
- Apache won't start because of
SSLEngine:mod_sslisn't enabled. Runsudo a2enmod ssl. - HTTPS shows a different site: the
ServerName/ServerAliasof the port 443 VirtualHost doesn't match, or the site isn't enabled. Usesudo apache2ctl -Sto see which VirtualHost answers which name. - Redirects loop: if
.htaccessor a WordPress plugin also forwards to HTTPS, the redirects can double up and loop. Keep the redirect in one place only.
Summary
- Obtain certificates with
certbot, not the oldletsencryptname. - For speed, use
certbot --apache; to manage the configuration yourself, usecertbot certonly --webrootand write the port 443 VirtualHost. - Set
SSLCertificateFiletofullchain.pemandSSLCertificateKeyFiletoprivkey.pem. - Allow only TLS 1.2 and 1.3, and permanently redirect HTTP to HTTPS.
- Confirm automatic renewal with
certbot renew --dry-runand the timer, and change the WordPress URLs tohttps://.
Related articles
- How to set up an SSL certificate for Apache with certbot
- How to auto-renew Let's Encrypt certificates on Apache
- Fixing HTTPS redirect loops on Apache
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)