Fix nginx default server catching request to subdomain

A step-by-step guide to diagnosing why nginx routes a subdomain to the default server and fixing the fall-through with config verification and safe reload.

Rao Aadil, India 7 min read

Confirm the symptom: Is the default server catching the subdomain request?

When a request to subdomain.example.com returns the default nginx page, that is nginx's default server catching the subdomain request. First confirm nginx is serving the request and inspect the response.

Use curl -I http://subdomain.example.com on Linux, or run Invoke-WebRequest -Method Head http://subdomain.example.com in Windows PowerShell. Both print response headers. Look for the Server header to verify nginx is answering. If the body or headers show the nginx welcome page, the request reached nginx but no server block matched the Host header.

Fetch the page content directly with curl http://subdomain.example.com on Linux or Invoke-WebRequest http://subdomain.example.com on Windows. If you see the default nginx page from /usr/share/nginx/html on Linux or C:\nginx\html on Windows, fall-through to the default server is likely.

Dump the active configuration next.

On Linux:

sudo nginx -T

On Windows, from the nginx installation directory in an elevated prompt or PowerShell:

cd C:\nginx
.\nginx.exe -T

This prints the full merged configuration in the order nginx loads it. Search for a server_name line containing your subdomain. If that block does not appear, nginx never loaded it. If it appears but is not first or lacks an exact match, the request may still hit another server.

Doing this with brynko devOps Agent

“A new domain lands on the welcome page instead of your app, and the config looks right.”

It checks the server_name matching, whether the site is enabled, and whether the default server is catching the request first, which is what usually happens.

It reads the real state of the server before it says anything, shows you the exact command, and waits for your approval. Windows and Linux, over the SSH access you already have.

Download for WindowsSee what else it does

Find the cause: Why does nginx fall through to the default server?

Nginx chooses a server block for each request using the Host header and the listen directives. When no server block matches the hostname, nginx uses the default server for the port. Several configuration mistakes cause this.

The server_name does not match the request host. The server block value must exactly match the hostname, or match via a wildcard or regex. Missing dots, stale domains, and typos like subdomain.example.com in the file but subdomain.example.com in the request are common. Open the intended config file and compare it character by character.

The default_server flag is set on the wrong block, or no default is explicitly defined. For every listen port, nginx chooses one default server: the block with the default_server flag on its listen line, or the first server block for that port if no flag is present. If another block appears earlier and has default_server, that block answers unmatched requests, even if your subdomain block exists. Run nginx -T and inspect every listen line for ports 80 and 443.

The site is not actually enabled. On Debian/Ubuntu, files in /etc/nginx/sites-available/ are only loaded if a symlink exists in /etc/nginx/sites-enabled/. Check with:

ls -l /etc/nginx/sites-enabled/

