Docs

Custom domains

Serve your deploy on your own hostname, like api.example.com, by adding one CNAME record to your DNS. You set it once and never touch it again.

Your hostname keeps working when we move your deploy between clusters, rebuild it, or replace the machine underneath it.

The four steps

  1. Claim the domain

    In the dashboard, open Domains and choose Claim domain. With the API, send POST /v1/organizations/{organization_id}/domains with {"domain": "example.com"}. The response includes challenge_record_name and verification_token.

  2. Prove you own it

    Publish a TXT record at the challenge_record_name you were given (_devlyft-challenge.example.com). Its value is the verification_token. Then click Verify now, or call POST /v1/organizations/{organization_id}/domains/{domain}/verify, or just wait, because we re-check periodically. You only do this once per domain. Every subdomain is covered too.

  3. Route a hostname to a deploy

    In Deployments, open a deploy's Routes and attach the hostname. With the API, send POST /v1/deploys/{deploy_id}/routes with {"hostname": "api.example.com", "path_prefix": "/"}. The hostname must be the claimed domain or a subdomain of it. The dashboard then shows the CNAME to publish. In the API response it's the cname_target field.

  4. Publish the CNAME

    api.example.com.   CNAME   d0c43d3885064d9a.edge.devlyft.io.

    Copy the target from the dashboard or from cname_target. Don't try to build it yourself. It's a digest of your hostname, so you can't work it out by hand.

Your certificate is issued automatically once the CNAME resolves to us. Until then the hostname won't serve HTTPS. Certificate issuance proves you control the name by answering a request on it, so it can't finish until your DNS points here.

Using Cloudflare? Set the CNAME to DNS only (grey cloud), not Proxied (orange cloud). Proxied records block certificate issuance. Details below.

Why the target looks like that, and why it never changes

cname_target is derived from your hostname alone. It isn't tied to a deploy, a cluster, a machine or a region, so none of those changing affects it. We change what that name resolves to, so you never have to edit your zone again.

Two consequences:

  • It is stable for the life of the hostname. Delete the route and create it again, or move the hostname to a different deploy, and the target stays the same. You don't need to publish it again.
  • It is per hostname, not per deploy. api.example.com and www.example.com get different targets. Each needs its own CNAME.

Cloudflare

If your DNS is on Cloudflare, set every CNAME that points at DevLyft to DNS only, the grey cloud in the Proxy status column. Don't use Proxied (the orange cloud).

  • Proxied records break certificate issuance. We issue your certificate with the HTTP-01 challenge, which means answering a request for your hostname at our edge. When the record is proxied, Cloudflare answers that request itself, so the challenge never reaches us and no certificate is issued.
  • Proxied records hide the target. A proxied record resolves to Cloudflare's own addresses, not to your cname_target. dig won't show you the target, so a proxied record looks as if it isn't set up.
  • Apex domains work when DNS only. An apex (example.com) can't hold a plain CNAME, so it needs CNAME flattening (see Apex domains). Cloudflare lets you create a CNAME at the apex and, with the record set to DNS only, flattens it automatically, answering with the addresses the target resolves to. Keep the apex record grey-clouded for the same reasons as any other.

To check your setup, run dig +short api.example.com. A DNS-only record returns your cname_target followed by an IP address.

Several deploys behind one hostname

You can split one hostname across deploys by path prefix, for example one deploy on / and another on /api. They share a single CNAME because the same cluster serves them.

Those deploys must be in the same environment and the same location. One hostname resolves to one cluster, so every deploy serving it has to be on that cluster. We check this when you attach the route. A hostname attached to a deploy in a different environment or location is rejected, so it can't end up half-working.

Several locations

To run the same environment in more than one location, give each location its own hostname, such as api.mia.example.com, api.lon.example.com and api.fra.example.com, with one CNAME each. Then handle geographic routing on top of those with whatever your DNS provider offers.

We don't currently serve one hostname from several locations at once.

Apex domains (example.com with no subdomain)

DNS doesn't allow a CNAME at the apex. It isn't a DevLyft restriction: the apex already holds the records that delegate your zone, and a CNAME can't sit alongside them. You have three options, best first:

  1. Use a subdomain. Use www.example.com or api.example.com, and redirect the apex to it at your registrar or CDN. It's the simplest option and what almost everyone does.
  2. Use your provider's ALIAS, ANAME or CNAME flattening if it has one. Cloudflare, Route 53, DNSimple and others do, under various names. On Cloudflare this happens automatically for a DNS-only apex CNAME (see Cloudflare).
    Make sure it follows more than one hop. Your hostname's target is itself a CNAME onto a cluster record, so resolving it takes two steps. Some flattening implementations only follow one and return nothing. Test before you rely on it: dig +short example.com should return an IP address, not a name and not an empty answer.
  3. Ask us for addresses to put in an A record. We provide these on request, and they're the last resort for a reason. An A record puts our address in your zone, so a change on our side needs a change on yours, which is exactly what the CNAME avoids. If you choose this option, expect us to ask you to update it now and then.

Things that will not work

  • Wildcard hostnames (*.example.com) are rejected when you attach a route. The method we use can't issue certificates for a wildcard, and a wildcard has no single target to point at. Route each hostname you actually serve.
  • Pointing at a cluster name you saw somewhere. Names like mia-0.edge.devlyft.io are internal and they move. cname_target is the only supported target.
  • Copying another hostname's target. Each target is a digest of its own hostname, so another hostname's target won't route yours.

When something is not working

  • dig api.example.com returns nothing. Your CNAME isn't published yet, or it hasn't propagated. Check that the target matches cname_target exactly, character for character.
  • It resolves to Cloudflare addresses, not your target. The record is proxied. Switch it to DNS only (see Cloudflare).
  • It resolves but HTTPS fails. The certificate hasn't been issued yet. It can't be issued until the name resolves to us, so this usually clears up on its own within minutes of the CNAME going live.
  • It resolves but serves the wrong thing, or 404s on some paths. If you've split the hostname across deploys by path prefix, check that every one of them is still exposed. A deploy that stops being exposed stops serving its paths, and the hostname keeps working for the others.
  • The dashboard says “DNS target pending…”. The deploy isn't publishing edge DNS yet, so there's no CNAME target to show. Reopen Routes in a little while. If it stays that way, contact us at info@devlyft.io.
  • Your deploy shows placement.state: PENDING. The deploy hasn't been assigned to a cluster yet, usually because your location doesn't have enough room for the environment. It retries on its own and you don't need to do anything. Contact us if it stays that way.