Use Caddy Server 2 For Multi-Tenant Apps

Published: 2022-12-10

Untitled

Building a multi-tenant app is complex. But Caddy makes it so much easier to manage. And the best part is it’s all free, so if you’re a builder and want to incorporate this knowledge or want to know how to get it done without spending tons of money on a Cloudflare enterprise plan, then this is how.

How does multi tenant TLS work?

Usually for a single domain, you get your certificate and call it a day. But with a dynamic site, with unknown domains & subdomains that certificate has to be generated on the fly. What we can do is use a reverse proxy server to do this.

Certificates for HTTPS only get listed if you pass certain challenges. In my particular case with Cloudflare, they needed a DNS challenge that required a Cloudflare api key. But to do that you need to install a very specific version of Caddy.

How To Install

The easiest way to install Caddy on your server is with XCaddy. This is basically required if you want and external hosting like Cloudflare or other providers. The plugin system XCaddy provides makes life a lot easier.

Follow:

  1. Make sure Go is installed (Caddy is written in Go) Guide

    Note: You must make sure to update to the latest version of Go, I couldn’t figure out why my Xcaddy builds were failing and had to update to the latest version.

  2. Follow  this guide to install Xcaddy 2. In your terminal now you can simply run:

xcaddy build — with github.com/caddy-dns/cloudflare3
  1. Now your build file is done, make sure to move it to the caddy directory it should be in /usr/bin4. Now you can start creating your Caddyfile

    Caddy server uses a config file just named ‘Caddyfile’ with no additional extensions. The syntax is pretty simple. You can immediately open a reverse proxy by listening to our localhost:5000 with reverse_proxy localhost:5000

  2. Below is my Caddyfile config I used for wildcard certs AND custom domains all with https.

    	example.com {
    	reverse_proxy localhost:5000
    	log {
    	format json
    	}
    	}
    
    	http:// {
    	redir https://{host}{uri}
    	}
    
    	*.example.com {
    	tls {
    	dns cloudflare {env.CLOUDFLARE_AUTH_TOKEN}
    	}
    
    	reverse_proxy localhost:5000
    	log {
    	format json
    	}
    	}
    
    	https:// {
    	reverse_proxy localhost:5000
    	tls {
    	on_demand
    	}
    	}

Let’s briefly go over the various options.

reverse_proxy [localhost:5000](http://localhost:5000) 

Here we will proxy any traffic to our server and serve whatever is on port 5000. Pretty simple, you can change it to whatever port you want. You can even serve static sites via folders with caddy.

*.example.xyz {
	tls {
	dns cloudflare {env.CLOUDFLARE_AUTH_TOKEN}
	}

Here’s our wildcard challenge that we will issue to Cloudflare. Under the hood, caddy will issue you a TLS based on a DNS challenge with a Cloudflare api token. You can store env variables in .bashrc so that your Caddyfile can access them.

http:// {
	redir https://{host}{uri}
	}

https:// {
	reverse_proxy localhost:5000
	tls {
	on_demand
	}
	}

Lastly let’s secure ALL the traffic that hits our server. We want a http -> https redirect.

There is a small gotcha here. If you don’t list your https endpoint as a tls ondemand, your custom domains will be served over plain http.

With this config you should be able to enable any custom domain from your website as a subdomain.

More options

As your application scales you can choose to add an endpoint to check if you need to issue a TLS cert to even further secure the traffic. (So any plain user can’t generate one)

https://miro.medium.com/max/1400/1*-rdMppPvAgwFDhJxvoymnQ.png

Of course, make sure to add Caddy to autostart with your server. You can configure this with a service file how you’d like.

Learn more

It turns out Hashnode itself uses Caddy for this exact problem. Wildcard Subdomains. This is a great read to understand more about it: here

Leave a like if you thought this was helpful. I definitely struggled for days setting this up, so I hope you can do it faster!

Home