A default Nginx installation exposes version information in response headers, accepts legacy TLS protocols, and sends no browser security directives — all of which reduce your attack surface score and leave clients vulnerable to clickjacking, MIME sniffing, and downgrade attacks. Hardening Nginx on RHEL 8 involves a series of targeted configuration changes: suppressing the server banner, adding HTTP security headers, enforcing TLS 1.2/1.3 with strong cipher suites, and enabling OCSP stapling so clients can verify certificate revocation status without a round trip to the CA. This guide covers each layer in turn and shows how to verify the results.
Prerequisites
- RHEL 8 server with Nginx installed and an HTTPS virtual host configured
- A valid TLS certificate (CA-issued for OCSP stapling; self-signed works for other steps)
- Root or sudo access
- Optional: SSL Labs account or
testssl.shfor automated grading
Step 1 — Suppress the Nginx Version Banner
By default, Nginx includes its version number in the Server response header and in error pages. Disable this to reduce information leakage.
sudo tee /etc/nginx/conf.d/security-headers.conf > /dev/null <<'EOF'
server_tokens off;
EOF
sudo nginx -t && sudo systemctl reload nginx
# Verify the header no longer shows a version
curl -sI http://localhost | grep Server
# Expected: Server: nginx (no version number)
Step 2 — Add HTTP Security Headers
Add the following response headers inside your HTTPS server block. These directives instruct browsers to reject framing, block MIME sniffing, enable XSS filtering, limit referrer leakage, and enforce HTTPS through HSTS.
sudo tee -a /etc/nginx/conf.d/security-headers.conf > /dev/null <<'EOF'
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none';" always;
EOF
sudo nginx -t && sudo systemctl reload nginx
The HSTS max-age of 63072000 seconds (two years) is the minimum required for HSTS preload list submission. Set a shorter value such as 3600 while testing and increase it once you are confident the configuration is stable.
Step 3 — Restrict TLS to 1.2 and 1.3 with Strong Cipher Suites
Disable TLS 1.0 and 1.1, which are deprecated by RFC 8996, and configure a cipher suite list that excludes NULL, EXPORT, and RC4 ciphers. Prefer server cipher order to prevent clients from negotiating weak options.
sudo tee /etc/nginx/conf.d/tls-hardening.conf > /dev/null <&1 | grep "handshake"
Step 4 — Enable OCSP Stapling
OCSP stapling allows Nginx to cache and serve the certificate revocation status response from the CA, eliminating the need for clients to make a separate OCSP request on every TLS handshake. This improves privacy, reduces latency, and works correctly only with CA-issued certificates that include an OCSP responder URL.
sudo tee -a /etc/nginx/conf.d/tls-hardening.conf > /dev/null <&1 | grep -A 10 "OCSP Response"
If you are using a self-signed certificate, ssl_stapling will be silently ignored. It requires a chain leading to a public CA with an OCSP responder.
Step 5 — Disable Weak Diffie-Hellman Parameters
Generate a strong Diffie-Hellman parameter file to replace the 1024-bit default and prevent Logjam attacks.
sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048
# Reference the file in your TLS configuration
echo 'ssl_dhparam /etc/nginx/dhparam.pem;' | sudo tee -a /etc/nginx/conf.d/tls-hardening.conf
sudo nginx -t && sudo systemctl reload nginx
Step 6 — Test with SSL Labs or testssl.sh
For servers with a public hostname, submit the domain to SSL Labs for an automated grade. For internal servers, run testssl.sh locally.
# Download and run testssl.sh
curl -sL https://testssl.sh/testssl.sh -o /tmp/testssl.sh
chmod +x /tmp/testssl.sh
/tmp/testssl.sh --fast https://yourdomain.com
A correctly hardened server should score A or A+ on SSL Labs with no warnings for deprecated protocols, weak ciphers, or missing HSTS.
Conclusion
Your Nginx instance on RHEL 8 now suppresses version information, sends a full set of browser security headers, enforces TLS 1.2 and TLS 1.3 with strong cipher suites, and staples OCSP responses to reduce client-side revocation overhead. These changes address the most common findings in web server security audits and form the baseline for an A+ SSL Labs score.
Next steps: How to Configure SSL/TLS with OpenSSL and Self-Signed Certificates on RHEL 8, How to Configure Nginx WebSocket Proxying on RHEL 8, and How to Monitor Nginx with Prometheus nginx-exporter on RHEL 8.