Cloudflare with LetsEncrypt SSL Certificates + Apache’s ProxyPass
So, you want to use LetsEncrypt to generate a free SSL certificate for your site behind Cloudflare and Apache (acting as a ReverseProxy). After many hours of research and tweaking, I got this setup to work. Here I will document my process for you to use. In the end, your setup will look something like this: User <-(SSL)-> Cloudflare <-(SSL)-> Apache <–> Your Webapp (not SSL). This guide assumes you have a site already setup without SSL. I am using Ubuntu 16.04 for my setup, but the process should be similar for other OSes.
Before we do anything, we need to install LetsEncrypt. LetsEncrypt reccomends Certbot as their client. Unless you know what you are doing, you should use this. Follow the instructions on their site to install the Certbot client. After Certbot is installed, you should install the apache mod mod_cloudflare. It isn’t required, but is good in any setup invloving Cloudflare, as it resolves IPs to their actual source, not Cloudflare’s IPs. Follow the instructions on Cloudflare’s site, and run
sudo a2enmod cloudflare to ensure it is enabled. Finally, make a backup of the the site configs you will be changing. It is unlikely something will go wrong, but just in case we need to roll back we should have one.
Custom Config Patch
Now that Certbot/LE is installed, we will continue on with the setup. By default, apache passes all traffic to the backend application when using ProxyPass. We need to add an exception to this rule by installing and including a custom config. If you aren’t using ProxyPass, skip this step. Make a new file in
/etc/apache2/conf-avaliable/letsencrypt-proxypass-fix.conf, and paste the following into it:
# From https://github.com/certbot/certbot/issues/2164 <IfModule mod_proxy.c> # If Proxy is installed ProxyPass "/.well-known/acme-challenge" "!" # Do not proxy the acme verification </IfModule> Alias /.well-known/acme-challenge /var/www/html/.well-known/acme-challenge # Send all requests for the acme verification to this location <Directory "/var/www/html/.well-known/acme-challenge"> # Allow any requests for it Options None AllowOverride None Require all granted AddDefaultCharset off </Directory>
Save the file, and quit. For now this isn’t activated, but we will be including it in the site configuration file next.
Generating the Certificate
Now that most of the prep work is finished, we can get to actually generating the certificate. Include the line
Include /etc/apache2/conf-available/letsencrypt-proxypass-fix.conf in the site’s config, and reload apache. Now, run
certbot certonly --webroot --webroot-path /var/www/html/ --renew-by-default -d YOUR.DOMAIN.HERE. Answer the questions, and assuming everything was done correctly, you will get a message saying that the certificate was generated successfully, and will expire in 90 days. Whoopee, you have an SSL certificate! However, even though you were issued an SSL certificate, apache doesn’t know about it, and is still only listening for non-secure connections. We need to install the certificate for apache to use.
Installing the Certificate
Now that you have generated the certificate, you need to install it to apache. Open your site’s config, and edit it to look something like the following. Note, some applications require extra flags and steps, so please follow their documentation as well; this is a minimal config. Also, don’t forget to include any other configurations you had from your old config!
<VirtualHost *:80> ServerName YOUR.DOMAIN.HERE Redirect permanent / https://YOUR.DOMAIN.HERE/ # Redirect all nonsecure requests to use HTTPS </VirtualHost> <VirtualHost *:443> ServerName YOUR.DOMAIN.HERE SSLProxyEngine On SSLCertificateFile /etc/letsencrypt/live/YOUR.DOMAIN.HERE/cert.pem SSLCertificateKeyFile /etc/letsencrypt/live/YOUR.DOMAIN.HERE/privkey.pem SSLCertificateChainFile /etc/letsencrypt/live/YOUR.DOMAIN.HERE/chain.pem Include /etc/letsencrypt/options-ssl-apache.conf # The LetsEncrypt SSL config Include /etc/apache2/conf-available/letsencrypt-proxypass-fix.conf # The patch for ProxyPass we made earlier ProxyRequests Off ProxyPreserveHost On ProxyPass / http://000.000.000.000/ # Replace this with whatever address you had from your old config ProxyPassReverse / http://000.000.000.000/ RequestHeader append "X-Forwarded-Proto" "https" # Tell the application we are forwarding from SSL RequestHeader set "X-Forwarded-Ssl" "on" </VirtualHost>
Tada! Your service now uses your certificate. If you were to visit this site without Cloudflare’s CDN you would be able to see that the site uses LetsEncrypt.
Now that HTTPS is installed, we need to tell Cloudflare to use Full SSL. I personally have had mixed experiences, but sometimes if this isn’t set properly, your browser can get stuck in a Redirect loop. Full SSL requires that your server has a certificate installed for users to access HTTPS via Cloudflare. Changing this option affects all records on the domain, so don’t do this unless everything is set up correctly (alternativley you can use a Page Rule). For a more detailed explanation, see Cloudflare’s support article.
Once you are logged into Cloudflare’s website, click your domain, click the Crypto button, and select Full (Strict) from the dropdown. Now Cloudflare will only use your valid LetsEncrypt Certificate for communication!
If all went according to plan, you should be able to naivgate your site from inside or ourside Cloudflare via HTTPS. Make sure you update your site’s links to use HTTPS!
Don’t forget every month or so to renew the certificate you just made with
certbot renew. I will make another post later on how to automatically renew your certs, eliminating the need for maintenance.
I hope this guide helped you. If you have any questions or comments, don’t be afraid to comment or contact me!