Isha Labs Support

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.com is 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:

  1. Enter the domain (e.g. booking.acme.com) and click Add domain → status becomes Pending.
  2. Follow the on-screen Step 1 (DNS) and add the record at their registrar.
  3. You (admin) issue the SSL certificate for the domain on the server (see Step 2).
  4. The owner clicks Verify. The app fetches 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.
  5. 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

  1. Add booking.acme.com as an Alias / Addon domain pointing to the same document root as the app (the public/ folder).
  2. 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:

  1. Add the domain to your app site's backend server_name in the Vhost (so nginx routes it to the app).
  2. Sites → Add Site → Create a Reverse Proxy → Domain: booking.acme.com, Reverse Proxy URL: http://127.0.0.1:8080 (your app backend).
  3. 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/Caddyfile
  • docker-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.