Handling Wildcard Subdomains with Nginx and PHP

Wildcard subdomains let you catch any subdomain — username.yoursite.com, blog.yoursite.com, whatever.yoursite.com — and handle it dynamically in your application. They're the backbone of SaaS tenant routing, user profile pages, and multi-tenant platforms. The technique is simple: catch everything at the DNS level, tell your web server to accept it, and let your application figure out what to do with it.

Where wildcards still work

Not all DNS providers support wildcard records anymore. As of 2026:

  • Cloudflare — ✅ Supports wildcard A and CNAME records on all plans, including free
  • DNSimple, DNS Made Easy, Google Cloud DNS — ✅ Support wildcards
  • HE.net (dns.he.net) — ❌ Dropped wildcard support for free accounts years ago
  • Many shared hosting DNS panels — ❌ Block wildcards or require a support ticket

If your DNS provider doesn't allow wildcards, the easiest fix is to delegate your domain's nameservers to Cloudflare (free) or another provider that does. You don't need to use their CDN — just their DNS.


Step 1: Add the wildcard DNS record

Create an A record for * pointing to your server's IP. If you use Cloudflare, the orange-cloud proxy works fine — all subdomains route through their network. If you're running Cloudflare in front of your server, make sure you've configured Nginx to see real visitor IPs — the Cloudflare Real IP with Nginx guide covers that setup.

If your server is behind a CNAME (like a load balancer or a platform-as-a-service), use * as a CNAME instead, pointing to your primary domain.


Step 2: Configure Nginx to accept wildcard requests

Add *.yourdomain.com to your server_name directive:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name yourdomain.com www.yourdomain.com *.yourdomain.com;

    # ... SSL, root, and the rest of your configuration ...

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }
}

That's it — Nginx now accepts any subdomain under yourdomain.com and routes it to the same application. The server_name directive supports wildcards at the start of the domain only, not in the middle, but that's all you need for subdomain routing.

If you also want to catch requests with no hostname at all (raw IP hits), add an empty server block that drops them — otherwise your wildcard server block will catch those too.


Step 3: Detect the subdomain in PHP

Once the request reaches your application, grab the hostname and extract the subdomain:

$host = $_SERVER['HTTP_HOST'] ?? '';
$baseDomain = 'yourdomain.com';

// Strip the base domain and any trailing dot
$subdomain = rtrim(str_replace('.' . $baseDomain, '', $host), '.');

// $subdomain is now '' (empty = no subdomain), 'www', 'username', etc.

A more robust approach using a configurable base domain:

$host = $_SERVER['HTTP_HOST'] ?? '';
$baseDomain = 'yourdomain.com';

// Remove port if present (some dev environments include it)
$host = explode(':', $host)[0];

if ($host === $baseDomain || $host === 'www.' . $baseDomain) {
    $subdomain = ''; // Root domain — no subdomain
} elseif (str_ends_with($host, '.' . $baseDomain)) {
    $subdomain = substr($host, 0, -strlen('.' . $baseDomain));
} else {
    // Request doesn't match our domain at all — reject or redirect
    $subdomain = null;
}

Now you can route based on the subdomain:

switch ($subdomain) {
    case '':
    case 'www':
        // Homepage
        break;
    case 'blog':
        // Blog section
        break;
    case 'status':
        // Status page
        break;
    default:
        // Assume it's a user profile
        $profile = getUserBySubdomain($subdomain);
        if ($profile) {
            renderProfile($profile);
        } else {
            http_response_code(404);
            render404();
        }
}

Step 4: SSL coverage for all subdomains

If you're using Let's Encrypt, request a wildcard certificate so every subdomain is covered:

certbot certonly --dns-cloudflare \
  --dns-cloudflare-credentials ~/.secrets/cloudflare.ini \
  -d yourdomain.com -d '*.yourdomain.com'

Wildcard certificates require DNS-based validation (HTTP validation can't prove you control all subdomains). Certbot supports plugins for Cloudflare, DigitalOcean, and most major DNS providers. Without a wildcard cert, each subdomain would need its own certificate — which defeats the purpose of dynamic subdomains.


A note on modern use cases

The "username.yourdomain.com" pattern from 2009 still works, but it's less common today — most platforms now use yoursite.com/username instead (simpler DNS, no SSL complications, no wildcard certificate needed). Where wildcard subdomains still shine:

  • Multi-tenant SaaS: acmecorp.yoursaas.com — each tenant gets their own subdomain for branding, SSL, and isolation
  • Branch deploys: feature-x.staging.yoursite.com — automated preview environments per Git branch
  • Regional routing: eu.yoursite.com, asia.yoursite.com — route to different backends by subdomain

If you're building one of those, wildcard subdomains with Nginx and a wildcard SSL certificate are the cleanest way to do it.

Technical Audit Summary

This guide is maintained as part of a modular, SSL-first framework. The wildcard subdomain pattern described here has been verified against live traffic.

Last Audit: May 2026
Environment: Debian Trixie (13)
Nginx: 1.30.1
PHP: 8.5.6

Compatibility: The Nginx server_name wildcard syntax works on all versions. The PHP detection logic uses str_ends_with() (PHP 8.0+); for older versions, use substr() with a negative length check instead.

2026-05-21: Production audit — bumped Nginx to 1.30.1, PHP to 8.5.6. Added cross-link to the Cloudflare Real IP guide in Step 1 for users running Cloudflare in front of Nginx. Updated the PHP detection snippet to use str_ends_with() (cleaner than string-length math for PHP 8.0+ environments).