Domain SDK
Providers

bunny.net custom domains

Add, verify, monitor, and remove customer hostnames on a bunny.net CDN pull zone with a typed server-side TypeScript adapter.

Scope and credentials

The adapter manages the custom hostnames of one bunny.net CDN pull zone. Set BUNNY_API_KEY and BUNNY_PULL_ZONE_ID; the pull zone ID is the numeric ID shown in the bunny.net dashboard URL, not the pull zone name.

domains.ts
import { createDomainClient } from "@opencoredev/domain-sdk";
import { bunny } from "@opencoredev/domain-sdk/bunny";

export const domains = createDomainClient({
  provider: bunny({
    apiKey: process.env.BUNNY_API_KEY!,
    pullZoneId: process.env.BUNNY_PULL_ZONE_ID!,
  }),
});

const domain = await domains.add("app.customer.com");

bunny.net account API keys are account-wide, so they can reach every zone on the account. Keep the key in server-only configuration and restrict who can read it.

DNS and certificates

Subdomains return a CNAME pointing at the pull zone's system hostname, normally <zone>.b-cdn.net. The adapter reads that target from the pull zone rather than assuming it, so a renamed zone still produces correct instructions.

Apex domains return an ALIAS to the same target. bunny.net publishes no fixed A record for pull zones, so the customer's DNS host must support ALIAS, ANAME, or CNAME flattening — Bunny DNS does, as do Cloudflare and Route 53.

Adding a hostname does not issue a certificate. bunny.net validates the hostname while issuing one, so the domain stays pending_dns until you call verify():

verify.ts
await domains.verify("app.customer.com");

verify() requests a free Let's Encrypt certificate over HTTP-01, which only succeeds once the routing record resolves to the pull zone. A failure comes back as a retryable VERIFICATION_FAILED error; when the certificate already exists the adapter skips the call so repeated verification cannot trip Let's Encrypt rate limits.

What active proves

bunny.net reports whether a hostname has a certificate, not whether its DNS still resolves. Certificate issuance is the strongest evidence the API offers, so the adapter reports active once a certificate exists — but that evidence is from issuance time. If a customer later points the record elsewhere, bunny.net keeps reporting the certificate and the domain keeps reading as active.

Treat active as "bunny.net accepted this hostname", not as a live reachability check. domain.verification.message states the same caveat. If your product needs to detect a customer breaking their DNS after setup, monitor the hostname itself; no bunny.net API field reports it.

Validation and SSL options

OptionEffect
allowDnsValidationPermits DNS-01 validation when a Bunny DNS zone exists for the hostname
forceSslRedirects HTTP to HTTPS for the hostname after verify() has issued its certificate

Wildcard hostnames such as *.customer.com can only be validated over DNS-01, so the adapter always uses it for them and they require the domain to be hosted on Bunny DNS.

forceSsl is applied during verify() rather than add(), because forcing HTTPS before a certificate exists would break the hostname.

Pull zone limits

The pull zone's own .b-cdn.net system hostname is excluded from get(), list(), and remove(), so customer domains never collide with it. bunny.net updates hostnames one request at a time and the adapter re-reads the pull zone after each mutation, so serialize domain changes for the same pull zone.

Official references: bunny.net API, add hostname, and SSL for custom domains.

Read next: Store domain state.