Skip to main content

Custom Domains

Bring your own domain to Meshr and publish mesh-internal services on subdomains under it — app.example.com, grafana.example.com, api.example.com — each backed by a peer on your mesh and served over HTTPS through the Meshr tunnel.

Two steps, in order:

  1. Verify you own the domain — one TXT record, one time.
  2. Expose a service — create an Endpoint on a subdomain, add the per-subdomain CNAME it shows you.

Step 1 — Verify the domain

When you add a domain in Dashboard → Domains, Meshr generates a one-time verification token and asks you to prove ownership with a DNS TXT record. This happens once per domain.

Add this record at your DNS provider (Cloudflare, Route 53, Namecheap, etc.):

FieldValue
TypeTXT
Name_meshr-verify.<your-domain>
Contentmeshr-verify=<token-shown-in-the-dialog>

For example.com the record name is _meshr-verify.example.com. The content is the full meshr-verify=… string from the verify dialog — copy it verbatim, including the meshr-verify= prefix.

Once the record is live, click Try again in the dialog (or the Verify button on the domain row). Meshr looks up the TXT record and flips the domain to Verified.

DNS propagation

New TXT records can take anywhere from a few minutes to 48 hours to propagate, depending on your provider and the record's TTL. If verification fails immediately after you add the record, wait a few minutes and try again.

You can check whether the record is visible from the public internet before clicking Verify:

dig +short TXT _meshr-verify.example.com
# should print: "meshr-verify=…"

If dig shows the record but Meshr still reports "TXT record not found", the record is propagating unevenly across resolvers — give it a few more minutes.

Common verification problems

  • Record added on the wrong name. It must be _meshr-verify.<domain>, not <domain> or meshr-verify.<domain>. The leading underscore matters.
  • Provider appended the domain twice. Some DNS UIs auto-append the zone, turning _meshr-verify.example.com into _meshr-verify.example.com.example.com. Enter just _meshr-verify if your provider already scopes the record to the zone.
  • Quotes around the content. Enter the value without surrounding quotes; the provider adds them. The stored record should be exactly meshr-verify=<token>.
  • Wrong token. Each domain gets its own token. If you deleted and re-added the domain, the token changed — copy the current one from the dialog.

Step 2 — Expose a service

After the domain is verified, create an Endpoint on a subdomain (e.g. app.example.com) and pick the mesh peer + port that should serve it. Its detail page then shows a CNAME record to add:

FieldValue
TypeCNAME
Namethe subdomain (e.g. app)
Targettunnel.meshr.to

Each subdomain gets its own Endpoint and its own CNAME — app and grafana are independent, point both at the tunnel and Meshr routes each to its configured backend. TLS is terminated at the tunnel edge, so the service on your mesh peer doesn't need its own certificate.

Apex vs subdomain

Verification covers the whole domain — verify example.com once and you can expose any number of subdomains under it. The apex (example.com itself) can't be a CNAME due to DNS rules; publish on a subdomain (www, app, …) instead.

How it fits together

You own example.com


_meshr-verify.example.com (TXT) ← Step 1, once per domain
│ proves ownership

app.example.com (CNAME → tunnel.meshr.to) ← Step 2, per subdomain
│ routes to

a peer on your mesh, served over HTTPS

Removing a domain

Deleting a domain in the dashboard stops routing for every Endpoint under it immediately. The DNS records you added stay at your provider until you remove them — clean up the _meshr-verify TXT and any subdomain CNAMEs once you're done.