deplaneDocs Dashboard

Custom domains

Serve an app at your own domain, with HTTPS. Every app always keeps its own address at <app>.deplane.app.

Connect a domain

In the dashboard, open the app's Domains tab and add the hostname, or run deplane domains add www.example.com. Deplane shows the two DNS records to set at your DNS provider:

DomainRecords
A subdomain, such as www.example.comCNAME to <app>.deplane.app, and TXT _deplane-challenge.www.example.com with the value shown
A root domain, such as example.com (it cannot have a CNAME)A to Deplane's address, and TXT _deplane-challenge.example.com with the value shown

Deplane checks every 2 minutes for 48 hours (or press Check now). When DNS points at the app and the TXT value matches, Deplane routes the domain and gets a certificate from Let's Encrypt, usually within a minute: Waiting for DNS, then Issuing certificate, then Active. Certificates renew automatically.

Switch DNS on Cloudflare

If the domain's DNS is on Cloudflare, the CLI can set the records for you, show you the exact changes first, and undo them:

$ export CLOUDFLARE_API_TOKEN=...            # or pipe it in
$ deplane domains switch www.example.com --app shop --check   # preview, changes nothing
$ deplane domains switch www.example.com --app shop           # asks, then switches
$ deplane domains switch www.example.com --rollback deplane-dns-www.example.com-20261031-140501.json

The token. Create a Cloudflare API token at https://dash.cloudflare.com/profile/api-tokens with the Edit zone DNS template, and under Zone Resources pick only this domain's zone. The CLI reads it from stdin or CLOUDFLARE_API_TOKEN, never from a flag. It talks to Cloudflare itself, from your computer: the token is never sent to Deplane, never printed, and never written to a file. If the token can see more than one zone, the preview says so: a token for the one zone is safer. You can delete the token in Cloudflare when you are done. A piped token takes stdin, so the switch cannot ask its question there and needs --yes: run it with --check first to read the preview, or set CLOUDFLARE_API_TOKEN and answer the question in your terminal.

The preview (--check) shows the records now at the domain and at _deplane-challenge.<domain>, and each change with its reason:

If the domain is not on the app yet, the switch adds it first. A zone that is not active on Cloudflare yet (its nameservers are not Cloudflare's) is refused, and so is a name delegated to other nameservers: records there do nothing.

The switch asks for confirmation (--yes skips it; with --json the preview goes to stderr before the question), then:

  1. Saves the records as they are to deplane-dns-<domain>-<date>.json in the current folder, readable only by you, without the token, and flushed to disk. If the records changed while you were reading the preview, it stops instead (dns_records_changed).
  2. Adds the TXT record on its own, and waits (up to 3 minutes) until public DNS shows it. Nothing visitors see has changed yet.
  3. Changes the records at the domain in one request to Cloudflare's batch API, which applies them all together or not at all: a failure leaves the domain as it was. If the zone cannot use the batch API, the changes are made one by one, adding before removing wherever Cloudflare allows it, and the command says so.
  4. Waits (up to 5 minutes) for Deplane to verify the domain, and says when it has. Until Deplane sees the new records (a few minutes, or up to the old TTL where resolvers cached the old answer) and gets the certificate, HTTPS to the domain may show errors.

--no-wait skips both waits, with a warning. If a change fails, the command stops and shows the rollback command.

The rollback (--rollback FILE) puts the saved records back exactly: content, TTL, proxy setting and comment, in one batch where Cloudflare allows it. It deletes what the switch created, restores what it changed, and recreates what it deleted (with new Cloudflare ids; tags on deleted records are not saved), starting from the records as they are now, so it also undoes a switch that stopped part way and is safe to run twice. --check previews it. The domain stays on the app; remove it with deplane domains remove if you no longer want it.

The dashboard does not do this yet, so that the token stays on your computer: use the CLI. Other DNS providers are not supported yet; set the records shown above by hand.

Why the TXT record

A domain is connected only when DNS proves that whoever controls it chose this connection. The TXT value is new each time a domain is added, so it proves the records were set for this app and this team, not left over from an app someone deleted: nobody can take over a domain whose DNS still points at Deplane after its owner moved on.

The TXT record is needed to connect the domain. After that you may keep it or remove it: a connected domain stays connected while its CNAME names the app (or, for a root domain, its A record points at Deplane).

Re-checks

Deplane checks every connected domain again every 6 hours. If its DNS no longer points at the app, the domain shows DNS changed and your team gets an alert (Custom domain no longer points here). Deplane keeps serving it for 7 days, sends a second alert a day before the end, and then stops serving the domain and its certificate; it goes back to Waiting for DNS. When DNS points back at the app, it is served again on the next check. A DNS server that does not answer changes nothing.

If another Deplane team adds the domain and proves it with its own TXT value (the domain changed hands, and its new owner points it at their app), that team's app gets the domain at once and the old connection stops. Your team gets an alert (Custom domain taken over) saying what happened and what to check: anyone who can write the domain's _deplane-challenge TXT record while it points at Deplane can do this, so keep that record's DNS access to your own people.

Limits

Up to 10 custom domains per app, and your plan's number for the whole team, all apps together: 3 on Free, 5 on Hobby, 25 on Pro, 100 on Team (see limit_domains). A domain can be connected to one app on Deplane at a time. Deplane's own domains cannot be added. Removing a domain stops it serving the app right away; deleting an app frees its domains.

When a team removes a domain or deletes its app, another team cannot add that domain while its CNAME still points at the old app's address (domain_dangling): change the CNAME first. A deleted app's name stays reserved for its team for 90 days, so nothing that still points at <app>.deplane.app (DNS, OAuth callbacks, webhooks) reaches another team's app.

This page is also available as Markdown. AI agents can start at /llms.txt.