Freestyle Docs

Freestyle / Docs

Wildcard Domains

Serve every subdomain of a domain from Freestyle VMs with a wildcard certificate and DNS record.

A wildcard domain serves any subdomain of a domain you own — alice.example.com, bob.example.com, and anything else — without setting up each one in advance. It takes three pieces: a wildcard DNS record, a wildcard TLS certificate, and a mapping per hostname you actually serve.

The third one surprises people, so it is worth stating up front: a wildcard certificate is about TLS, not routing. Freestyle matches incoming requests to mappings by exact hostname. The wildcard means a new subdomain does not need to wait for a certificate; it does not mean traffic to an unmapped subdomain goes anywhere.

Delegate The Challenge Zone

All issuance is proven over DNS, so Freestyle has to be able to publish a challenge record under your domain. If you already set this up for an ordinary domain it is the same record and there is nothing more to do — Domain DNS covers it:

Type: NS
Name: _acme-challenge
Value: beta-dns.freestyle.sh

That gives Freestyle authority over _acme-challenge.example.com alone. The rest of your zone stays entirely under your control, and the delegation stays in place between renewals so certificates keep reissuing without you doing anything.

Delegate at the level you are certifying. A wildcard for *.example.com is proven at _acme-challenge.example.com; one for *.app.example.com is proven at _acme-challenge.app.example.com.

Request The Certificate

The domain you pass is the parent. Requesting a wildcard for example.com produces a certificate for *.example.com:

import { Freestyle } from "freestyle";

const freestyle = new Freestyle();

await freestyle.domains.certificates.createWildcard("example.com");

The delegation is checked immediately — if the NS record is missing or points elsewhere, the call fails and names the nameserver it expected. Issuance itself happens in the background once the check passes, so poll for it:

const certificates = await freestyle.domains.certificates.list();
const wildcard = certificates.find((c) => c.domain === "example.com" && c.wildcard);

console.log(wildcard?.active, wildcard?.notAfter);

Or from the CLI:

freestyle domain cert wildcard example.com
freestyle domain cert list

A wildcard covers exactly one label. *.example.com matches app.example.com, but not example.com itself and not a.b.example.com — nested subdomains need their own wildcard on the parent, *.b.example.com.

Point The Wildcard At Freestyle

Type: CNAME
Name: *
Value: beta-web.freestyle.sh

See Domain DNS for apex domains and for checking that the record resolves.

Map Each Hostname

Ownership carries down: verifying example.com lets you map any subdomain of it without verifying each one. But every hostname you serve still needs its own mapping, created when you know the hostname:

await freestyle.domains.mappings.create({
  domain: `${tenant}.example.com`,
  vmId,
  vmPort: 3000,
});

*.example.com is not itself a valid mapping domain — mappings name a real host. A request for a subdomain with no mapping is answered with a 404 by the edge, over a valid certificate.

What the wildcard buys you is the certificate: mapping a new subdomain normally triggers its own issuance, and that means an ACME round trip before the hostname serves traffic. Under a live wildcard the mapping is the only step, so a tenant hostname works the moment you create it.

When To Use One

Reach for a wildcard when subdomains are created programmatically and you cannot enumerate them ahead of time — per-tenant hostnames, per-branch preview environments, per-user sandboxes.

For a handful of fixed subdomains, skip it and let each mapping get its own certificate. That costs nothing extra to set up — the _acme-challenge delegation is required either way — it just means a new hostname waits on its own issuance before it serves.

esc