You're building something where every customer needs their own address — acme.yourapp.com, widgetco.yourapp.com, and so on — and there's no way you're going to open wordpress-missing-a-temporary-folder-upload-error" class="auto-link">cPanel's Zone Editor and add a new subdomain by hand every time someone signs up. That's exactly what wildcard DNS is for. It takes about fifteen minutes to set up correctly, but the failure modes (subdomains that resolve but 404, SSL warnings, one tenant's request accidentally serving another tenant's data) are the kind of thing that looks fine in testing and breaks the moment a real customer signs up at 2am. Here's how to do it properly on a VPS.

Symptom: Adding Subdomains One at a Time Doesn't Scale

If you're hosting a SaaS product, a white-label platform, or anything with per-customer subdomains, the naive approach is to add each one manually: create the DNS record, create the vhost, reload the web server, repeat. It works for your first five customers. It falls apart at fifty, and it's simply not viable for self-serve signups where a subdomain needs to exist within seconds of someone filling out a form.

The fix is a single DNS record that covers every possible subdomain, paired with a web server configuration that routes all of them to one application — which then figures out which customer it's serving from the hostname itself.

Step 1: Add the Wildcard DNS Record

You need one record that matches anything under your domain. Two options, depending on whether your VPS has a static IP:

Record typeHostPoints toWhen to use it
A*Your VPS IPv4 addressYou have a fixed IP on the VPS (the common case)
CNAME*Your main domain or an alias hostnameYou're behind a load balancer or CDN with a hostname target

In cPanel's Zone Editor (if your domain's nameservers point to SkyServer), add a record with the name field set to *.yourdomain.com and the value pointing at your VPS IP. If you manage DNS elsewhere — Cloudflare, your registrar's panel — the process is the same: host is literally the asterisk character, nothing else.

One thing that trips people up: a wildcard A record does not automatically cover the bare domain (yourdomain.com with no subdomain) or www. Those need their own explicit records if you want them pointed at the same place. It also won't override a more specific record — if you already have an A record for mail.yourdomain.com, that one wins over the wildcard for mail traffic specifically, which is usually what you want anyway.

Give it time to propagate before you start debugging anything else — usually under an hour, but TTL-dependent. Check with:

dig acme.yourdomain.com +short
dig random-string-that-cant-exist.yourdomain.com +short

If both return your VPS IP, the wildcard is live.

Step 2: Configure the Web Server to Accept Any Subdomain

DNS resolving is only half the job — your web server still needs a vhost that matches the wildcard, otherwise every request lands on the default server block and either 404s or serves the wrong site.

Nginx:

server {
    listen 80;
    server_name *.yourdomain.com;

    root /var/www/yourapp/public;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

Apache:

<VirtualHost *:80>
    ServerName yourdomain.com
    ServerAlias *.yourdomain.com
    DocumentRoot /var/www/yourapp/public
</VirtualHost>

Reload the service after editing (nginx -t && systemctl reload nginx, or apachectl configtest && systemctl reload httpd) and test with a few made-up subdomains to confirm the same app handles all of them.

Step 3: Identify the Tenant from the Hostname

This is the part that's outside the web server's job — your application needs to read the Host header on each request and map it to a customer. In practice that usually means pulling the first label off the hostname and looking it up against your tenants table:

// example, Node/Express style
app.use((req, res, next) => {
  const sub = req.hostname.split('.')[0];
  req.tenant = tenants.findBySubdomain(sub);
  if (!req.tenant) return res.status(404).send('Unknown workspace');
  next();
});

Reserve a short list of subdomains that customers can never claim — www, api, admin, mail, ftp, status, app — and check against it before letting a signup form create a tenant with one of those names. Skipping this step is how someone eventually registers as "admin" and your own dashboard becomes unreachable.

Step 4: Get a Wildcard SSL Certificate

A wildcard DNS record needs a wildcard SSL certificate to match — a normal Let's Encrypt certificate issued via HTTP validation won't cover *.yourdomain.com because it can't verify subdomains that don't exist yet. You need the DNS-01 challenge instead:

certbot certonly --manual --preferred-challenges dns \
  -d yourdomain.com -d "*.yourdomain.com"

Certbot will ask you to create a TXT record to prove domain ownership. If your DNS is hosted with a provider that has an API (Cloudflare, Route 53), use the matching certbot DNS plugin instead of the manual flow so renewals don't require you to babysit a TXT record every 90 days. If your domain's DNS lives in cPanel and you're hosting the sites there rather than on a bare VPS, our wildcard SSL for cPanel subdomains guide covers the AutoSSL side of this instead.

Common Mistakes

  • Forgetting the bare domain. The wildcard covers subdomains, not the root — add a separate A record for yourdomain.com itself.
  • Testing before propagation finishes. A "not found" error five minutes after adding the record is usually just DNS catching up, not a config problem.
  • Case-sensitive tenant lookups. Hostnames arrive lowercase from browsers but not always from every client — normalize before you query.
  • No rate limiting on subdomain creation. Without it, someone can script-generate thousands of tenant subdomains and hammer your DNS-dependent SSL renewal or your database.
  • Trailing dot or www mismatch in the certificate. Make sure the cert covers both yourdomain.com and *.yourdomain.com — they're treated as separate names by CAs, so you need both explicitly in the -d flags.

Prevention

Set a calendar reminder or a cron alert for certificate renewal if you're on the manual DNS-01 flow — wildcard certs don't auto-renew the way HTTP-validated ones do unless your DNS provider's API plugin is wired in. Log every new tenant subdomain as it's created so you have an audit trail if something starts resolving unexpectedly. And keep a small monitoring check that hits a random, definitely-non-existent subdomain every few hours and confirms it gets your app's "unknown workspace" response rather than a raw 404 or, worse, someone else's tenant data.

Frequently Asked Questions

Does a wildcard DNS record slow down resolution for real subdomains?

No. DNS resolution time is the same whether the match comes from a wildcard record or an explicit one — the lookup is a single query either way.

Can I use a wildcard subdomain with a shared cPanel hosting plan instead of a VPS?

Not in the same way. cPanel's subdomain and addon domain features are built around explicit entries, not runtime wildcard routing to a single app. If you need genuine wildcard subdomain behavior for an application, a VPS (or a dedicated server) is the right fit.

Will the wildcard record also cover something like sub.sub.yourdomain.com?

No. A single-level wildcard (*.yourdomain.com) only matches one label deep. foo.yourdomain.com matches; foo.bar.yourdomain.com does not. You'd need a separate wildcard record at that level if you need two-level subdomains.

What happens if two tenants try to register the same subdomain name?

That's an application-level concern, not a DNS one — enforce uniqueness on the subdomain column in your tenants table with a database constraint, and check availability before showing a signup form as successful.

Do I still need this if I'm using a service like Cloudflare in front of the VPS?

Yes, the wildcard DNS record still needs to exist (proxied through Cloudflare or not), and your origin web server still needs the wildcard server_name/ServerAlias block. Cloudflare just sits in front of the same setup — it doesn't replace it.