Custom Domain
Point a custom domain at your LinkDen instance.
๐ Custom Domain Setup
Give your LinkDen instance a custom domain instead of the default *.workers.dev URLs. This is the recommended production setup: on a custom domain the web app and the API share one origin, so admin login works without any cookie or CORS tricks.
โก TL;DR
- Your domain must be a zone in your Cloudflare account, and the hostname must have no existing DNS record.
- Set
SITE_DOMAINand pointBETTER_AUTH_URL,NEXT_PUBLIC_SERVER_URL,CORS_ORIGIN, andNEXT_PUBLIC_SITE_URLat it. - Run
bun ship. Alchemy creates the Custom Domain (DNS + certificate) and the/api/*and/trpc/*routes. - Verify: the page loads over HTTPS,
/api/healthreturns"status":"ok", and/admin/loginstays signed in.
๐งญ How It Works
Alchemy does the wiring for you from a single variable, SITE_DOMAIN:
| Worker | What Alchemy creates |
|---|---|
linkden (web) | A Custom Domain on SITE_DOMAIN (DNS record + certificate) |
linkden-api (API) | Two Routes: SITE_DOMAIN/api/* and SITE_DOMAIN/trpc/* |
Cloudflare matches routes before the custom-domain Worker, so requests to /api/* and /trpc/* reach the API and everything else reaches the web app. There is no separate API hostname.
Without SITE_DOMAIN the deploy targets workers.dev, where the two Workers are different origins and /admin cannot hold a session. Treat workers.dev as staging only.
โ Requirements
- Your domain is a zone in your Cloudflare account (Cloudflare nameservers). If it is not yet, go to the Cloudflare dashboard โ Add a site, pick the Free plan, and switch your registrar's nameservers to the ones Cloudflare shows you. Propagation takes anywhere from 15 minutes to 24 hours.
- The hostname you choose must not already have a DNS record. Cloudflare creates the record when it attaches the Custom Domain and refuses to overwrite an existing A, AAAA, or CNAME. If something lives there today, delete that record first.
- Your
CLOUDFLARE_API_TOKENhas the Zone permissions listed in the Cloudflare guide: Workers Routes:Edit, Zone:Read, DNS:Edit, SSL and Certificates:Edit.
๐ Set It Up
-
Set
SITE_DOMAINand point every URL at it. In production all four URLs are the same value:SITE_DOMAIN=links.yourdomain.com BETTER_AUTH_URL=https://links.yourdomain.com NEXT_PUBLIC_SERVER_URL=https://links.yourdomain.com CORS_ORIGIN=https://links.yourdomain.com NEXT_PUBLIC_SITE_URL=https://links.yourdomain.comIf you deploy from GitHub Actions,
SITE_DOMAINandNEXT_PUBLIC_SITE_URLgo in as variables on theproductionenvironment; the rest are secrets. -
Redeploy:
bun shipThe deploy log lists the custom domain and the two routes as they are created. Certificate issuance usually finishes within a minute.
-
Verify:
https://links.yourdomain.comloads your link page with a lock icon.curl https://links.yourdomain.com/api/healthreturns"status":"ok", andcurl -Ion the same URL shows the API'sStrict-Transport-Securityheader, which proves the route won over the web Worker./admin/loginsigns you in and stays signed in.
๐ Apex Domains
An apex domain is yourdomain.com with no subdomain. Cloudflare Custom Domains support it directly (CNAME flattening is automatic), so SITE_DOMAIN=yourdomain.com works as long as the apex has no existing record. Most people still prefer a subdomain such as links.yourdomain.com so the apex stays free for a main website.
๐ External DNS
Custom Domains require the zone to be on Cloudflare DNS. If your DNS lives elsewhere (Namecheap, GoDaddy, Route 53, and so on), move the zone to Cloudflare first. The Free plan is enough, the registrar stays where it is, and switching the nameservers is the only change. Cloudflare imports your existing records when you add the site, so nothing else breaks.
๐ Changing or Removing the Domain
- Change: update
SITE_DOMAINand the four URLs, make sure the new hostname has no DNS record, and runbun ship. Alchemy removes the old domain and routes and creates the new ones. - Remove: unset
SITE_DOMAIN, point the URLs back at theworkers.devaddresses, and runbun ship. The DNS record Cloudflare created is deleted with the Custom Domain. - Roll back to a previous site on that hostname: re-create the old DNS record after removing
SITE_DOMAINand redeploying. Nothing else needs undoing.