CloudPanel
β
Requirements
Before you begin, make sure:
Your Concord CRM is deployed and running on CloudPanel.
You have sudo/root access to the server or full access to the CloudPanel dashboard.
Letβs Encrypt is enabled and ports 80 and 443 are open.
SaaS module is installed and activated in Concord CRM.
π§ Goal
Allow your CRM to serve multiple tenants using:
Wildcard Subdomains
Custom Domains per Tenant
Auto-SSL for All Domains
βοΈ Step-by-Step Configuration
1. Install Concord CRM Correctly
When creating your site in CloudPanel:
Go to Sites > Create Site
Choose:
PHP (or Laravel)
Set domain:
yoursaas.com
Set Document Root to:
Click Create Site
β This sets up the base Laravel app with the proper public path.
2. Enable Wildcard Subdomain Support
π A. Configure DNS for Wildcard Subdomains
On your DNS providerβs dashboard, add:
AND
This ensures *.yoursaas.com
resolves to your CloudPanel server.
π B. Add Wildcard Domain in CloudPanel
Go to Sites > yoursaas.com > Domains
Click Add Domain
Enter:
Set Document Root to:
β
This allows all subdomains like tenant1.yoursaas.com
to point to your main Laravel app.
π C. Install Letβs Encrypt Wildcard SSL
Go to Sites > yoursaas.com > SSL/TLS
Select:
Letβs Encrypt
Check
*.yoursaas.com
βProvide a valid email
CloudPanel will verify DNS and install SSL
β οΈ Wildcard SSL uses DNS-01 validation. You may need to manually add TXT records at your registrar during verification.
3. Enable Custom Domain Support
When a client wants to use their own domain:
πͺͺ A. Ask Client to Point DNS
Client should add the following A record:
Optionally:
π§© B. Add Client Domain in CloudPanel
Instead of manually adding each client domain one by one, you can configure CloudPanel to support a catch-all domain setup, which routes any custom domain pointing to your server to the same Laravel app. This simplifies onboarding and eliminates the need for manual intervention every time a new client adds their domain.
βοΈ Steps:
Modify NGINX Configuration to Support Catch-All
Go to:
Sites > yoursaas.com > Manage > Web Server > Custom Configuration
Add the following inside your
server
block to capture all unknown hostnames:This sets a default fallback server that serves any domain not explicitly configuredβgreat for multi-tenant SaaS apps where clients add their own domains.
Ensure Laravel Handles Domain Mapping
Your Laravel app should extract the domain from the request and map it to the correct tenant (e.g., using middleware like
TenantIdentificationMiddleware
).Automate SSL Installation
Example using acme.sh:
Then reload NGINX:
π‘ All domains and subdomains share the same Laravel app.
π C. Enable SSL for Custom Domain
Go to Sites > yoursaas.com > SSL/TLS
Click Install Letβs Encrypt
Choose:
clientdomain.com
www.clientdomain.com
(optional)Enter a valid email
CloudPanel will automatically generate the certificates.
π SSL Renewal & Maintenance
CloudPanel handles auto-renewals for Letβs Encrypt
Just ensure:
DNS remains pointed correctly
No firewall blocks port 80 or 443
You can manually verify:
From SSL/TLS page in CloudPanel
Or with tools like SSL Labs
π§ͺ Testing the Setup
https://tenant1.yoursaas.com
Should route to the correct tenant
https://clientdomain.com
Should show the correct client tenantβs CRM
https://yoursaas.com
Should show default/root tenant
dig +short tenant1.yoursaas.com
Should return your server IP
curl -I https://clientdomain.com
Should return 200 OK
and valid SSL
π Troubleshooting
Subdomain not resolving
Check wildcard A
record at DNS provider
SSL error on custom domain
Ensure domain is added to CloudPanel & points to server
Wildcard SSL fails to install
Ensure TXT records are added properly during DNS-01 verification
π‘ Pro Tip
If you support many tenants with custom domains, consider automating the following using Laravel commands or cronjobs:
Auto-adding domains (via CloudPanel API or SSH)
Requesting/renewing SSL via CLI (
acme.sh
,certbot
, etc.)Updating NGINX config (if needed)
π MySQL Root Integration for Automatic Tenant Provisioning
The MySQL Root Integration allows the SaaS system to perform database-level operations using root or privileged MySQL credentials. This is essential when using a multi-database or isolated-database tenancy model.
π₯ Configuration Fields
Go to Settings > MySQL Root tab in your Concord CRM admin panel.
Provide the MySQL root credentials or privileged user credentials.
βοΈ How It Works
When creating a new tenant with the "Create a new database" or "I will provide my own credentials" option:
A new database is automatically created.
A new MySQL user is created (if enabled).
Required privileges are assigned to the user.
Credentials are securely used on the server side only.
π§ Fallback Behavior
If disabled or credentials aren't provided:
The system uses the current database connection from
.env
.Ideal for shared hosting or single-database (table-prefix-based) tenancy.
π‘οΈ Security Recommendations
You may use a dedicated MySQL user with scoped privileges instead of a root user.
Avoid reusing root credentials for other services.
Ensure secure access policies are enforced on your MySQL server.
Last updated