KB
Web Servers

Hide nginx server Details from headers

3 min read680 words10 code blocks

At a glance#

  • Purpose: Stop nginx from advertising its name and version number in HTTP response headers.
  • Applies to: nginx on Debian/Ubuntu (via nginx-extras) and any build with the headers-more module.
  • Risk: Low — a configuration change with a reload, no downtime.
  • Time: About 10 minutes.

Overview#

By default nginx returns a Server header on every response:

text
Server: nginx/1.18.0

That tells anyone scanning the site exactly which software and version is running, which makes it trivial to look up known vulnerabilities for that release. Removing it does not fix vulnerabilities, but it stops the server volunteering a target list, and it is routinely flagged as information disclosure in vulnerability scans and PCI assessments.

There are two levels of fix:

SettingEffect
server_tokens off;Hides the version, leaving Server: nginx
more_clear_headers Server;Removes the Server header entirely

server_tokens is built into nginx. Removing the header completely requires the headers-more module, which is not compiled into the default nginx package.

Before you start#

  • Root or sudo access on the web server.
  • A maintenance window is not normally required — nginx reloads without dropping connections.

Check what the server currently returns:

bash
curl -sI https://example.com | grep -i server

Procedure#

1. Install a build that includes headers-more#

On Debian and Ubuntu, the nginx-extras package is a build of nginx with additional modules compiled in, including headers-more:

bash
sudo apt update
sudo apt install nginx-extras
Warning: Installing nginx-extras replaces the running nginx binary. Existing configuration under /etc/nginx/ is preserved, but the service restarts. Do this in a maintenance window on a busy production server.

On RHEL-family systems there is no nginx-extras package. Either use server_tokens off; alone, or compile nginx with --add-module=/path/to/headers-more-nginx-module. If only the version needs hiding, skip to step 2 and use server_tokens on its own.

2. Edit the nginx configuration#

bash
sudo nano /etc/nginx/nginx.conf

Add both directives inside the http block:

nginx
http {
    server_tokens off;
    more_clear_headers Server;

    # ... existing configuration
}

Placing them in the http block applies them to every site on the server. To limit the change to a single site, put the same lines inside that site's server block instead.

Note: more_clear_headers will cause nginx to fail its configuration test with unknown directive if the headers-more module is not present. If that happens, remove the line and rely on server_tokens off; alone.

3. Test the configuration#

Always test before reloading. A syntax error caught here is harmless; the same error found during a reload can take the site down.

bash
sudo nginx -t

Expected:

text
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

4. Reload nginx#

bash
sudo systemctl reload nginx

reload applies the new configuration without dropping active connections. Use restart only if reload does not take effect.

Verification#

Check the headers again:

bash
curl -sI https://example.com | grep -i server
  • With both directives applied, the command returns nothing — the header is gone.
  • With only server_tokens off;, it returns Server: nginx with no version.

Confirm the version is not leaking anywhere else, such as on error pages:

bash
curl -sI https://example.com/this-page-does-not-exist | grep -i server

Default nginx error pages also carry a version footer. server_tokens off; suppresses that too.

Troubleshooting#

SymptomCause and fix
nginx: [emerg] unknown directive "more_clear_headers"The headers-more module is not present. Install nginx-extras, or remove the directive and use server_tokens off; only.
Header still shows after reloadA server block is overriding the http block. Search for other occurrences: grep -rn "server_tokens" /etc/nginx/
Header still shows, config is correctA reverse proxy, load balancer or CDN in front of nginx is adding its own. Test nginx directly: curl -sI http://127.0.0.1
Site down after installing nginx-extrasA module in the old build is missing from the new one. Check sudo journalctl -u nginx -n 50 for the failing directive.