Go slowly   About  Contact  Archives

Auto SSL for custom domains at scale

Up to some scale, your SaaS will have to support white-label customers with their custom domains. And enabling SSL (TLS now actually) for them is a must. How to automate this process and support a large number of custom domains at scale? Behold for Caddy will come and save your day!

1. What is Caddy?

Caddy is an open-source web server with automatic HTTPS written in Go. Besides automatic HTTPS, it can also do HTTPS on demand and scale horizontally when using a shared storage system for certificates. Popular choices are Redis, Consul, S3 or DynamoDB.

2. How do Caddy work?

Our request flow will look like this:

Client (browsers) => Caddy server (auto & on-demand SSL) => Your proxy server (forward requests based on custom domains) => Your target server (do the real work)

Simple enough, eh? On localhost, Caddyfile looks like this:


tls internal {


Our proxy server looks like this:

package main

import (

func main() {
	remotes := map[string]string{
		"localhost":          "https://www.google.com",

	handler := func(w http.ResponseWriter, r *http.Request) {
		rawURL := remotes[r.Host]
		remote, err := url.Parse(rawURL)
		if err != nil {

		w.Header().Set("User-Custom-Domain", r.Host)
		r.Host = remote.Host

		proxy := httputil.NewSingleHostReverseProxy(remote)
		proxy.ServeHTTP(w, r)

	http.HandleFunc("/", handler)

	err := http.ListenAndServe(":8080", nil)
	if err != nil {

The target server here is google.com.

Now when you visit https://localhost, it will show google.com website. Google just got another custom domain from us with SSL!

Written on January 10, 2022.