✨ Made with Daftpage

How to implement the "custom domain" feature on your SAAS business?

I share the lesson learned while building this feature for my business.


What's the "custom domain" feature?


When using a website hosting service, you usually get a subdomain allocated by the provider.

But users might want to bind their custom domain to your service as it makes their website more credible and helps build an online reputation.



Context


I've recently released Daftpage, a cute landing page builder.

For this type of project, custom domain binding is a must-have.

In Dafpage every published website get a subdomain 

project-name.daftpage.com

Premium users can bind their custom domain to their website with SSL out of the box.



Vercel API 


Vercel has a limit of 50 custom domains/projects. This limit is a no-go as my project would serve thousands of websites!

So I contacted their sales services to see what they can do about it. 

Sadly it would cost thousands of dollars to increase the limit.


Screenshot of Vercel's response


I scrapped all the web, looking for an alternative solution but couldn't find one.

So I decided to build the service "from scratch".



Caddy 🥰


Luckily I came across Caddy

Caddy is an open-source, production-ready, server with automatic HTTPS certificate generation via Let's Encrypt.

The beauty of Caddy is its simplicity, in three lines of code, you get a reverse proxy with HTTPS automatically.

daftpage.local {
    reverse_proxy 127.0.0.1:4200
}

💡 I also use caddy in development to have HTTPS running through localhost



Building the feature (total cost: $5-$20/month)


What you'll need:

  • A remote server with SSH access and filesystem permission (I'm using a droplet on Digital Ocean 5$/month)

  • REDIS Database (Optional. I'm using a managed Redis instance on Digital ocean $15/month)

  • A web service to restrict HTTPS certificates generation (Optional but highly recommended as you could reach Let's Encrypt rates limit when robots crawl your websites)


By default Caddy stores the HTTPS locally.

To make the solution more scalable, I'm using the Redis module for storing the certificate. 

https://caddyserver.com/docs/modules/caddy.storage.redis

This way I can horizontally scale Caddy servers ⚡️


Caddyfile

{
    on_demand_tls {
      # ask option will make a GET request to the URL stored in $TLS_ASK_URL. The request contains a "domain" query parameter containing the requested domain name.
      ask {$TLS_ASK_URL}
      interval 1m
      burst 5
    }

    storage redis {
        key_prefix    "caddytls"
        value_prefix  "caddy-storage-redis"
        tls_enabled   "true"
    }
}


setup_caddy.sh

# load env variables
./setup_caddy_env.sh

# Install caddy
sudo apt-get install caddy
systemctl stop caddy

# Then remove default Caddy binary as we want the Redis module version.
rm /usr/bin/caddy
wget "https://caddyserver.com/api/download?os=linux&arch=amd64&p=github.com%2Fgamalan%2Fcaddy-tlsredis&idempotency=76843349100279" -O /usr/bin/caddy
chmod +x /usr/bin/caddy

rm /etc/caddy/Caddyfile
mv ./Caddyfile /etc/caddy/Caddyfile
systemctl start caddy


setup_caddy_env.sh

export CADDY_CLUSTERING_REDIS_HOST=XXX
export CADDY_CLUSTERING_REDIS_PORT=XXX
export CADDY_CLUSTERING_REDIS_USERNAME=XXX
export CADDY_CLUSTERING_REDIS_PASSWORD=XXX
export TLS_ASK_URL=https://...
export PROXY_TO_URL=https://...



Add a custom domain


To add a custom domain your customers must add records to their domain's DNS config. 

Two possibilities: A or CNAME record.

A record allows mapping root domains or subdomains to an IP address.

CNAME record allows mapping root domains or subdomains to another domain.


CNAME is preferable because it does not depend directly on the Caddy server's IP.

If you update the IP for some reason your users will not be impacted.


The tricky part is that certain domain providers don't allow creating CNAME for the root domain. In this case, users have to use A record.






And voilà! You should have all the materials to build the custom domain feature on your SAAS business.


More questions? Spotted an error or grammar mistakes? Shoot me an email georges@daftpage.com


Georges

Follow me on Twitter