Why Hide the Version?
By default, NGINX exposes its version number in the Server response header and on error pages. While this doesn't directly create vulnerabilities, it helps attackers:
- Identify known vulnerabilities - CVEs specific to your version
- Choose targeted exploits - Skip versions that aren't vulnerable
- Automate attacks - Scanners filter targets by version
- Fingerprint your infrastructure - Part of reconnaissance phase
Security Through Obscurity
Hiding the version is not a substitute for keeping NGINX updated. It's a defense-in-depth measure that makes attackers work harder. Always patch vulnerabilities promptly.
Where Version is Exposed
1. Server Response Header
HTTP/1.1 200 OK
Server: nginx/1.24.0
Content-Type: text/html
...
2. Default Error Pages
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.24.0</center>
</body>
</html>
The Fix: server_tokens off
Add this directive to your configuration to hide the version:
# In http, server, or location block
http {
server_tokens off;
# ... rest of configuration
}
Result: Header
HTTP/1.1 200 OK
Server: nginx
Content-Type: text/html
...
Result: Error Page
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
server_tokens Options
| Value | Server Header | Recommendation |
|---|---|---|
on (default) |
nginx/1.24.0 |
Avoid |
off |
nginx |
Recommended |
build |
nginx/1.24.0 (Ubuntu) |
Avoid - even more info |
"" (empty)* |
No Server header | Best (requires module) |
* Removing the Server header entirely requires the ngx_headers_more module.
Completely Remove Server Header
To remove the Server header entirely, use the headers-more module:
# Requires ngx_headers_more module
# Install: https://github.com/openresty/headers-more-nginx-module
http {
more_clear_headers Server;
# Or set a custom value
# more_set_headers "Server: MyApp";
}
libnginx-mod-http-headers-more-filter. On CentOS/RHEL, it's available in the EPEL repository or GetPageSpeed repo.
Custom Error Pages
Replace default error pages to remove all NGINX branding:
# Custom error pages
error_page 404 /errors/404.html;
error_page 500 502 503 504 /errors/50x.html;
location /errors/ {
internal;
root /var/www;
}
Create minimal error pages without any server identification:
<!-- /var/www/errors/404.html -->
<!DOCTYPE html>
<html>
<head><title>Not Found</title></head>
<body>
<h1>Page Not Found</h1>
<p>The requested resource could not be found.</p>
</body>
</html>
Detecting with Gixy
Gixy detects version disclosure issues:
$ gixy /etc/nginx/nginx.conf
==================== Results ====================
[version_disclosure] Do not enable server_tokens on or build.
Severity: HIGH
Description: Exposing nginx version allows attackers to learn
of known vulnerabilities.
Reason: server_tokens is "on" (default).
Pseudo config:
http {
# server_tokens on; (default)
}
File: /etc/nginx/nginx.conf
Line: 1
==================== Summary ====================
Total issues: 1 (High: 1)
Verify the Fix
# Check response headers
curl -I https://yourdomain.com
# Before:
# Server: nginx/1.24.0
# After:
# Server: nginx
# Check error page (trigger a 404)
curl -I https://yourdomain.com/nonexistent-page-12345
Additional Hardening
While you're at it, consider these related measures:
http {
# Hide version
server_tokens off;
# Don't send NGINX in proxy headers
proxy_hide_header X-Powered-By;
# Remove other identifying headers
fastcgi_hide_header X-Powered-By;
# Set custom Server header (requires headers-more)
# more_set_headers "Server: WebServer";
}
Complete Example
http {
# Security: Hide version info
server_tokens off;
# Custom error pages (no NGINX branding)
error_page 404 /errors/404.html;
error_page 500 502 503 504 /errors/50x.html;
server {
listen 443 ssl http2;
server_name example.com;
# Error page location
location /errors/ {
internal;
root /var/www;
}
# ... rest of configuration
}
}
Checklist
- Set
server_tokens off;in the http block - Create custom error pages without server identification
- Consider removing the Server header entirely (headers-more module)
- Hide X-Powered-By headers from upstream applications
- Keep NGINX updated - hiding version is not a substitute for patching
- Run Gixy to verify the configuration