nginx duplicate server block for same server_name

Duplicate server blocks with the same server_name cause nginx to serve the first matching block and ignore later ones, often without obvious errors. This guide shows how to trace the active configuration, fix the conflict, and prevent it on Linux and Windows.

Rao Aadil, India 7 min read

Confirm the duplicate server block is the problem

When you edit a server block for example.com and the live site still serves old content, check for a duplicate server_name first. Nginx merges all config files into one effective configuration. Two blocks with the same server_name on the same listen address and port trigger a warning, and nginx uses whichever one it loads first. The other block is ignored entirely. Edits to that file do nothing.

Print the entire effective configuration and search for server_name. On Linux, run:

nginx -T | grep -n "server_name"

On Windows PowerShell, the equivalent is:

nginx -T | Select-String "server_name"

From cmd.exe, use:

nginx -T | findstr /i "server_name"

nginx -T dumps the complete merged configuration, including the file path of each included file. Look for lines like server_name example.com; appearing more than once, and note any file boundary comments such as # configuration file /etc/nginx/sites-enabled/example.com.conf:.

The warning to look for:

nginx: [warn] conflicting server name "example.com" on 0.0.0.0:80, ignored

You'll see this when two blocks share a server_name and listen address. It appears during a reload, a start, or a config test. On Windows, check the same output from an elevated command prompt; the warning goes to stderr and the error log at C:\nginx\logs\error.log.

Confirm which block actually serves the request by sending an explicit Host header. On Linux:

curl -H "Host: example.com" http://localhost

On Windows PowerShell:

Invoke-WebRequest -Headers @{Host="example.com"} http://localhost

Compare the response body, headers, or upstream behavior with what you expect from the block you edited. If the response comes from the old block, you have a duplicate that is winning.

Doing this with brynko devOps Agent

Test configs before they go live, read the right log, and reload safely, on nginx, IIS or Tomcat.

“the site is throwing 502, it was fine yesterday”

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

Trace where the duplicate server blocks are defined

The include chain in nginx.conf controls which files get merged. On Linux, a typical nginx.conf contains:

