How to Set Up Wildcard Subdomains in Apache

How to set up wildcard subdomains in Apache

How to set up wildcard subdomains in Apache

When I built a small multi-tenant SaaS side project, I needed every signed-up user to get their own subdomain automatically — alice.myapp.com, bob.myapp.com, and so on — without me manually creating a new virtual host every single time someone signed up. That’s exactly what wildcard subdomains solve. In this post, I’ll walk through exactly how I set up wildcard subdomain support in Apache.

What Wildcard Subdomains Are and Why They Matter

A wildcard subdomain setup lets a single Apache virtual host respond to any subdomain of a given domain — *.example.com — without needing a separate DNS entry or virtual host block for each one. Instead, Apache captures whatever subdomain was requested and can use it dynamically, often to route to user-specific content or pass it along as a variable to your application.

I use wildcard subdomains for:

Prerequisites

Step 1: Configure Wildcard DNS

The very first step happens at the DNS level, not in Apache. I add a wildcard A record:

*.example.com.    A    203.0.113.10

This tells DNS that any subdomain of example.com — one that doesn’t have its own explicit record — should resolve to my server’s IP. I verify propagation with:

dig random123.example.com +short

Step 2: Create a Wildcard Virtual Host

In Apache, I use a wildcard in the ServerAlias directive to catch all subdomains:


    ServerName example.com
    ServerAlias *.example.com
    DocumentRoot /var/www/example.com/public_html

    
        AllowOverride All
        Require all granted
    

    ErrorLog ${APACHE_LOG_DIR}/example.com_error.log
    CustomLog ${APACHE_LOG_DIR}/example.com_access.log combined

The ServerAlias *.example.com line is the key part — it matches every possible subdomain, from alice.example.com to staging.example.com, all pointing to the same document root and application.

Step 3: Enable the Site and Reload Apache

sudo a2ensite example.com.conf
sudo apache2ctl configtest
sudo systemctl reload apache2

Step 4: Capture the Subdomain Inside Your Application

Since all subdomains share the same DocumentRoot, your application needs a way to know which subdomain was actually requested. I do this by reading the Host header directly in my app code, or by using mod_rewrite to pass it along as an environment variable:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com$ [NC]
RewriteRule ^(.*)$ /index.php?subdomain=%1&path=$1 [L,QSA]

This captures whatever comes before .example.com (e.g., alice) and passes it into index.php as a query parameter, which my application can then use to load the right tenant’s data.

Step 5: Add SSL for Wildcard Subdomains

For HTTPS, I need a wildcard SSL certificate — a regular single-domain certificate won’t cover arbitrary subdomains. With Let’s Encrypt, wildcard certificates require DNS-01 validation instead of the standard HTTP validation:

sudo apt install -y certbot python3-certbot-apache
sudo certbot certonly --manual --preferred-challenges dns -d example.com -d *.example.com

Certbot will prompt me to add a specific TXT record to my DNS to prove domain ownership, since wildcard certs can’t be validated via a simple HTTP file check.

Once issued, I reference the certificate in my SSL virtual host:


    ServerName example.com
    ServerAlias *.example.com
    DocumentRoot /var/www/example.com/public_html

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

Step 6: Automate Wildcard Certificate Renewal

Since DNS-01 validation isn’t fully automatic out of the box (it requires a manual DNS TXT record unless you use a supported DNS provider plugin), I use a Certbot DNS plugin matching my DNS provider (Cloudflare, Route53, etc.) so renewal happens without manual intervention:

sudo apt install -y python3-certbot-dns-cloudflare
sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini -d example.com -d *.example.com

Real-World Example: Per-User Subdomains for a SaaS App

In my side project, every new signup automatically got username.myapp.com. There was no per-user Apache configuration at all — the wildcard vhost handled routing, and my application layer looked up which account matched the subdomain in the Host header, then served that user’s dashboard accordingly. Scaling to thousands of users required zero changes to Apache config.

Step 7: Reserving Certain Subdomains from Wildcard Matching

