Custom domains

on team pico's blog

it's as easy as a DNS entry
#feature, #announcement

It's been a pretty exciting week for us at the pico.sh headquarters.

We made it to the front-page of hackernews!

front-page of hacker news

We were so excited about the launched that we announced in the thread support for custom domains landed.

We figured it would be a good idea to officially announce it on our blog.

Add your custom domain today!

Don't want to be bored with the details of how custom domains work?

The full usage guide can be found on our help page.

How it works

We decided to go with a solution that didn't require us to store any information about the custom domain you want to use. Instead, all the user needs to do is add a TXT record and then point the domain with a CNAME to prose.sh.

Under the hood we use Caddy's on-demand tls. On our end, the configuration was very simple using Caddyfile:

{
	on_demand_tls {
		ask http://web:3000/check
		interval 1m
		burst 10
	}
}

:443 {
	reverse_proxy web:3000
	tls hello@prose.sh {
		on_demand
	}
	encode zstd gzip
}

The endpoint referenced in the above Caddyfile points to this golang function:

 1func checkHandler(w http.ResponseWriter, r *http.Request) {
 2	dbpool := GetDB(r)
 3	cfg := GetCfg(r)
 4
 5	if cfg.IsCustomdomains() {
 6		hostDomain := r.URL.Query().Get("domain")
 7		appDomain := strings.Split(cfg.ConfigCms.Domain, ":")[0]
 8
 9		if !strings.Contains(hostDomain, appDomain) {
10			subdomain := GetCustomDomain(hostDomain)
11			if subdomain != "" {
12				u, err := dbpool.FindUserForName(subdomain)
13				if u != nil && err == nil {
14					w.WriteHeader(http.StatusOK)
15					return
16				}
17			}
18		}
19	}
20
21	w.WriteHeader(http.StatusNotFound)
22}

This function does a couple of things. It gets the current domain from the request and then performs a TXT lookup via GetCustomDomain:

 1func GetCustomDomain(host string) string {
 2	records, err := net.LookupTXT(fmt.Sprintf("_prose.%s", host))
 3	if err != nil {
 4		return ""
 5	}
 6
 7	for _, v := range records {
 8		return strings.TrimSpace(v)
 9	}
10
11	return ""
12}

If the username matches then we respond with a success status. That's really all there is to it.

It's amazing how far we've come with TLS, isn't it?

Wrap up

This is just one of many features we have planned to make prose.sh awesome. We also have a handful of sibling services we are thinking about building.


Join our irc #pico.sh on libera or email us at ~erock/pico.sh@lists.sr.ht.

Be sure to subscribe to our rss feed to get the latest updates at team pico.