Properly Enable HTTPS on Apache with Let’s Encrypt on Ubuntu
This tutorial is going to show you how to properly enable HTTPS on Apache with Let’s Encrypt on Ubuntu. Google Chrome and Firefox have already begun marking non-encrypted web pages with password input box as being insecure. Eventually all HTTP web pages will be marked as insecure. HTTPS will become default for any website. It’s also a requirement if you want to utilize HTTP/2 protocol to speed up your website.
As you may probably know, Let’s Encrypt is a free, automated, and open certificate authority. The official documentation describes simple steps you can follow to enable HTTPS with Let’s Encrypt, but there’s more to it than that. If you follow the official doc, you will score A on SSL Labs test. If you follow my steps, you will get an A+ score. If you’ve already deployed a Let’s Encrypt certificate before, you can still follow this tutorial to renew and replace your existing certificate.
Before I show you the steps to enable HTTPS with Let’s Encrypt, I want to first talk about CAA record, security headers and OCSP stapling. These things are what can help you get A+. I will also show you how to deal with CloudFlare CDN service at the end of this tutorial.
Note: This tutorial works on all current versions of Apache and Ubuntu (including 16.04, 18.04 and 20.04).
Creating CAA Record for Your Domain Name
Certificate Authority Authorization (CAA) is a DNS resource record that specifies which certificate authorities (CAs) are allowed to issue certificate for a particular domain name. Starting September 2017, All CAs are mandated to check CAA records before issuing certificate for a particular domain name. If no CAA record is found for a domain name, then any CA can issue certificate for that domain name. If a CA is not listed in your CAA record, then that CA cannot issue certificate for your domain name.
To create a CAA record which allows Let’s Encrypt to issue certificate for your domain name, add the following entry in your DNS server or DNS manager.
example.com. IN CAA 0 issue "letsencrypt.org"
You can also use iodef to make CA report malicious certificate issue request to your email address.
example.com. IN CAA 0 iodef "mailto:your-email-address"
The format of the above records is for zone files. Below are a few tips for you.
- You can use SSLMate CAA Record Helper to generate CCA record for your domain name.
- If you are using GoDaddy DNS, then follow this post to add CAA record.
You can use the following dig command to check your CAA record.
dig example.com CAA
Note that web browsers will not check CAA records.
Security Headers
Security headers are as important as HTTPS, but only a small percentage of HTTPS-enabled sites pay attention to security headers. While a complete discussion about security headers is beyond the scope of this tutorial, I want to talk about the upgrade-insecure-requests and HSTS headers because you can easily enable them with Let’s Encrypt to increase your site’s security.
Upgrade Insecure Requests
There are times when a site has enabled HTTPS, but some CSS, images or JavaScripts are still served over HTTP. In this case, the green padlock at the beginning of browser address bar will disappear. In Google Chrome, it’s replaced with an info icon; In Firefox, it’s replaced with a gray padlock with a yellow triangle. You will want to show a green padlock to site visitors as much as possible and the easy way to fix this problem is to enable upgrade-insecure-requests header, which will force the web browser to use https:// for every http:// resource.
To enable this header, simply add --uir
flag when issuing certbot command. Note that this header works on resources hosted on your own domain and resources on third-party domains that support HTTPS. If your web page includes resources on third-party servers that aren’t available over HTTPS, then those resources will be blocked by web browsers, but using this header ensures that your web pages always get a green padlock.
HSTS (HTTP Strict Transport Security)
The HSTS header tells web browsers that all communication with your website should be done over HTTPS. It defends against SSL Striping, which is an attack to downgrade from HTTPS to HTTP. To enable this header, simply add --hsts
flag when issuing certbot command.
OCSP Stapling
When a web browser connects to a HTTPS website, it sends an OCSP (Online Certificate Status Protocol) request to the certificate authority (CA) in order to query the revocation status of the website’s SSL certificate. This can delay page loading by 1-3 seconds, according to Firefox telemetry data.
To improve performance, website owner can enable OCSP stapling, in which case the web server itself fetches OCSP response signed by CA at regular interval and sends it to web browser, thus eliminating the need for web browser to contact OCSP server.
To enable OCSP stapling, simply add --staple-ocsp
flag when issuing certbot command.
OCSP Must Staple
If a hacker make a fake, duplicate website, turn off OCSP staple and also block the web browser’s access to OCSP server, then the web browser will assume it’s OK and proceed to the malicious website. To solve this problem, you can enable OCSP must staple on your website, which tells web browsers that OCSP staple response must be presented by your website during HTTPS connection. So when web browsers connect to a fake website that doesn’t have OCSP staple, it will stop the connection.
To enable OCSP must staple, add --must-staple
flag when issuing certbot command.
Installing Let’s Encrypt Client (Certbot) on Ubuntu
Now it’s time to get your hands dirty. Starting Ubuntu 16.04, Let’s Encrypt client (Certbot) is included in the Ubuntu repository, so you can install it with the following command. Python3-certbot-apache is the Certbot Apache plugin.
sudo apt install certbot python3-certbot-apache
To check the version number, run
certbot --version
Sample output:
certbot 0.31.0
If you want to use the latest version, you can install Certbot from the Snap store.
sudo apt install snapd sudo snap install --classic certbot
Note: If you want to use the Snap version, you need to use the full binary path: /snap/bin/certbot
.
Using Apache Plugin to Enable HTTPS
If your website doesn’t use CDN service, then it’s recommended to use the Apache plugin to enable HTTPS on Apache web server, as it can automatically obtain SSL/TLS certificate and configure it for you. Run the following command on your Ubuntu server.
sudo certbot --apache --agree-tos --redirect --uir --hsts --staple-ocsp --must-staple -d www.example.com,example.com --email [email protected]
Explanation:
--apache
: Use the Apache authenticator and installer--agree-tos
: Agree to Let’s Encrypt terms of service--redirect
: Automatically redirect all HTTP traffic to HTTPS--uir
: Add the “Content-Security-Policy: upgrade-insecure-requests” header to every HTTP response.--hsts
: Add the Strict-Transport-Security header to every HTTP response.--staple-ocsp
: Enables OCSP Stapling.--must-staple
: Adds the OCSP Must Staple extension to the certificate.-d
flag is followed by a list of domain names, separated by comma. You can add up to 100 domain names.--email
: Email used for registration and recovery contact.
You will be asked if you want to receive emails from EFF(Electronic Frontier Foundation). After choosing Y or N, your SSL certificate will be automatically obtained and configured for you, which is indicated by the message below.
Now if you visit your website, you can see that HTTP is automatically redirected to HTTPS connection. Please note that certbot client creates /etc/apache2/sites-enabled/example.com-le-ssl.conf SSL virtual host when configuring SSL for your website.
Testing Your SSL Certificate
Go to ssllabs.com to test your SSL certificate and configuration. As I’ve promised, you get A+. You can also check if your domain name has enable CAA record, whether your server has enabled HSTS, OCSP stapling and OCSP must staple.
Redirecting WWW to Non-WWW (Or Vice-Versa)
We have already enabled redirecting HTTP to HTTPS, what’s left to do is redirect www to non-www, or vice versa. If you are using WordPress, then it’s very easy. Simply go to WordPress Dashboard > Settings > General and set your preferred version (www or non-www) in WordPress Address and Site Address.
If you go that route, you will end up with what’s known as double 301 redirect. First, Apache server redirect HTTP to HTTPS, then WordPress redirects to www or non-www domain.
Some may argue that you can lose SEO link juice when doing double 301 redirect. If you are worried about that, then you can use the method below to make all domain versions to go directly to the final destination.
Edit your virtual host file. (Not the SSL virtual host)
sudo nano /etc/apache2/sites-enabled/example.com.conf
CertBot client added the following lines to the file to redirect HTTP to HTTPS.
RewriteEngine on RewriteCond %{SERVER_NAME} =example.com [OR] RewriteCond %{SERVER_NAME} =www.example.com RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
To redirect to www or non-www domain, you need to change the last line. Replace %{SERVER_NAME}
with your preferred domain version like below. (www domain)
RewriteRule ^ https://www.example.com%{REQUEST_URI} [END,NE,R=permanent]
If you prefer non-www domain, change it to the following.
RewriteRule ^ https://example.com%{REQUEST_URI} [END,NE,R=permanent]
Then save and close the file. We will also need to edit the SSL virtual host.
sudo nano /etc/apache2/sites-enabled/example.com-le-ssl.conf
Add the following lines above the closing </VirtualHost> tag to redirect non-www to www domain.
RewriteEngine on RewriteCond %{SERVER_NAME} =example.com RewriteRule ^ https://www.example.com%{REQUEST_URI} [END,NE,R=permanent]
If you want to redirect www to non-www domain, add the following lines instead.
RewriteEngine on RewriteCond %{SERVER_NAME} =www.example.com RewriteRule ^ https://example.com%{REQUEST_URI} [END,NE,R=permanent]
Save and close the file. Reload Apache service for the changes to take effect.
sudo systemctl reload apache2
To be more clear, below is a screenshot of my Apache virtual host file and SSL virtual host file for redirecting non-www to www domain.
If you are using WordPress, make sure you set your preferred domain version in WoredPress Address and Site Address before editing Apache virtual host files. If WordPress settings contradicts with Apache configuration, your site will be in a redirect loop.
How to Disable TLSv1 and TLSv1.1
TLSv1 and TLSv1.1 are no longer considered secure. To disable them, edit the Let’s Encrypt SSL options configuration file.
sudo nano /etc/letsencrypt/options-ssl-apache.conf
Find the following line, which disables SSLv2 and SSLv3 by default.
SSLProtocol all -SSLv2 -SSLv3
Change it to the following to also disable TLSv1.0 and TLSv1.1.
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
Save and close the file. Then restart Apache.
sudo systemctl restart apache2
Certificate Auto Renewal
To automatically renew Let’s Encrypt certificate, simply edit root user’s crontab file.
sudo crontab -e
Then add the following line at the bottom.
@daily certbot renew --quiet && systemctl reload apache2
--quiet
flag will suppress normal messages. If you want to receive error messages, then add the following line at the beginning of crontab file.
MAILTO=your-email-address
Reloading Apache is needed for it for present the new certificate to clients.
CloudFlare CDN
The first thing you need to know is that if you want to install Let’s Encrypt certificate on your server and at the same time use CloudFlare’s CDN service, then you will need to enable CloudFlare’s Universal SSL on your site, which means
- Connections between site visitors and CloudFlare edge server are encrypted using CloudFlare Universal SSL certificate.
- Communications between your origin server and CloudFlare edge server are encrypted using Let’s Encrypt issued certificate.
If you install Let’s Encrypt certificate on your origin server, redirect HTTP to HTTPS and turn off CloudFlare Universal SSL, the web browsers will complain that your website is in a infinite redirect loop because CloudFlare redirect HTTPS to HTTP.
The second thing you need to know is that if you want to enable CAA record while using CloudFlare Universal SSL, then you also need to create the following CAA record.
example.com. IN CAA 0 issue "comodoca.com" example.com. IN CAA 0 issue "digicert.com" example.com. IN CAA 0 issue "globalsign.com
Follow this post to add CAA record for CloudFlare Universal SSL certificate.
So how do you go about installing Let’s Encrypt certificate with CloudFlare? Well, there are two scenarios.
- You’ve already installed Let’s Encrypt certificate using the above steps, now you want to enable CloudFlare CDN service.
- Your website is using CloudFlare CDN service, now you want to install Let’s Encrypt certificate on your origin server.
The First Scenario
If you are in the first scenario, then you can go ahead and enable CloudFlare CDN service and also enable CloudFlare Universal SSL in CloudFlare Dashboard by going to Crypto > SSL and choosing Full (Strict). Your site will be working fine without a problem.
The Second Scenario
If you use CloudFlare CDN and now you want to install Let’s Encrypt on your origin server, then run the following command to obtain and install Let’s Encrypt TLS certificate.
sudo certbot --apache --agree-tos --redirect --uir --hsts --staple-ocsp --must-staple -d www.example.com,example.com --email [email protected]
After the certificate is obtained and installed on your server, go to Cloudflare dashboard and enable CloudFlare Universal SSL.
Next Step
I hope this tutorial helped you enable HTTPS on Apache virtual host with Let’s Encrypt on Ubuntu. You may also want to set up ModSecurity web application firewall to protect your site from hacking.
To speed up your website, you can enable HTTP/2 protocol with Apache.
As always, if you found this post useful, then subscribe to our free newsletter to get more tutorials.
If you see the following error while trying to obtain TLS certificate.
It’s probably because you installed a malfunctioning certbot binary. I recommend installing certbot from the Snap store.
Then remove the certbot deb pacakge.
WOW, Really well explained and detailed!
It was super easy to setup!
Thank you so much!
Absolutely perfect. You rock!
Thank you so much.
Thanks for these instructions! I actually needed to remove the HTTPS redirect on my site as I am trying to provide a site that will work in the earliest web browsers, and newer browsers were forcing HTTPS… so I installed certbot, and then the older browsers couldn’t access the site anymore. I’m good now after I commented out the RewriteCond & RewriteRule from the sites-enabled file.
One of the best tutorials on the web, all works like a charm, DO server, Outlook/Apple Mail connected, thank you!
Hi Xiao I long ago bought a comodossl certificate and followed your tutorial. But I realized that the certificate only works on the local network. from the internet it gives me an error (the connection is not private) and shows me a certificate (ZTE) which is not mine. Where am I doing wrong?
You don’t need to buy any SSL certificate to follow this tutorial. Let’s Encerypt certificate is free.
Allora questo certificato posso installarlo anche anche sul mio web server Raspberry pi in casa?
I’m sorry …. So can I also install this certificate on my Raspberry pi web server at home?
Hi xiao, can you explain to me the atumatic renewal with cronotab?
It’s very simple.
certbot renew
is used to renew TLS certificate. The Cron job will runcertbot renew
once a day. If the certificate is about to expire in 30 days, then certbot will renew the certificate.