How to Display Actual Hostname Instead of Regex Pattern in Nginx Logs and FastCGI Parameters


4 views

When using regex patterns in Nginx's server_name directive, administrators often face a frustrating behavior: the logs and FastCGI parameters show the raw regex pattern instead of the actual matched hostname. This occurs with configurations like:

server_name ~^(:?(?<second>.+)\\.)?(?<domain>[^.]+\\.[^.]+)$;

While PHP applications can still access the real hostname through $_SERVER['HTTP_HOST'], this doesn't help with Nginx's native logging or when you need the actual hostname in FastCGI parameters.

The most effective approach is to leverage Nginx's named capture groups and variable assignment:

server {
    server_name ~^(:?(?<subdomain>.+)\\.)?(?<domain>[^.]+\\.[^.]+)$;
    
    set $actual_host $subdomain.$domain;
    if ($subdomain = "") {
        set $actual_host $domain;
    }
    
    access_log /var/log/nginx/access.log combined host=$actual_host;
    
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param HTTP_HOST $actual_host;
        fastcgi_param SERVER_NAME $actual_host;
        # Other FastCGI parameters...
        fastcgi_pass unix:/var/run/php/php-fpm.sock;
    }
}

To ensure the actual hostname appears in all logs, modify your log format:

log_format custom '$remote_addr - $remote_user [$time_local] '
                 '"$request" $status $body_bytes_sent '
                 '"$http_referer" "$http_user_agent" '
                 'Host: $actual_host';

For environments with multiple server blocks or complex matching requirements, consider using the map directive:

map $host $loggable_host {
    default $host;
    "~^(:?(?<sub>.+)\\.)?(?<main>[^.]+\\.[^.]+)$" $sub.$main;
}

Then reference this in your server block:

access_log /var/log/nginx/access.log combined host=$loggable_host;
fastcgi_param HTTP_HOST $loggable_host;

After implementing these changes:

  1. Reload Nginx: sudo nginx -s reload
  2. Make test requests to verify the logs
  3. Check PHP's $_SERVER variables to confirm proper FastCGI parameter passing

When using regex patterns in Nginx's server_name directive, administrators often face an unexpected behavior where the raw regex pattern appears in logs and FastCGI parameters instead of the actual matched hostname. This occurs with configurations like:

server_name ~^(:?(?<second>.+)\\.)?(?<domain>[^.]+\\.[^.]+)$;

The regex-based server_name is powerful for matching multiple domains, but the logging behavior creates these issues:

  • Server access logs show regex patterns instead of real domains
  • FastCGI parameters (like SERVER_NAME) contain the regex string
  • Debugging becomes harder without actual domain information

The most straightforward solution is to explicitly set the server name in FastCGI parameters and logs using Nginx's $host variable:

location ~ \.php$ {
    fastcgi_param SERVER_NAME $host;
    include fastcgi_params;
    # other FastCGI configuration...
}

Here's a full vhost configuration that handles both logging and FastCGI correctly:

server {
    listen 80;
    server_name ~^(:?(?<second>.+)\\.)?(?<domain>[^.]+\\.[^.]+)$;
    
    access_log /var/log/nginx/access.log combined_host;
    
    location / {
        root /var/www/$domain;
        try_files $uri $uri/ /index.php?$args;
    }
    
    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SERVER_NAME $host;
        include fastcgi_params;
    }
}

log_format combined_host '$host $remote_addr - $remote_user [$time_local] '
                        '"$request" $status $body_bytes_sent '
                        '"$http_referer" "$http_user_agent"';

If you need the captured groups from your regex in logs, you can create a custom log format:

log_format regex_groups '$domain $second $remote_addr - $remote_user [$time_local] '
                       '"$request" $status $body_bytes_sent '
                       '"$http_referer" "$http_user_agent"';

After implementing these changes, verify with:

  1. Check Nginx configuration syntax: nginx -t
  2. Reload Nginx: systemctl reload nginx
  3. Make test requests and inspect logs
  4. Check PHP's $_SERVER['SERVER_NAME'] value