Resolving Nginx Server Name Conflict for Subdomains: foo.domain.com vs bar.domain.com


2 views

When setting up multiple subdomains in Nginx, you might encounter server name conflicts where requests to one subdomain incorrectly serve content from another. This typically happens when Nginx can't properly distinguish between server blocks.

The key symptom is the warning message during Nginx restart:

nginx: [warn] conflicting server name "" on 0.0.0.0:443, ignored

This indicates Nginx found duplicate or ambiguous server_name definitions for the same IP/port combination.

In your configuration, while you've properly defined server_name for both HTTP (port 80) blocks, there's a critical omission in your HTTPS (port 443) blocks - they're missing the server_name directive entirely. Nginx needs this to properly route requests.

Here are the corrected configuration files with explanations:

foo.domain.com

upstream php-handler {
    server unix:/var/run/php5-fpm.sock;
}

server {
    listen 80;
    server_name foo.domain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    server_name foo.domain.com;  # THIS WAS MISSING
    
    ssl_certificate      [path_foo]/cacert.pem;
    ssl_certificate_key  [path_foo]/privkey.pem;

    root [path]/foo;
    
    # Additional SSL configuration would go here
    # ...
}

bar.domain.com

server {
    listen 80;
    server_name bar.domain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    server_name bar.domain.com;  # THIS WAS MISSING
    
    ssl_certificate      [path_bar]/cacert.pem;
    ssl_certificate_key  [path_bar]/privkey.pem;

    root [path]/bar;
    
    # Additional SSL configuration would go here
    # ...
}
  • Always include server_name in both HTTP and HTTPS server blocks
  • The modern Nginx syntax uses listen 443 ssl instead of separate ssl on
  • Consider adding a default server block to catch undefined hostnames

After making changes:

sudo nginx -t  # Test configuration
sudo service nginx reload  # Apply changes

Verify with:

curl -I http://foo.domain.com
curl -I https://foo.domain.com
curl -I http://bar.domain.com
curl -I https://bar.domain.com

To prevent any future conflicts, add this catch-all block:

server {
    listen 80 default_server;
    listen 443 ssl default_server;
    ssl_certificate      /path/to/default/cert.pem;
    ssl_certificate_key  /path/to/default/key.pem;
    return 444;  # Close connection without response
}

The warning message you're seeing (conflicting server name "" on 0.0.0.0:443) typically occurs when Nginx can't properly distinguish between virtual hosts, especially in SSL configurations. The symptom where both subdomains serve the same content indicates Nginx is defaulting to one of your server blocks.

The main issues in your configuration are:

1. Missing server_name in your SSL server blocks
2. Potential certificate mismatch
3. Lack of default_server designation

Here's the corrected configuration for both subdomains:

foo.domain.com

upstream php-handler {
    server unix:/var/run/php5-fpm.sock;
}

server {
    listen 80;
    server_name foo.domain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    server_name foo.domain.com;
    
    ssl_certificate     [path_foo]/cacert.pem;
    ssl_certificate_key [path_foo]/privkey.pem;
    
    root [path]/foo;
    index index.php index.html index.htm;
    
    # Additional PHP-FPM configuration
    location ~ \.php$ {
        fastcgi_pass php-handler;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

bar.domain.com

server {
    listen 80;
    server_name bar.domain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl;
    server_name bar.domain.com;
    
    ssl_certificate     [path_bar]/cacert.pem;
    ssl_certificate_key [path_bar]/privkey.pem;
    
    root [path]/bar;
    index index.php index.html index.htm;
    
    # Additional configuration if needed
}

The critical fixes include:

  • Added server_name to SSL server blocks
  • Modernized SSL directive syntax (listen 443 ssl instead of separate ssl on)
  • Ensured each subdomain has its own complete configuration

After making these changes:

sudo nginx -t  # Test configuration
sudo systemctl restart nginx

Verify using:

curl -I http://foo.domain.com
curl -I https://foo.domain.com
curl -I http://bar.domain.com
curl -I https://bar.domain.com

For more complex setups, consider:

# Wildcard SSL certificate option
server_name *.domain.com;

# Default server catch-all
server {
    listen 443 ssl default_server;
    server_name _;
    return 444;  # Close connection
}