HTTPS with CloudFlare + Caddy = ❤️

There are dozens of reverse proxies and thousands of ways to configure them. Unlike many, Caddy is very easy to configure and use, it's very efficient and production-ready. It has sensible defaults and does everything for you out of the box.

Cloudflare is one of the biggest CDN(Content Delivery Network), widely used to speed up page loading, enable edge caching and mitigate attacks. It also provides HTTPS certificates for your website, for free, even on the free plan.

Recently Caddy has become my default front-facing proxy-server, especially when I need quick and reliable setup of HTTPS with Let's Encrypt TLS. In this post, you learn how to configure it to work with Cloudflare. As usual, it takes a few lines to set it up.

Full end-to-end encryption with Caddy and Cloudflare

In this tutorial, you'll configure full end-to-end encryption from the user to your website served by Caddy webserver:

  • Clients are connected via HTTPS using automatically generated free Cloudflare TLS certificate
  • Cloudflare is communicating with my edge server via self-signed SSL certificate generated by Caddy server
  • In this setup all communication between browser and your Caddy server is encrypted, that helps to mitigate MIIM(Man-in-the-middle) attack

Setup DNS configuration in the Cloudflare settings:

  • Add redirection from **www.$SITEDOMAIN**
  • Point A record to the IP address of your server running Caddy

DNS Configuration in Cloudflare to make it work with Caddy server

In the SSL/TLS settings set encryption to FULL

Configure Cloudflare to use full encryption with Caddy self-signed certificate

That's it; we've done with major Cloudflare settings, feel free to play with other parameters

Configure Caddy

The next step is to configure Caddy to work with it. Your Caddy server need to generate and use self-signed SSL certificate. Don't try to setup to setup Let's Encrypt - it won't work behind CloudFlare(or at very least there is no point in it) {
    tls internal
    reverse_proxy myweb-site-ip-address-or-docker-host:80

As I promised, - it's just a few lines. In default configuration Caddy is trying to get Let's Encrypt and adding tls internal prevents it from doing so. Instead of requesting certificate Caddy generates new, self-signed certificate. Note, it's not valid from the outer world's perspective so that the web browser would display an SSL error message.

Mixed configuration - Let's Encrypt without Cloudflare

I like how easy to add a new host to the Caddy. Few lines and the new virtual host is configured to obtain Let's Encrypt certificates automatically.

In my particular case, I want a mixed configuration:

  • Some hosts are served directly from Caddy server
  • Other hosts are behind Cloudflare, so clients are not directly communicating with Caddy {  # this website is behind CloudFlare
    tls internal
    reverse_proxy myweb-site-ip-address-or-docker-host:80
} { # this website is accessed directly from browser
    reverse_proxy myotherwebsite-ip-address-or-docker-host:80

See? No need to put anything special, Caddy generously protect our website by default.


With Caddy it's effortless to configure a multi-host server and even serve some website via CloudFront using a single instance of the webservice.