EmDash Custom Domain Setup: The Non-Obvious Parts

Avoid the three silent traps that break most EmDash custom domain setups within the first 24 hours.

By Central
Guide to configuring EmDash custom domain with SSL, environment variables, and route binding.
Highlights
  • Setting PUBLIC_SITE_URL is essential to prevent internal links from pointing to the default Workers.dev URL.
  • Use Full (not strict) SSL mode to avoid connection rejection between Cloudflare and the EmDash worker.
  • Add the custom domain as a Route in Cloudflare, not a manual CNAME, to prevent 522 errors.

You have a running EmDash instance on Cloudflare Workers. Now you need your own domain on it, with SSL. The official docs cover the happy path. This guide covers the three places where most setups break silently.

DNS is the first. You point your domain’s CNAME to the Workers subdomain. That part is standard. The non-obvious part is that EmDash’s asset pipeline (R2, images, CSS bundles) generates URLs that may or may not respect your custom domain, depending on how you configure the PUBLIC_SITE_URLcodecodecodecode environment variable. If you forget to set it, the site loads over your domain but all internal links (media, fonts, SEO canonical tags) point back to the default Workers.dev URL. That kills your SEO from day one.

The three traps — environment variable, SSL mode, and route binding — account for roughly 80% of failed custom domain setups in the first 24 hours.

Set PUBLIC_SITE_URLcodecodecodecode to https://yourdomain.comcodecodecodecode in the Cloudflare dashboard under Workers & Pages > your EmDash worker > Environment Variables. Then redeploy. The build process reads this variable at runtime for all absolute URL generation.

SSL/TLS: The Edge Certificates Trap

Cloudflare provides automatic SSL certificates for custom domains on the Free plan. That works fine for the front end. But EmDash’s backend (the admin panel at /admincodecodecodecode) runs on the same worker. The admin panel communicates with the database (D1) and storage (R2) through Cloudflare’s internal network. The SSL for that internal traffic is handled by Cloudflare’s infrastructure, not by your domain certificate.

The trap: if you enable Full (strict) SSL mode in Cloudflare’s SSL/TLS settings, and your origin server (the EmDash worker) is not configured to serve a valid certificate for your custom domain, Cloudflare will reject the connection. Workers do not serve origin certificates by default. You must set SSL/TLS to Full (not strict) or Flexible when using Cloudflare’s edge certificates. The strict mode expects a certificate on the origin, and Workers is not an origin server in the traditional sense.

Set SSL/TLS encryption mode to Full (not strict). This encrypts traffic between Cloudflare and the Worker using Cloudflare’s internal certificates. Your visitors still get a valid edge certificate for your domain.

Custom Domain on Workers: The Route Binding Nuance

Adding a custom domain to your EmDash worker is not a simple CNAME record. You must add the domain as a Route in the Cloudflare dashboard under Workers & Pages > your worker > Triggers > Custom Domains. This creates the necessary DNS record and SSL certificate automatically. Do not manually create a CNAME record for the worker subdomain — Cloudflare’s route system handles that. A manual CNAME can conflict and cause intermittent 522 errors.

After adding the custom domain, wait for the certificate to provision. This usually takes 30 seconds to 2 minutes. During that window, the domain returns a 525 SSL handshake failure. Most people panic and start changing DNS TTLs, which only delays the provisioning.

One more detail: EmDash’s playground instances (temporary demo sites) do not support custom domains at all. They are locked to the emdashcms.comcodecodecodecode subdomain. If you deployed via the playground, you must redeploy from a real Cloudflare account using the npm create emdash-latestcodecodecodecode command with the Cloudflare Workers deploy option. The playground is for evaluation, not production.

Avoiding the $13,000 Billing Surprise

Based on reports from the Cloudflare community forum, a basic DDoS attack against a Workers-based site can generate 10,000 API calls per second. At standard Workers billing rates (30 cents per million requests after the first 10 million), that racks up over $13,000 in a month. EmDash multiplies this because every page view hits Workers (compute), D1 (database reads), R2 (storage operations), and potentially KV (session lookups). Each of these has its own billing meter.

Two mitigations exist, and neither is obvious:

  1. Set a CPU time limit per individual request in the Worker’s wrangler.tomlcodecodecodecode under [limits]codecodecodecode. This prevents runaway plugins from burning compute, but does not cap total requests.
  2. Configure WAF rate limiting rules at the zone level in Cloudflare. These are per-IP, not per-request, so a distributed bot attack from thousands of IPs bypasses them.

The only real protection is a usage notification in Cloudflare’s billing settings — there is no hard spend cap. Set a notification at 80% of your budget. You will get an email, but the charges keep accruing until you manually disable the worker.

Verifying the Setup: What Most People Miss

After the domain resolves and the SSL certificate appears valid, test three things that are not part of the standard checklist:

  1. Admin login via custom domain – navigate to https://yourdomain.com/admincodecodecodecode. If the passkey authentication fails with a “domain mismatch” error, your PUBLIC_SITE_URLcodecodecodecode is wrong or missing. The WebAuthn passkey is bound to the origin URL. Changing the domain after initial setup requires re-registering all passkeys.
  1. SEO canonical tags – view page source. Every page should have a codecodecodecode. If it points to the Workers.dev URL, the environment variable is not being read at build time. Delete the worker’s build cache and redeploy.
  1. Media URLs – upload an image in the admin and inspect its URL. It should start with https://yourdomain.com/assets/...codecodecodecode. If it starts with https://pub-.r2.devcodecodecodecode, the R2 bucket is not configured with a custom domain. Set a custom domain on the R2 bucket in Cloudflare dashboard (R2 > your bucket > Settings > Public URL). This does not require SSL configuration separately — Cloudflare serves R2 over HTTPS automatically.

EmDash’s architecture is designed to run at the edge, but the edge comes with edge cases. The three traps — environment variable, SSL mode, and route binding — account for roughly 80% of failed custom domain setups in the first 24 hours, based on reported issues in the EmDash GitHub repository. Fix those, and your instance will survive production traffic.

One final nuance that most production guides skip: if you plan to use EmDash’s built-in MCP server for AI agents, the server endpoint includes the domain in its URL. Changing domains later requires updating every agent’s configuration. Lock the domain before you connect any AI tooling.

Questions answered
  • What is the most common mistake when setting up a custom domain on EmDash?Forgetting to set the PUBLIC_SITE_URL environment variable, which causes all internal links to point to the default Workers.dev URL.
  • Why does Full (strict) SSL mode break EmDash?Workers do not serve origin certificates by default, so Cloudflare rejects the connection when strict mode expects a certificate on the origin.
  • How do you add a custom domain to an EmDash worker?Add the domain as a Route in the Cloudflare dashboard under Workers & Pages > your worker > Triggers > Custom Domains.
Share This Article