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.
{primary.fa-info-circle} 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 |
A business owner manages this from Business Panel โ Account โ Custom Domain:
booking.acme.com) and click Add domain โ status becomes Pending.https://booking.acme.com/.well-known/slotline-verify and confirms it returns the expected token โ proving DNS, routing, and a valid TLS certificate in one check.https://booking.acme.com.{primary.fa-shield} Verification is done over HTTPS on purpose. A passing check guarantees the certificate is valid โ a DNS-only (TXT) check could not.
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) |
{danger.fa-ban} 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.
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.
booking.acme.com as an Alias / Addon domain pointing to the same document root as the app (the public/ folder).CloudPanel is built around one domain per site, so the cleanest approach is a dedicated Reverse Proxy site per custom domain:
server_name in the Vhost (so nginx routes it to the app).booking.acme.com, Reverse Proxy URL: http://127.0.0.1:8080 (your app backend).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.ymlCaddy 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
{primary.fa-server} 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.
If your main app domain sits behind Cloudflare, keep custom domains out of it:
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.
| 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 |
{primary.fa-check} 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.