40% off Cloud Workspace for 24 months

Claim 40% off
FLYNODE
Applications

Wildcard Domains for Multi-Tenant Apps

Send every name under your domain to one app: add *.yourdomain.com once, create two DNS records, and every tenant subdomain works over HTTPS with no setup per name. Dashboard and API.

9 min readUpdated Nov 2, 2026FlyNode docs
Browse documentation

Need a hand?

Can't find your answer? Our team replies fast.

Contact support

A wildcard domain sends every name under your domain to one app. You add *.yourdomain.com once, create two DNS records, and from then on tenant-a.yourdomain.com, tenant-b.yourdomain.com and any other name you make up all reach the app over HTTPS. You don't add each name, you don't redeploy, and you don't wait for a certificate per name.

It is made for multi-tenant apps: a booking system, a store builder or a SaaS where every customer gets their own subdomain. Your app creates a tenant, and the tenant's address works straight away.

What you need

  • A Custom app on a Cloud Workspace, deployed from Git, a Docker image or a Dockerfile. One-click template apps and Server GTM containers can't have a wildcard.
  • A domain you control, and access to its DNS (Cloudflare, Namecheap, your registrar, anywhere that lets you add CNAME records).
  • The Developer role or higher on the account.

How it works

You create two records. The first sends visitors to FlyNode. The second lets FlyNode prove to Let's Encrypt that the domain is yours, so one certificate can cover every name under it.

RecordTypePoints toWhat it does
*.yourdomain.comCNAMEyour app's .flynode.io addressEvery name under your domain reaches the app.
_acme-challenge.yourdomain.comCNAMEa value FlyNode gives you, ending in .acme.flynode.ioProves the domain is yours and lets FlyNode get and renew the certificate for you.

FlyNode does nothing with your domain until the _acme-challenge record points at the value made for you. That record is the proof you own the domain. Nobody else can attach it to their app, and if someone added it before you without the record, adding it yourself takes it over.

The certificate is renewed automatically before it runs out, as long as both records stay in place.

Set it up in the dashboard

  1. Open your app and go to the Domains tab.
  2. Find the Wildcard domain card below your domain list. Type *.yourdomain.com and press Add wildcard. (Typing yourdomain.com works too.)
  3. The card shows the two records with their exact values. Press a value to copy it.
  4. Create both records at your DNS provider. On Cloudflare, set both to DNS only (grey cloud).
  5. Wait. The badge changes by itself: Waiting for DNS, then Getting certificate, then Active. When the records are right it usually takes a few minutes. You can press Check again at any time instead of waiting for the next automatic check.

When the badge says Active, open any name under your domain, for example https://test.yourdomain.com. It shows your app.

Already have a * record?

Many apps already have a * record pointing at their old host. Change its target to your app's .flynode.io address. Until you do, tenant names keep going to the old place, and the card says so once the certificate is ready.

Using Cloudflare's proxy (orange cloud)

The _acme-challenge record must always be DNS only. A proxied record hides the CNAME, and the certificate can't be issued.

We recommend DNS only for the * record too. If you want to keep it proxied, set Cloudflare's SSL/TLS mode to Full (strict). Because FlyNode can't see through the proxy, the card then shows a note that tenant names resolve to Cloudflare's addresses. That note is expected.

What each status means

StatusWhat is happeningWhat to do
Waiting for DNS (pending_dns)The _acme-challenge record is missing, points somewhere else, or is proxied. Nothing is routed yet.Create or correct the record. The reason under the badge says which.
Getting certificate (verifying)The proof record is right. FlyNode now routes the names and is asking Let's Encrypt for the certificate.Nothing. It usually takes a few minutes.
Active (active)The certificate is issued and every name under the domain reaches your app.Nothing. If a note appears under the badge, read it: it tells you about a missing or changed record.
Failed (failed)No certificate after 30 minutes, or the certificate stopped being served.Check both records, then press Check again. That gives it another 30 minutes.

FlyNode checks a wildcard every 2 minutes until it is active, then once a day. A wildcard that has waited for DNS for more than 3 days is checked once an hour.

What it covers, and what it doesn't

  • One level only. tenant-a.yourdomain.com works. a.b.yourdomain.com doesn't, because a wildcard certificate covers one level. If you need names one level deeper, add a wildcard for that level too, for example *.eu.yourdomain.com.
  • Not the domain itself. yourdomain.com isn't covered by *.yourdomain.com. Add it as a normal domain (see Custom Domains for Your Apps).
  • Exact domains win. If a name under the wildcard is also added as a normal domain, on this app or another of your apps, the normal domain decides where it goes. That's how you send one tenant somewhere else.
  • Up to 5 wildcards per app. Each one has its own records and its own certificate.
  • Names that start with a letter or digit and contain only letters, digits and hyphens. Upper and lower case both work.

Telling tenants apart in your app

Every tenant name reaches the same app, with the name the visitor typed in the request's Host header. Read the first part of it to know which tenant to show. For example, a request for tenant-a.yourdomain.com arrives with Host: tenant-a.yourdomain.com. Answer names you don't know with a 404 or a "this page doesn't exist" screen, since any name under the domain will reach you.

Use the API

Everything above can be done from a script or your own backend with an API token.

1. Create a token

Go to Settings → API tokens. Choose Deploy access to add, list and check wildcards, or Full to also remove them. Under Workspace, pick the Workspace your app runs in so the token can't reach anything else. Copy the token: it starts with fn_live_ and is shown only once.