On RHEL/CentOS, the main /etc/nginx/nginx.conf usually includes files from /etc/nginx/conf.d/. On Windows, the default C:\nginx\conf\nginx.conf typically has an include conf.d/*.conf; line, or a similar include for your configuration directory. Verify the include line exists and the file is in the included path. On Windows, view the include lines with:

type C:\nginx\conf\nginx.conf

A duplicate server_name or load order issue. If two server blocks contain the same server_name, nginx uses the one that appears first in the merged configuration. The same can happen if a wildcard or regex block earlier in the config captures the hostname before your exact match block. Exact server_name matches have the highest priority, but a missing exact match due to a typo or an unloaded file forces nginx to fall back to wildcard, regex, or the default server.

Use nginx -T to view the final load order. The output is the merged config exactly as nginx parsed it, so it resolves include ambiguity.

Fix the configuration: Make the subdomain block match and take precedence

After identifying the cause, edit the configuration file. On Linux, the subdomain block is often in /etc/nginx/sites-available/subdomain.example.com or /etc/nginx/conf.d/subdomain.conf. On Windows, a typical path is C:\nginx\conf\conf.d\subdomain.conf.

Correct the server_name directive to the exact hostname:

server {
    listen 80;
    server_name subdomain.example.com;
    # other directives
}

Make sure the file is actually included. On Debian/Ubuntu, create the symlink if missing:

sudo ln -s /etc/nginx/sites-available/subdomain.example.com /etc/nginx/sites-enabled/

On Windows or RHEL/CentOS, confirm nginx.conf includes the directory where your file lives. If not, add or uncomment an include line such as:

include conf.d/*.conf;

If you have an explicit catch-all block, place default_server only on that block, not on the subdomain block:

server {
    listen 80 default_server;
    server_name _;
    return 444;
}

The subdomain block then matches its server_name; all unmatched requests go to the catch-all.

Test the configuration before reloading. On Linux:

sudo nginx -t

On Windows, from the nginx directory in an elevated prompt or PowerShell:

cd C:\nginx
.\nginx.exe -t

Only proceed if the output includes syntax is ok and test is successful. Then reload. On Linux, prefer a root-owned wrapper script if you have one; otherwise use:

sudo systemctl reload nginx

or, if you must signal nginx directly:

sudo nginx -s reload

On Windows, run from an elevated prompt or PowerShell:

cd C:\nginx
.\nginx.exe -s reload

After reloading, test the subdomain again with curl -I http://subdomain.example.com on Linux or Invoke-WebRequest -Method Head http://subdomain.example.com on Windows. Expect your application's response headers, not the nginx welcome page.

Prevent recurrence: Validate and enforce default server best practices

Make defaults explicit to avoid this later.

Always define an explicit default server for each listen port. A minimal catch-all block like the one above can live in /etc/nginx/conf.d/000-default.conf on Linux or C:\nginx\conf\conf.d\00-default.conf on Windows. The 000- or 00- prefix ensures it loads first—convenient but not required; the default_server flag does the real work.

Keep server names unique. After every configuration change, review the rendered config with nginx -T and search for the server_name lines. This catches duplicates and missing include lines before a reload.

Set up a pre-reload check that runs nginx -t automatically and refuses to reload on failure. A wrapper script or configuration management tool can enforce this. On Windows, the same nginx.exe -t and nginx.exe -s reload commands work in scripts and CI; directive syntax is identical to Linux, only file paths and invocation differ.

Document which domain maps to which server block and which block is the default for each port. When adding a new subdomain, follow the same pattern: exact server_name, no default_server on application blocks, test, then reload.

If you manage several servers, a tool that can test the config with nginx -t before any reload, identify which config file actually serves the domain across sites-available, sites-enabled, and conf.d, tail the access and error log for the specific request, and reload safely via root-owned wrapper scripts can shorten this loop. It does not edit the server block for you; you still correct server_name or default_server in the file.

Related reading

Stop nginx default server catching subdomain requests

Get a tool that tests nginx configs before reload, finds which config file actually serves a domain, and tails the right log for the failing request.

An AI teammate that builds, runs, fixes, deploys and operates your software, on your machine and on your servers. It reads the real state of your systems, shows you every command before it runs, and never touches production without your approval.

Works with Docker Docker Compose nginx IIS Tomcat MySQL / MariaDB PostgreSQL Redis Linux servers Windows servers AWS Jenkins Let's Encrypt Node.js Python Java .NET Go PHP
  • Every change asks first, and shows you the exact command or diff before it runs.
  • File edits are snapshotted and reversible. Deleted folders are archived, not removed.
  • Private key material never reaches the model, under any setting.
brynko devOps Agent
Web servers

the site is throwing 502, it was fine yesterday

read the error log checked the vhost listed ports

nginx is fine and so is your app. The error log repeats connect() failed (111: Connection refused) for upstream 127.0.0.1:8019, but nothing is listening there. Your container is bound to 9014. The port changed at the last deploy and the vhost still points at the old one.

point nginx at the right one

one line in the vhost nginx -t passed reloaded

Done. I changed the upstream port in your site config, tested it before applying, and reloaded. The site is returning 200 again.

Fixed · 200 OK

Free download for Windows. 300 free credits on signup, no card, no subscription.

Questions

Common questions

Why does nginx serve the default page for my subdomain even though I have a server block for it?
Nginx selects a server block by matching the Host header against server_name. If no block matches, nginx uses the default server for the port. Your subdomain block may have a typo, may not be included, or another block may be marked default_server.
How do I check which server block nginx is actually using for a request?
Run nginx -T to dump the active configuration in load order. Look for the server_name that matches the request host and check the listen default_server flags. You can also inspect the access log for the request to see which server block recorded it.
What is the order of server_name matching in nginx?
Nginx checks exact names first, then the longest wildcard starting with *., then the longest wildcard ending with .*, then regex names in the order they appear. If no name matches, the default server for the port handles the request.
How do I make a server block the default for a port?
Add default_server to the listen directive, for example listen 80 default_server. Only one default server per listen port should be defined. If multiple blocks have default_server on the same port, the first one in load order wins.
How do I test nginx configuration before reloading on Windows and Linux?
On Linux run sudo nginx -t. On Windows, open an elevated prompt, change to the nginx directory, and run nginx.exe -t. Only reload if the test reports syntax is ok.
Why is my site enabled but still not working?
The file may not be included from the main configuration, or a duplicate server_name earlier in load order is taking precedence. Use nginx -T to confirm the final loaded configuration and check for typos, default_server flags, and include directives.

Keep reading