Custom HTTPS Hostnames, One API Call

Fly announced that our API is now open to the public. One killer feature of the API is the ability to generate custom HTTPS hostnames for your legions of customers. We'll talk about the complexity of the problem this solves then show you how one API call can get you threaded to a global network with an automatically renewing Let's Encrypt TLS certificate. Let's check it out!

Give the People What They Want!

Let's say your Software-as-a-Service enables the creation of APIs, store-fronts, static pages, blogs or web platforms. When a user creates something within your service, you might generate a unique URL for them. Odds are you've seen this all over the place:,,,, It's personalized for the user but still nested within their domain.

Your users will want to bring their own custom hostnames. Their hostname is their brand and while they may love your service, a brand doesn't have as much penache coming from Generating a subdomain for them is one thing. Generating an automatically renewing, signed Let's Encrypt certificate for their custom hostname is another. If you have many customers, each with their own custom hostname, this can get complicated in a hurry.

If you're going to use Let's Encrypt on your own, Certbot is relatively slick option.

You install it on your server then provide it with a domain name. It generates a series of certificates...

goodroot@flyio:~ # ls /etc/letsencrypt/live/
cert.pem  chain.pem  fullchain.pem  privkey.pem

You then combine them...

DOMAIN='' sudo -E bash -c 'cat /etc/letsencrypt/live/$DOMAIN/fullchain.pem /etc/letsencrypt/live/$DOMAIN/privkey.pem > /etc/haproxy/ssl/$DOMAIN.pem'

... Make them available within a reverse-proxy like haproxy...

frontend www-https
  bind [PUBLIC_IP]:443 ssl crt /etc/haproxy/ssl/
  reqadd X-Forwarded-Proto:\ https
  default_backend web-backend

... Create a script for automatic renewals...

certbot renew --pre-hook "service haproxy stop" --post-hook "service haproxy start"
DOMAIN='' sudo -E bash -c 'cat /etc/letsencrypt/live/$DOMAIN/fullchain.pem /etc/letsencrypt/live/$DOMAIN/privkey.pem > /etc/haproxy/ssl/$DOMAIN.pem'

... For each and every domain that your users create -- ack! That could get out-of-hand in a hot minute. The Fly API was built to help with this problem.

We've written a guide to show you how to Load Balance HTTPS with Let's Encrypt if you want more insight into the Let's Encrypt experience.

(AP)I Cap'n!

Construct a call to the Fly API. Receive a preview url in reponse. Create a DNS record with the preview URL to confirm ownership. Once confirmed, boom! That's it -- HTTPS for everyone. In addition, their domain now has a fleet of global edge-servers behind it, making it faster. Let's put this in motion.

"The main thing about the API integration code is how little there is, like 15 LOC including the API adapter class and no additional libraries needed." -, Case Study

First, an organization creates an account within Fly. An organization contains many sites and a site can contain many hostnames. Let's say your organization is "CoolCats" and your site is "", a static site generator that provides neat templates and custom, globally load balanced HTTPS to its users.

Once you've created your organization, head to settings to generate a Personal Access Token.

It looks like this:


The token is key -- the key is the token! With it we can ignite the API. Of course, one would want to deploy much better token obfuscation then is being presented within this article. We're making it visual for clarity; keep it secret, keep it safe!


Let's head to your trusty command-line. We can use curl to breakdown the call we'd write into our applicaitions...

curl -H "Authorization: Bearer [FLY_PERSONAL_ACCESS_TOKEN]" -H "Content-Type: application/json" -X POST -d '{"data": { "attributes": { "hostname": "[NEW_HOSTNAME]" } } }'[SITE_NAME]/hostnames

First, we authorize against Fly. Next, we POST a JSON object to the API.

Our variables within the call are:

  • [FLY_PERSONAL_ACCESS_TOKEN], your unique account identifier
  • [NEW_HOSTNAME], any new hostname you'd like to serve through SSL
  • [SITE_NAME], the Fly site you're adding the new hostname under

All filled out, it looks like this:

curl -H "Authorization: Bearer 9f5e850b7d5fac5566aa35e5a3836df03eac4b3c79115e1f19d43d979ddada48"-H "Content-Type: application/json" -X POST -d '{"data": { "attributes": { "hostname": "" } } }'`

After a few milliseconds of churning and bubbling out pops:


Voila! Our preview hostname with HTTPS is ready: The URI pattern is the Fly URI pattern. Given that you could change services at some point, you might not want to send all of your user's domains generated by a third-party. If your DNS has an API, you can place an intermediate step to create your own preview domain.

When Fly responds with a domain, create a CNAME record for that domain within your DNS. That way, you can provide your user with a domain that's under your umbrella: instead of With this approach,if you change services you need only change your own set of records; your users create a CNAME for their custom domain using your domain instead of Fly's.

Once the preview hostname has been provided to your end-user, you can instruct them to check it out, make sure it looks good, then create a DNS record with it. For example, the following record types would be supported by the hostname or your own custom one:

ALIAS: If their provider offers ALIAS records, it will look similar to this:

Record Name Content
ALIAS or @

ANAME: If their provider offers ANAME records, it will look similar to this:

Record Name Content
ANAME or @

Flattened CNAME: If they use CloudFlare, NameCheap, or 123-Reg, they can setup a flattened CNAME record. If they provider does not offer CNAME flattening, you may need to convert the URI into a IP address to set it at as an A Record.

Record Name Target
CNAME or @

That's it, that's all! Renewal, patching, load balancing -- all taken care of. With minimal effort, you can offer an exciting feature set to your customers: custom HTTPS hostnames and faster pages served from a global network over HTTP/2.

Fly started when we wondered "what would a programmable edge look like"? Developer workflows work great for infrastructure like CDNs and optimization services. You should really see for yourself, though.

Show Comments

Get the latest posts delivered right to your inbox.