Handling HTTPS redirects with Caddy

July 15, 2020 - 6 min read

Have you ever had this or a similar problem? You have a website or app running on on the www sub-domain but still want users accessing your domain without www to get redirected to your main page.
Sure - some hosting providers such as Vercel or Firebase Hosting offer you an almost perfect solution for this but with other services like AWS they tell you to set up an S3 Bucket in combination with CloudFront for HTTPS for a simple redirect. What? And if you are using a fully managed service like Google Cloud Run (Google’s serverless offering for containers) to expose an HTTP endpoint you’re straight out of luck.
That’s the reason why I’m going to show you how you can setup a simple instance of Caddy - an open source web server - to handle your redirects over HTTP and HTTPS without much hassle.

Possible solutions

Using your registrars redirect feature

Most domain registrars offer a built-in HTTP redirect feature that aims to solve the problem described above… But all registrars’ redirect features I’ve tried were just straight up unusable. Be it because they don’t support HTTPS and therefore possibly break a bunch of backlinks or even worse be extremely slow or not redirect the user at all.

Using a commercial service

I believe that there are some truly great commercial services out there tackling this problem - that is if you budget allows for it. And if you are getting only a few visitors on site it’s most likely not worth it spending 10$ or more each month. While most offer a free tier as well it’s usually quite limited regarding the features it offers or the amount of redirect rules you can create. So if you are reading this article this option is probably out of question.

Setting up nginx for redirects

This is the first DIY solution I’m going to talk about. Using nginx has the advantage of being easy to integrate into an existing server configuration as you can simply create a new virtual host within an existing nginx process to handle your redirects.
This could look something like this:

server {
  server_name www.example.com;

  return 301 https://example.com$request_uri;

  listen 80;

But there’s an issue. If you’ve looked closely you might have noticed that we only listen on port 80 meaning we only support the HTTP protocol - not HTTPS. So if you want to support HTTPS - which you seriously should as it’s 2020 and you can get SSL certificates for free - your config file will inevitably get more complex and the steps needed to get up and running increase. While this could be a viable option it lacks simplicity and maintainability for multiple redirects.

Using Caddy

Why use Caddy? It solves all the problems I mentioned previously:

Setting up Caddy to handle redirects

Installing Caddy

Unless you are handling thousands of visitors you should be fine using a basic VPS from whatever provider you like.
The steps outlined here are the same as in Caddy’s documentation. This also includes instructions on how to run Caddy using Docker. For Debian, Ubuntu or Raspbian installation process only requires the following three simple commands:

  1. Telling apt were to find the Caddy download
$ echo "deb [trusted=yes] https://apt.fury.io/caddy/ /" \
    | sudo tee -a /etc/apt/sources.list.d/caddy-fury.list
  1. Reloading all package sources
$ sudo apt update
  1. And finally download Caddy itself
$ sudo apt install caddy

Setting up the first redirect

No matter what distro you are on you should now have a server running Caddy as a service.
By default Caddy’s configuration file - the appropriately named Caddyfile - is located in /etc/caddy/ and you should be able to edit it using a simple command line based editor like Vim. To do so use

$ vi /etc/caddy/Caddyfile

In case you haven’t used Vim before this tutorial by Linux Hint should get your started.

The initial Caddyfile makes Caddy serve static files from /srv/share/caddy no matter from what domain the server is access from though that’s not what we want to achieve. We’ll start out by setting up our first Virtual Host like this:

example.com {
  // Further configuration

Everything inside the curly braces will only be considered when the server is access through the domain specified so it’s here where we can specify our redirect. This is done using the redir keyword:

www.example.com {
  redir https://example.com

Using the config above any request to www.example.com will be redirected to https://example.com. If you want to preserve the path you can append the {uri} placeholder like this:

www.example.com {
  redir https://example.com{uri}

Finally if you want to redirect users only if they visit a specific path you can prepend it to the target url like this:

www.example.com {
  // Specify path
  redir /org https://example.org

  // Handle all other cases
  redir https://example.com{uri}

If you want to learn more about configuring paths I can highly recommend diving in the Caddy’s documentation on Request Matchers.

You can add as many Virtual Hosts as you like to support as many domains as you like.

Updating Caddy’s config

Finally we can tell Caddy about the new config by navigating into the location of the edited Caddyfile if you haven’t changed its path it’s located at /etc/caddy/ and reloading the Caddy process.

$ cd /etc/caddy
$ caddy reload

Don’t forget to point your DNS records to your server. HTTPS should be handled by automatically handled by Caddy in the background.

Bonus: Setting up a health check endpoint

If you set up a health check endpoint you can use a monitoring service (I can recommend UptimeRobot as it’s free and I’ve never had any problems with them) to get notified if you server for whatever reason becomes unavailable and would stop handling redirects.
For that we configure another Virtual Host and tell it to respond with a hard-coded string:

healthcheck.example.com {
  respond "healthy"


That’s it. I hope I could solve at least one of your problems. 😉