Send it with every request:

Authorization: Bearer fn_live_...

2. Find your app's ID

It's the last part of the address when the app is open in the dashboard: app.flynode.io/deployments/<app-id>. GET https://api.flynode.io/api/deployments also lists your apps with their IDs.

3. The endpoints

Method and pathWhat it doesToken access
GET /api/deployments/{appId}/wildcard-domainsList the app's wildcards with their status, reason and DNS records.Read only or higher
POST /api/deployments/{appId}/wildcard-domainsAdd a wildcard. Body: {"domain": "*.yourdomain.com"}. Returns 201 when new, 200 with the same wildcard when it was already on this app.Deploy or Full
POST /api/deployments/{appId}/wildcard-domains/{id}/verifyCheck the records and the certificate now. Returns the wildcard as it stands after the check.Deploy or Full
DELETE /api/deployments/{appId}/wildcard-domains/{id}Remove the wildcard. Its names stop reaching the app within seconds.Full

All paths are on https://api.flynode.io.

Example: add a wildcard

curl -X POST https://api.flynode.io/api/deployments/APP_ID/wildcard-domains \
  -H "Authorization: Bearer fn_live_..." \
  -H "Content-Type: application/json" \
  -d '{"domain": "*.yourdomain.com"}'

The answer:

{
  "id": "cmx1k2...",
  "domain": "*.yourdomain.com",
  "status": "pending_dns",
  "reason": "Add the _acme-challenge CNAME record shown below.",
  "dnsRecords": [
    { "type": "CNAME", "name": "*.yourdomain.com", "value": "your-app.flynode.io" },
    { "type": "CNAME", "name": "_acme-challenge.yourdomain.com", "value": "3f9a1c0d7e2b5a64.acme.flynode.io" }
  ],
  "activeAt": null,
  "lastCheckedAt": "2026-11-02T12:17:44.000Z",
  "createdAt": "2026-11-02T12:17:44.000Z"
}

Create the two records in dnsRecords at your DNS provider. If your DNS is on Cloudflare, you can create them with Cloudflare's own API in the same script. Then read the list every minute or so until status is active, or call verify when you know the records are in. Calling add again with the same domain is safe: it returns the wildcard you already have.

Example: check it

curl -X POST https://api.flynode.io/api/deployments/APP_ID/wildcard-domains/WILDCARD_ID/verify \
  -H "Authorization: Bearer fn_live_..."

verify can be called once every 30 seconds per wildcard. Sooner returns 429.

Errors

Errors come back as JSON with the HTTP status and a message you can show to a person:

{ "statusCode": 409, "message": "*.yourdomain.com is already attached to another app.", "error": "Conflict" }
StatusMessageWhat it means
400Enter a domain like *.yourdomain.com (no https:// or path).The domain isn't a plain domain name.
400That address belongs to FlyNode. Use a domain you own.Names under flynode.io can't be used.
400An app can have up to 5 wildcard domains.Remove one first.
400Wildcard domains work on Custom apps (Git, Docker image or Dockerfile). This app type is not supported.The app is a one-click template or a Server GTM container.
400This app has nothing to attach a domain to yet.The app hasn't been created on the server yet. Wait for its first deploy.
400This app needs its FlyNode address before a wildcard can point at it.The app has no .flynode.io address. Contact support.
400Wildcard domains are not available on this app's server yet. Contact support.The app runs on a server that isn't set up for wildcard certificates.
401UnauthorizedThe token is missing, wrong, expired or revoked.
403This token does not have the "deploy" scope. (or "destroy")The token's access is too low: Read only can't add, and Deploy can't remove.
403This token is limited to another Workspace.The token was made for a different Workspace than the app's.
404Deployment not found.Wrong app ID, or the app isn't yours.
404Wildcard domain not found.Wrong wildcard ID, or it belongs to another app.
409*.yourdomain.com is already attached to another app.Another app proved this domain first. Remove it there, or contact support if it isn't yours.
409A domain under yourdomain.com is already used by another account.Someone else has a name under this domain as a normal domain. Contact support.
429Wait a few seconds before checking again.verify was called less than 30 seconds after the last call.

Remove a wildcard

Press the bin icon on the card, or call DELETE. Every name under the domain stops reaching the app within seconds. Normal domains you added stay as they are. Then delete the two DNS records, or point the * record somewhere else.

Troubleshooting

  • Stuck on Waiting for DNS. Look up the record with dig CNAME _acme-challenge.yourdomain.com or an online DNS checker. It must show the exact value from the card. On Cloudflare, check it's grey-clouded. New records can take a few minutes to be seen.
  • "points at your-app.flynode.io" or the reason names your app's address. The _acme-challenge record is missing, so your * record answers in its place. Add the _acme-challenge record; it takes priority over *.
  • Failed after 30 minutes. Check both records, then press Check again. If it fails again, contact support with the domain name.
  • Active, but a tenant name shows another site. The * record still points at your old host, or that one name has its own DNS record that wins over *. Remove or change that record.
  • Active, but one tenant name shows a FlyNode error page. The name has two levels (a.b.yourdomain.com), or your app itself isn't answering. Open the app's .flynode.io address to check the app.

Still stuck?

Open a support ticket from your dashboard and include the container name.

Contact support