Caddy: Custom Domains for SaaS


Building custom domains for your SaaS is not always easy, especially when certificates get involved.

With Caddy it becomes very easy!

On The Caddy Side

{
    email dns@marco.ninja
    # Caddy asks this endpoint if it shall handle traffic for a domain
    on_demand_tls {
        ask https://backend.local/internal/custom-domain-check/
    }
}


# Accept all domains that pass the ask endpoint
https:// {
    tls {
        on_demand
    }

    handle /.well-known/health {
        respond "200 OK" 200
    }

    reverse_proxy https://backend.local {
		header_down -server
	}
}

On The App Side

Simply implement a CRUD UI for your customer to add their custom domain.

Then add an endpoint that Caddy can ask if a domain is valid for it to serve, might look something like this:

from django.http import HttpResponse

from core.models import Project

def custom_domain_check(request):
    """Check if we are authorized to issue certificates for the given domain"""
    try:
        domain = request.GET["domain"].lower()
        Project.objects.get(custom_domain=domain)
    except:
        return HttpResponse(status=404)
    return HttpResponse(status=200)

Scaling and HA Considerations

  • Caddy can be scaled, if you give it a storage engine that is HA, might be easiest to use the one for the DB you are hosting already
  • Traffic into the Caddy instances needs to be balanced on layer 3, no CloudFlare CDN possible (at least not easily)

Tip

Need help getting your SaaS infrastructure and custom domains up and running?

I’m available for consulting.

caddy 

See also