When working with wildcard subdomains in Nginx, you might need to redirect URLs like www.joe.domain.com
to their cleaner counterpart joe.domain.com
. This is particularly common in SaaS applications or multi-tenant systems where each user gets their own subdomain.
The key challenge is capturing the dynamic part of the subdomain (in this case "joe") while removing the "www" prefix. We need to handle this for any arbitrary subdomain name.
Here's the complete solution using Nginx's regex capture groups:
server {
listen 80;
server_name ~^www\.(?<subdomain>[^.]+)\.domain\.com$;
return 301 $scheme://$subdomain.domain.com$request_uri;
}
server {
listen 80;
server_name ~^(?<subdomain>[^.]+)\.domain\.com$;
# Your regular configuration here
}
The first server block catches all requests to www.*.domain.com
patterns:
~^www\.
- Matches "www." at the start(?<subdomain>[^.]+)
- Captures the subdomain name (any characters until a dot)\.domain\.com$
- Matches the domain suffix
The captured subdomain is then used in the 301 redirect to construct the clean URL.
After implementing, test with:
curl -I http://www.joe.domain.com
You should see a 301 response with the Location header pointing to http://joe.domain.com
.
If you're using SSL, make sure to duplicate this configuration for port 443 and include your SSL parameters:
server {
listen 443 ssl;
server_name ~^www\.(?<subdomain>[^.]+)\.domain\.com$;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
return 301 https://$subdomain.domain.com$request_uri;
}
The solution already preserves the entire request URI including path and query parameters through $request_uri
. For example:
http://www.joe.domain.com/path?query=string
will redirect to:
http://joe.domain.com/path?query=string
When dealing with multi-tenant applications or user-specific subdomains, we often need to handle dynamic subdomain rewrites. A common requirement is removing the "www" prefix from wildcard subdomains while preserving the dynamic portion.
Here's the complete solution using regex pattern matching and rewrite rules:
server {
listen 80;
server_name ~^(www\.)?(?<subdomain>[^.]+)\.domain\.com$;
if ($host ~* ^www\.(?<sub>.+)\.domain\.com$) {
return 301 $scheme://$sub.domain.com$request_uri;
}
# Additional configuration for non-www requests
location / {
# Your regular configuration here
}
}
The configuration works through these key components:
server_name ~^(www\.)?(?<subdomain>[^.]+)\.domain\.com$
- Matches both www and non-www variantsif ($host ~* ^www\.(?<sub>.+)\.domain\.com$)
- Captures the dynamic subdomain portionreturn 301
- Performs permanent redirect with HTTP 301 status
For more complex scenarios, consider these variations:
# SSL-enabled version
server {
listen 443 ssl;
server_name ~^(www\.)?(?<sub>[^.]+)\.domain\.com$;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
if ($host ~* ^www\.(?<subdomain>.+)\.domain\.com$) {
return 301 https://$subdomain.domain.com$request_uri;
}
}
# Preserving query parameters
if ($host ~* ^www\.(?<sub>.+)\.domain\.com(.*)$) {
return 301 $scheme://$sub.domain.com$1$is_args$args;
}
While if
in Nginx is generally discouraged, it's the cleanest solution for this specific pattern matching requirement. The performance impact is negligible for this use case compared to the alternative of duplicating server blocks.
Always verify your changes with:
sudo nginx -t
sudo systemctl reload nginx
Test using curl to confirm the redirect works as expected:
curl -I http://www.joe.domain.com
curl -I http://joe.domain.com