Hide nginx server Details from headers
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 theheaders-moremodule. - 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:
Server: nginx/1.18.0That 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:
| Setting | Effect |
|---|---|
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
sudoaccess on the web server. - A maintenance window is not normally required — nginx reloads without dropping connections.
Check what the server currently returns:
curl -sI https://example.com | grep -i serverProcedure#
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:
sudo apt update
sudo apt install nginx-extrasWarning: Installingnginx-extrasreplaces 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#
sudo nano /etc/nginx/nginx.confAdd both directives inside the http block:
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_headerswill cause nginx to fail its configuration test withunknown directiveif theheaders-moremodule is not present. If that happens, remove the line and rely onserver_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.
sudo nginx -tExpected:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful4. Reload nginx#
sudo systemctl reload nginxreload applies the new configuration without dropping active connections. Use restart only if reload does not take effect.
Verification#
Check the headers again:
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 returnsServer: nginxwith no version.
Confirm the version is not leaking anywhere else, such as on error pages:
curl -sI https://example.com/this-page-does-not-exist | grep -i serverDefault nginx error pages also carry a version footer. server_tokens off; suppresses that too.
Troubleshooting#
| Symptom | Cause 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 reload | A server block is overriding the http block. Search for other occurrences: grep -rn "server_tokens" /etc/nginx/ |
| Header still shows, config is correct | A 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-extras | A module in the old build is missing from the new one. Check sudo journalctl -u nginx -n 50 for the failing directive. |
Related#
- NGINX ADVANCED INSTALLATION, HARDENING, AND MONITORING GUIDE — the full nginx hardening reference.
- Hardening Linux Server