Appearance
Public DNS with Cloudflare
This is the one-time setup that makes *.by-managed.works names resolve. It's for whoever runs the managed.works control plane (the ui/ app) — not something an end user of the CLI does. Until it's set up, everything else still works; the app just skips publishing public DNS records.
You need a domain in Cloudflare (e.g. by-managed.works) and about five minutes.
1. Add the domain to Cloudflare
If it isn't already there: Cloudflare dashboard → Add a site → enter your domain → follow the steps to point your registrar's nameservers at Cloudflare. Wait until the zone shows Active.
2. Create a scoped API token
Dashboard → My Profile → API Tokens → Create Token → Create Custom Token:
- Permissions:
Zone→DNS→Edit - Zone Resources:
Include→Specific zone→ your domain - Create the token and copy it (you only see it once).
3. Find the Zone ID
Open the domain in the dashboard → Overview → copy the Zone ID from the right-hand sidebar.
4. Set two environment variables on the control plane
bash
CLOUDFLARE_API_TOKEN=<the token from step 2>
CLOUDFLARE_ZONE_ID=<the Zone ID from step 3>Set them wherever the ui/ app runs (your host's env, the platform's secrets, a .env). That's it — on the next managed apply, the app publishes an A record for every internet-facing service to the node's public (or reserved) IP, and removes records for services you delete.
How it fits together
- The CLI decides which names exist and where they point — it writes them to
state.public_dns_recordson every apply (only for services whose port isfrom: public, only on a connected project). - The control plane (
ui/app/lib/dns.ts, called from the state-sync route) pushes that set to Cloudflare, tagging each record withmanaged:<projectId>so it only ever touches records it created. - Names follow
<service>.<project>.<account>.by-managed.works, where<account>is your org slug and<project>is the project name slugified.
Notes
- Different domain? Set
network.public_dns_zoneinmanaged.yamlto the zone you host, and pointCLOUDFLARE_ZONE_IDat that zone. - Wildcard / proxy: records are created un-proxied (grey cloud) with a short TTL so they track IP changes. If you want Cloudflare's proxy, enable it per record or adjust
proxiedindns.ts. - Private services (databases) never get a public record — by design, a public name pointing at a firewalled port would be useless. Use the internal
*.managed.internalnames for those (no Cloudflare needed; see Networking & DNS).