In a multi-tenant setup, I always need a handful of subdomains reserved for actual infrastructure — www, api, admin, mail — rather than letting them accidentally get treated as a tenant name. I handle this at the application layer, checking the captured subdomain against a reserved list before doing any tenant lookup:

RewriteCond %{HTTP_HOST} ^(www|api|admin|mail)\.example\.com$ [NC]
RewriteRule ^(.*)$ /system/$1 [L]

This rule intercepts those specific reserved subdomains and routes them to dedicated system logic before the generic wildcard tenant-lookup logic ever runs, which prevents someone from being able to register an account literally named “admin” or “api” and hijacking a reserved namespace.

Step 8: Testing Wildcard Behavior Thoroughly Before Launch

Before opening up per-user subdomains to real signups, I test a range of edge cases: subdomains with hyphens, numeric-only subdomains, unusually long subdomain names, and subdomains that collide with reserved words. I also specifically test what happens when someone requests a subdomain that doesn’t correspond to any real tenant, to make sure my application returns a clean “not found” experience rather than an ugly error page or, worse, leaking another tenant’s data by mistake.

Troubleshooting Common Issues

Subdomain doesn’t resolve at all This is almost always DNS — confirm the wildcard A record exists and has propagated with dig subdomain.example.com.

Subdomain resolves but shows the wrong content Check that ServerAlias *.example.com is present and that no more specific, conflicting vhost is intercepting the request first.

SSL certificate warning on subdomains This typically means a wildcard certificate wasn’t actually issued, or the certificate paths in the SSL vhost point to a non-wildcard cert.

Application doesn’t know which subdomain was requested Make sure your application (or the rewrite rule) is actually reading the Host header or the passed subdomain variable, not assuming a single static domain.

Security Best Practices

Performance Optimization Tips

Step 9: Handling Case Sensitivity and Normalization

Hostnames are technically case-insensitive, but I’ve still run into situations where inconsistent casing in a URL caused a subdomain lookup to fail because my application’s tenant lookup was doing a case-sensitive string comparison. I now normalize the captured subdomain to lowercase before using it anywhere in application logic:

RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com$ [NC]
RewriteRule ^(.*)$ /index.php?subdomain=${lc:%1}&path=$1 [L,QSA]

This requires defining an lc rewrite map earlier in the configuration using RewriteMap, but the underlying idea is simple: never trust that a hostname will arrive in a consistent case, and normalize it immediately before doing any lookups.

Frequently Asked Questions

Do I need a wildcard SSL certificate for wildcard subdomains? Only if you’re serving those subdomains over HTTPS, which you almost certainly should be. A standard single-domain certificate won’t cover arbitrary subdomains.

Can I mix wildcard subdomains with specific dedicated subdomains? Yes — Apache will match the more specific ServerAlias/ServerName first if one exists, falling back to the wildcard for everything else.

Does this work for nested subdomains like a.b.example.com? A simple *.example.com wildcard only covers one level. For nested subdomains you’d need *.*.example.com in DNS (not all DNS providers support this cleanly) and adjust your rewrite pattern accordingly.

Is wildcard DNS the same as wildcard SSL? No — they’re two separate things you need to configure independently: a wildcard DNS record routes traffic to your server, while a wildcard SSL certificate lets you serve that traffic securely.

Step 10: Planning for Subdomain Deletion and Cleanup

When a tenant closes their account, I make sure my application actually removes or deactivates their subdomain mapping rather than leaving it dangling. Since the wildcard vhost matches any subdomain by design, a stale tenant record left behind after account deletion could still resolve and potentially serve cached or orphaned content. I treat subdomain deactivation as a required step in my account deletion workflow, not an optional cleanup task.

Summary and Key Takeaways

Wildcard subdomains in Apache come down to three coordinated pieces: a wildcard DNS record, a virtual host using ServerAlias *.example.com, and — if you want HTTPS, which you should — a wildcard SSL certificate issued via DNS-01 validation. Once configured, this setup scales to essentially unlimited subdomains without touching Apache config again, which makes it perfect for multi-tenant applications.

References

Exit mobile version