How to setup catch-all wildcard subdomain in Nginx

How to setup catch-all wildcard subdomain in Nginx
Photo by Shannon Potter / Unsplash

Let's say you have a problem. You are serving a SaaS-based software with each client needing to have their own subdomain setup. The easiest way is to point all of their DNS to the servers, right?

But how about your VirtualHost setup? Do I need to set up each subdomain's virtual host every time I add a new subdomain?

The answer is absolute no. We could always use a catch-all wildcard configuration, and in this article, I will try to show you how to set it up.

The Typical Setup

server {
        listen 80;
        listen [::]:80;
        server_name domain.com www.domain.com;

        root /var/www/domain.com/htdocs/;
        index index.html index.php;

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

        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_param SERVER_NAME domain.com;
                fastcgi_pass 127.0.0.1:9000;
        }

        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;
}
Typical nginx+php virtual host configuration

The code above shows a typical Nginx with PHP configuration. We will focus on a few variables to change, with the final result looking like this:

a.domain.com -> /var/www/domain.com/a/
b.domain.com -> /var/www/domain.com/b/

First, we need to change the server_name variable to accept wildcard subdomains. To do this, change the value with:

server_name	~^(?<subdomain>.*)\.domain\.com$;

With that, Nginx now by default accepts every subdomain request within this virtual host configuration.
Next, change which directory the directory points towards by using the $subdomain variable:

root /var/www/domain.com/$subdomain/;

When using PHP, sometimes I would like to capture the domain name using the default superglobal value $_SERVER['SERVER_NAME'] and use the fastcgi_param to help forward it to the application.

By doing that, we need to add a new variable initialization and change the fastcgi_param value.

set $server_name_full $subdomain.domain.com;
fastcgi_param SERVER_NAME $server_name_full;

In the end, your configuration should look like this:

server {
        listen 80;
        listen [::]:80;
        server_name	~^(?<subdomain>.*)\.domain\.com$;
        set $server_name_full $subdomain.domain.com;

        root /var/www/domain.com/$subdomain/;
        index index.html index.php;

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

        location ~ \.php$ {
                include snippets/fastcgi-php.conf;
                fastcgi_param SERVER_NAME $server_name_full;
                fastcgi_pass 127.0.0.1:9000;
        }

        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;
}

That's all you need to get started with setting up the catch-all subdomain config.
Feel free to give feedback or ask for help in the comments!

Subscribe to A Gema's Ramble.

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe