Custom Domains
Updated Oct 18, 2026
Overview
Custom domains let each business serve its booking page on a domain it owns — for example booking.acme.com — instead of the default your-app.com/acme (or acme.your-app.com) URL.
The feature is progressive and non-breaking: a newly added domain starts as Pending, the business keeps using its default booking URL the whole time, and traffic only switches to the custom domain once it is verified. A half-finished setup can never take a live booking page down.
Note: The app maps the full hostname to the business. Once
booking.acme.comis verified, it serves that business's booking page at the clean root — the URL slug is no longer needed.
There are two layers to make a custom domain work, and both must be in place:
| Layer | What it does | Who handles it |
|---|---|---|
| DNS | Points the domain at your server | The business owner (at their registrar) |
| SSL | A valid HTTPS certificate for the domain | You (the platform admin), via your hosting panel |
How a Business Connects a Domain
A business owner manages this from Business Panel → Account → Custom Domain:
- Enter the domain (e.g.
booking.acme.com) and click Add domain → status becomes Pending. - Follow the on-screen Step 1 (DNS) and add the record at their registrar.
- You (admin) issue the SSL certificate for the domain on the server (see Step 2).
- The owner clicks Verify. The app fetches
https://booking.acme.com/.well-known/slotline-verifyand confirms it returns the expected token — proving DNS, routing, and a valid TLS certificate in one check. - On success the status flips to Active and the booking page is live at
https://booking.acme.com.
Note: Verification is done over HTTPS on purpose. A passing check guarantees the certificate is valid — a DNS-only (TXT) check could not.
Step 1 — DNS
The business owner adds one record at their domain registrar. The panel shows both options with your server's values filled in:
| Type | Record | Points to |
|---|---|---|
| A (recommended) | booking.acme.com |
Your server's IP address |
| CNAME | booking.acme.com |
Your app host (e.g. your-app.com) |
Important: The record must be DNS only (unproxied). If the registrar has a proxy toggle (for example Cloudflare's orange cloud), turn it off — otherwise the SSL certificate cannot be issued and requests never reach your server correctly.
Prefer the A record for arbitrary customer domains: it points straight at your origin and is not affected by any CDN in front of your main domain.
Step 2 — SSL Certificate
A custom domain needs its own HTTPS certificate on your server. The application never issues certificates itself — you do it through your hosting environment. Pick the section that matches your setup.
cPanel / Plesk
- Add
booking.acme.comas an Alias / Addon domain pointing to the same document root as the app (thepublic/folder). - AutoSSL issues a free Let's Encrypt certificate automatically within a few minutes.
CloudPanel
CloudPanel is built around one domain per site, so the cleanest approach is a dedicated Reverse Proxy site per custom domain:
- Add the domain to your app site's backend
server_namein the Vhost (so nginx routes it to the app). - Sites → Add Site → Create a Reverse Proxy → Domain:
booking.acme.com, Reverse Proxy URL:http://127.0.0.1:8080(your app backend). - CloudPanel auto-issues a Let's Encrypt certificate for the domain.
Bare VPS / Docker (automatic)
For a fully self-serve, zero-touch experience, run Caddy with on-demand TLS in front of the app. A ready-made config ships with the product:
docker/caddy/Caddyfiledocker-compose.caddy.yml
Caddy fetches a Let's Encrypt certificate on the first request to any domain your app approves via the internal /internal/tls-check endpoint. The business owner just points DNS and clicks Verify — no admin step per domain.
# On a VPS where ports 80 and 443 are open to the internet:
docker compose -f docker-compose.yml -f docker-compose.caddy.yml up -d
Note: Ports 80 and 443 must be open to the world (Let's Encrypt validation + direct visitor traffic). Do not restrict them to a CDN's IP ranges, or DNS-only custom domains cannot be reached.
Behind Cloudflare
If your main app domain sits behind Cloudflare, keep custom domains out of it:
- Point each custom domain DNS only directly at your origin IP (A record). Do not CNAME it to your Cloudflare-proxied app host — Cloudflare will not serve a hostname it does not own, and you will get errors 1014 / 1016 / 525.
- Cloudflare can only proxy arbitrary customer domains if you configure Cloudflare for SaaS (Custom Hostnames) — a paid, optional add-on. It is not required when custom domains go straight to your origin.
Plan Gating
Custom domains can be limited to specific subscription tiers. In Super Admin → Subscription Plans, edit a plan and toggle Capabilities → Allow Custom Domain.
It is enabled by default so the feature works out of the box; turn it off on lower tiers to make custom domains a premium upsell. Businesses on a plan without the capability see an upgrade notice instead of the connect form.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| 525 SSL handshake failed | Record is proxied through Cloudflare, but your origin has no HTTPS cert for the domain | Set the record to DNS-only and issue the origin certificate |
| 530 / 1016 origin error | A proxied CNAME points at a Cloudflare-fronted host that can't be resolved | Use an A record → origin IP, DNS-only |
| "Could not reach the domain over HTTPS yet" | No valid certificate on the origin yet, or DNS still propagating | Issue the cert (Step 2), confirm curl -I https://booking.acme.com/ returns a response, then retry Verify |
| Verify keeps failing though the page loads in a browser | The record is still proxied, or the server can't reach its own public IP (hairpin NAT) | Set DNS-only; ensure the server can make outbound HTTPS requests to the domain |
| Wrong IP shown in the A-record instruction | Your app host resolves to a CDN edge | The panel uses the server's own bound/public IP; if it can't detect it, enter your origin IP manually |
Note: Quick sanity check before clicking Verify — from any machine run
curl -I https://booking.acme.com/. If it returns an HTTP response (not a connection or SSL error), Verify will pass.