http {
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

On Windows, the official distribution usually includes only conf.d, but many setups add a sites-enabled equivalent:

http {
    include C:/nginx/conf/conf.d/*.conf;
    include C:/nginx/conf/sites-enabled/*;
}

The include lines vary from one install to another, so run nginx -T and check the top of the output for the actual paths.

List the files and symlinks in each include directory to see what is actually active. On Linux:

ls -l /etc/nginx/sites-enabled/
ls -l /etc/nginx/conf.d/

On Windows PowerShell (adjust the path if nginx is installed elsewhere, such as C:\Program Files\nginx):

Get-ChildItem C:\nginx\conf\sites-enabled
Get-ChildItem C:\nginx\conf\conf.d

nginx -T prints each file with a comment line like # configuration file /etc/nginx/sites-enabled/example.com.conf: before its contents. Use that to map each server_name occurrence to its source file and line number.

Search all config files at once. On Linux:

grep -R "server_name" /etc/nginx/

On Windows cmd.exe:

findstr /s /i "server_name" "C:\nginx\conf\*.conf"

findstr with a wildcard may not recurse into subdirectories if the path has spaces. A more reliable PowerShell command is:

Get-ChildItem -Path C:\nginx\conf\* -Recurse | Select-String -Pattern "server_name"

Record the file path and line number for every duplicate server_name. You'll need both locations before you can decide which block to keep and which to disable.

Why nginx picks one duplicate over the other

Two server blocks with the exact same server_name and listen address produce that conflicting server name warning. Nginx then uses the block that appears first in the effective configuration. "First" means first after all includes are merged, which is normally the order of the include directives in nginx.conf. The later duplicate is ignored for that listen address.

That rule only holds when the listen address matches exactly. Two blocks with listen 80; and listen [::]:80; might not be duplicates if one is IPv4-only and the other is IPv6-only. Depending on the system and the ipv6only setting, they can be distinct sockets. A request to 127.0.0.1 matches the IPv4 block; a request to [::1] matches the IPv6 one. The warning only appears when both blocks bind the same address and port.

If the duplicates are on different ports, there is no warning and both blocks can coexist. The client's port selects the listener, and the Host header then selects among the server_name values on that listener.

default_server can mask a duplicate. A default server block does not take part in server_name matching for hosts that have no explicit match; it is the fallback. Seeing default server content for a domain that should have its own block usually means a duplicate or a missing server_name.

To verify which block answers on a specific address, send a request to that IP and port explicitly. On Linux:

curl -H "Host: example.com" http://127.0.0.1:80
curl -H "Host: example.com" http://[::1]:80

On Windows PowerShell:

Invoke-WebRequest -Headers @{Host="example.com"} http://127.0.0.1:80
Invoke-WebRequest -Headers @{Host="example.com"} http://[::1]:80

Compare the responses with what each file defines. The active block is the one whose root or proxy_pass matches the output.

Fix: remove, rename, or correct the duplicate server block

Decide which block to keep. That is usually the one with the correct root, proxy_pass, or other directives for the domain. The other block should be disabled or removed.

On Linux, if the unwanted file is enabled through a symlink in sites-enabled, unlink the symlink:

sudo unlink /etc/nginx/sites-enabled/duplicate.conf

If the duplicate is a regular file in conf.d, either move it out of the include directory or rename it so it no longer matches the *.conf pattern:

sudo mv /etc/nginx/conf.d/duplicate.conf /etc/nginx/conf.d/duplicate.conf.disabled

On Windows, rename the file so it no longer matches the include pattern. From PowerShell:

Rename-Item C:\nginx\conf\sites-enabled\duplicate.conf duplicate.conf.disabled

Or move it to a backup folder:

Move-Item C:\nginx\conf\conf.d\duplicate.conf C:\nginx\conf\backup\duplicate.conf

If the kept block needs edits, make them now. Then validate the configuration. On Linux:

sudo nginx -t

On Windows, open an elevated command prompt or PowerShell and run:

nginx -t

Once the test passes, reload nginx to pick up the change without dropping connections. On Linux with systemd:

sudo systemctl reload nginx

Alternatively:

sudo nginx -s reload

On Windows:

nginx -s reload

Re-test with the explicit Host header to confirm the correct block now serves:

curl -H "Host: example.com" http://localhost
Invoke-WebRequest -Headers @{Host="example.com"} http://localhost

Prevent future duplicate server blocks

Keep site configurations in exactly one include directory. If you use sites-enabled, do not also place the same domain in conf.d. Official nginx packages on Linux often use sites-enabled exclusively; Windows setups usually rely on conf.d. Pick one convention and document it.

Name files by domain, such as example.com.conf, and remove old symlinks when a site goes away. On Linux:

sudo unlink /etc/nginx/sites-enabled/old.example.com.conf

On Windows:

Remove-Item C:\nginx\conf\sites-enabled\old.example.com.conf

Before every reload, scan for duplicate server_name entries. On Linux:

nginx -T | grep -n "server_name example.com;"

If the output shows more than one line for the same domain on the same listen address, investigate before reloading.

On Windows cmd.exe:

nginx -T | findstr /c:"server_name example.com"

Or in PowerShell:

nginx -T | Select-String "server_name example.com"

Pay attention to the conflicting server name warning whenever you run nginx -t. In a CI pipeline, treat that warning as a failure so duplicate blocks do not reach production.

A configuration management tool that runs nginx -T, flags duplicate server blocks, and validates with nginx -t before reloading through root-owned wrappers can catch these issues across both Linux and Windows without manual searching.

Related reading

Fix duplicate nginx server blocks

Use the tool to validate configs before they go live, locate the active file for any domain, and reload safely through root-owned wrappers on Linux and Windows.

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 is my nginx serving the wrong site when I have two server blocks with the same server_name?
When two server blocks have identical server_name and listen on the same address and port, nginx emits a conflicting server name warning and uses the first block it loads, ignoring later duplicates. The active block may have an old root or proxy_pass, so edits to the other block appear to have no effect.
How do I find which nginx config file is actually being used for a domain?
Run nginx -T and look for file boundary comments like # configuration file /etc/nginx/sites-enabled/example.com.conf: before the server block that contains your server_name. You can also search all includes with grep -R on Linux or findstr /s on Windows and compare line numbers with the output of nginx -T.
How do I remove a duplicate server block without breaking the site?
Identify the block you want to keep, then disable the unwanted file by unlinking its symlink in sites-enabled or renaming it with a .disabled suffix so it no longer matches the include pattern. Run nginx -t to validate, then reload with nginx -s reload or systemctl reload nginx.
Will nginx warn me about duplicate server names?
Yes, when two server blocks have the same server_name on the same listen address and port, nginx logs a warning like nginx: [warn] conflicting server name "example.com" on 0.0.0.0:80, ignored. The warning appears during configuration test, startup, or reload, but only for exact matches on the same IP:port.
Can I have two server blocks with the same server_name on different ports?
Yes, that is allowed and does not produce a duplicate warning because the listen address differs. nginx uses the IP:port the client connected to, then matches the Host header against server_name for that specific listener.
What is the difference between sites-available, sites-enabled, and conf.d when duplicates appear?
sites-available holds all config files, sites-enabled contains symlinks to the active ones, and conf.d is an additional include directory often used for snippets or extra vhosts. A duplicate can occur if the same domain is enabled in both sites-enabled and conf.d, or if two files in the same directory define the same server_name.

Keep reading