Headers More NGINX Rocky Linux 10 provides advanced HTTP header manipulation beyond what standard NGINX directives offer. This module lets you add, modify, or remove any HTTP header in both requests and responses, enabling security hardening, server fingerprint removal, and custom header injection.
This comprehensive guide shows you how to install and configure the Headers More module for NGINX on Rocky Linux 10, AlmaLinux 10, and other Enterprise Linux 10 distributions. You will learn to remove the Server header, add security headers, and implement advanced header manipulation patterns. By the end, you will have Headers More NGINX Rocky Linux 10 enhancing your server’s security and flexibility.
Why Use the Headers More Module
The standard NGINX add_header directive has significant limitations. It only adds headers to successful responses (2xx and 3xx status codes) and cannot modify or remove existing headers. The Headers More module solves these problems:
- Remove any header: Delete Server, X-Powered-By, or other revealing headers
- Works on all responses: Add headers to 4xx and 5xx error responses
- Modify existing headers: Change header values rather than just adding new ones
- Request header control: Manipulate incoming request headers before processing
- Conditional logic: Apply headers based on response status or content type
These capabilities are essential for security hardening and compliance requirements. Many security frameworks require specific headers on all responses, including errors.
Prerequisites
Before installing Headers More NGINX Rocky Linux 10 packages, ensure you have:
- Rocky Linux 10, AlmaLinux 10, RHEL 10, or Oracle Linux 10
- Root or sudo access to the server
- NGINX installed (or we will install it in this guide)
The GetPageSpeed repository provides pre-built Headers More packages ready for immediate use.
Installation
Step 1: Configure GetPageSpeed Repository
The GetPageSpeed repository provides enterprise-grade NGINX modules including Headers More. Install the repository:
sudo dnf -y install https://extras.getpagespeed.com/release-latest.rpm
Step 2: Install NGINX
If NGINX is not already installed:
sudo dnf -y install nginx
sudo systemctl enable --now nginx
Step 3: Install Headers More Module
Install the NGINX Headers More module:
sudo dnf -y install nginx-module-headers-more
After installation, you will see:
----------------------------------------------------------------------
The nginx-module-headers-more package has been installed.
To enable this module, add the following to /etc/nginx/nginx.conf
and reload NGINX:
load_module modules/ngx_http_headers_more_filter_module.so;
----------------------------------------------------------------------
Step 4: Enable the Module
Add the module loading directive at the top of your NGINX configuration:
# /etc/nginx/nginx.conf
load_module modules/ngx_http_headers_more_filter_module.so;
user nginx;
worker_processes auto;
# ... rest of configuration
Test and reload:
sudo nginx -t && sudo systemctl reload nginx
Core Directives
The Headers More module provides four main directives for header manipulation.
more_set_headers
Adds or replaces response headers:
more_set_headers "X-Custom-Header: value";
more_set_headers "Cache-Control: no-store";
Unlike add_header, this works on all response codes including errors.
more_clear_headers
Removes response headers:
more_clear_headers "Server";
more_clear_headers "X-Powered-By";
more_clear_headers "X-AspNet-Version";
more_set_input_headers
Adds or replaces request headers before processing:
more_set_input_headers "X-Real-IP: $remote_addr";
more_set_input_headers "X-Forwarded-Proto: $scheme";
more_clear_input_headers
Removes request headers:
more_clear_input_headers "X-Forwarded-For";
Common Use Cases
Security Header Hardening
Add comprehensive security headers to all responses:
http {
# Security headers for all responses
more_set_headers "X-Content-Type-Options: nosniff";
more_set_headers "X-Frame-Options: SAMEORIGIN";
more_set_headers "X-XSS-Protection: 1; mode=block";
more_set_headers "Referrer-Policy: strict-origin-when-cross-origin";
more_set_headers "Permissions-Policy: geolocation=(), microphone=()";
server {
listen 80;
# ...
}
}
These headers protect against:
- MIME type sniffing attacks
- Clickjacking via iframes
- Cross-site scripting (XSS)
- Referrer information leakage
- Unwanted browser feature access
Remove Server Fingerprint
Hide server software information:
http {
# Remove headers that reveal server software
more_clear_headers "Server";
more_clear_headers "X-Powered-By";
more_clear_headers "X-AspNet-Version";
more_clear_headers "X-AspNetMvc-Version";
# Optionally set a generic server header
more_set_headers "Server: WebServer";
}
Before:
Server: nginx/1.28.1
X-Powered-By: PHP/8.1.0
After:
Server: WebServer
Content Security Policy
Add CSP headers for XSS protection:
server {
more_set_headers "Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'";
}
For complex policies, use line continuation:
more_set_headers "Content-Security-Policy: default-src 'self';
script-src 'self' https://cdn.example.com;
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:";
CORS Headers for All Responses
Add CORS headers that work on error responses too:
location /api/ {
more_set_headers "Access-Control-Allow-Origin: https://example.com";
more_set_headers "Access-Control-Allow-Methods: GET, POST, OPTIONS";
more_set_headers "Access-Control-Allow-Headers: Authorization, Content-Type";
more_set_headers "Access-Control-Max-Age: 86400";
proxy_pass http://backend;
}
This is superior to add_header because CORS headers appear on 4xx and 5xx responses. When your API returns a 401 or 500 error, browsers still need CORS headers to read the response.
Conditional Headers by Status Code
Add headers only for specific response codes:
location / {
# Add header only for 404 responses
more_set_headers -s 404 "X-Error-Type: not-found";
# Add header for all error responses
more_set_headers -s '400 401 403 404 500 502 503' "X-Error: true";
proxy_pass http://backend;
}
Conditional Headers by Content Type
Add headers based on response content type:
# Add cache headers only for static files
more_set_headers -t 'text/css text/javascript application/javascript'
"Cache-Control: public, max-age=31536000, immutable";
# Add download header for PDFs
more_set_headers -t 'application/pdf'
"Content-Disposition: attachment";
Request Header Manipulation
Modify incoming request headers:
server {
# Normalize client IP header
more_set_input_headers "X-Real-IP: $remote_addr";
# Add tracking header
more_set_input_headers "X-Request-ID: $request_id";
# Remove potentially dangerous headers
more_clear_input_headers "X-Forwarded-Host";
location / {
proxy_pass http://backend;
}
}
Cache Control Strategies
Implement different caching policies:
# Static assets - long cache
location ~* \.(css|js|jpg|png|gif|ico|woff2?)$ {
more_set_headers "Cache-Control: public, max-age=31536000, immutable";
root /var/www/html;
}
# HTML pages - no cache
location ~* \.html$ {
more_set_headers "Cache-Control: no-cache, no-store, must-revalidate";
more_set_headers "Pragma: no-cache";
more_set_headers "Expires: 0";
root /var/www/html;
}
# API responses - short cache
location /api/ {
more_set_headers "Cache-Control: private, max-age=60";
proxy_pass http://backend;
}
Comparison with add_header
Understanding when to use Headers More versus standard add_header:
| Feature | add_header | more_set_headers |
|---|---|---|
| Works on 2xx/3xx | Yes | Yes |
| Works on 4xx/5xx | Only with always |
Yes (default) |
| Remove headers | No | Yes |
| Modify existing | No | Yes |
| Request headers | No | Yes |
| Filter by status | No | Yes |
| Filter by type | No | Yes |
Use add_header for simple cases where you only need headers on successful responses. Use Headers More for security headers, error responses, or any advanced manipulation.
Verification
After configuring Headers More NGINX Rocky Linux 10, verify the setup.
Check Response Headers
curl -sI http://localhost/ | grep -E "(Server|X-)"
Expected output (with security headers, no Server version):
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Test Error Response Headers
Verify headers appear on 404 errors:
curl -sI http://localhost/nonexistent | grep -E "(X-)"
Test with Different Content Types
Check headers vary by content type:
curl -sI http://localhost/style.css | grep Cache-Control
curl -sI http://localhost/index.html | grep Cache-Control
Troubleshooting
Headers Not Applied
Symptom: Headers do not appear in responses
Solutions:
- Verify the module file exists:
ls /usr/lib64/nginx/modules/ngx_http_headers_more_filter_module.so - Check the module is configured:
nginx -T 2>&1 | grep headers_more - Ensure
nginx -tpasses without errors - Check directive placement (http, server, or location context)
- Ensure no conflicting
add_headerdirectives
Header Appears Multiple Times
Symptom: Same header appears twice
Solutions:
- Remove duplicate
add_headerdirectives - Use
more_set_headersinstead ofadd_headerto replace - Check parent contexts for inherited headers
Input Headers Not Modified
Symptom: Request headers unchanged at backend
Solutions:
- Place
more_set_input_headersbefore proxy_pass - Check if backend overwrites headers
- Verify directive is in correct location block
SELinux Compatibility
The nginx-module-headers-more package from GetPageSpeed works correctly with SELinux in enforcing mode. No additional policy configuration is required.
Complete Production Configuration
Here is a production-ready Headers More NGINX Rocky Linux 10 configuration:
# /etc/nginx/nginx.conf
load_module modules/ngx_http_headers_more_filter_module.so;
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Remove server fingerprint
more_clear_headers "Server";
more_clear_headers "X-Powered-By";
# Security headers for all responses
more_set_headers "X-Content-Type-Options: nosniff";
more_set_headers "X-Frame-Options: SAMEORIGIN";
more_set_headers "X-XSS-Protection: 1; mode=block";
more_set_headers "Referrer-Policy: strict-origin-when-cross-origin";
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name example.com;
# Static files with long cache
location ~* \.(css|js|jpg|png|gif|ico|woff2?)$ {
more_set_headers "Cache-Control: public, max-age=31536000";
root /usr/share/nginx/html;
}
# HTML with no cache
location / {
more_set_headers "Cache-Control: no-cache";
root /usr/share/nginx/html;
index index.html;
}
}
}
Test and apply:
sudo nginx -t && sudo systemctl reload nginx
Related Articles
For more NGINX security and configuration guides:
Conclusion
Headers More NGINX Rocky Linux 10 provides essential header manipulation capabilities for security hardening and compliance. Unlike the standard add_header directive, it works on all response codes, can remove headers, and supports conditional logic based on status or content type.
Key benefits include removing server fingerprints, adding security headers to error responses, and implementing sophisticated caching strategies. The module integrates seamlessly with existing NGINX configurations and requires no application code changes.
For any production NGINX deployment, the Headers More module is essential for implementing proper security headers and meeting compliance requirements. The ability to manipulate headers on error responses alone justifies its use over standard NGINX header directives.

