Skip to content

Web server hardening

  • Disable Server Tokens: Prevent version leakage in HTTP banners and error pages.
  • TLS 1.3 Exclusivity: Enforce modern ciphers and disable obsolete SSL/TLS protocols (SSLv3, TLS 1.0, TLS 1.1).
  • HSTS Preloading: Prevent SSL stripping and ensure browsers connect only via HTTPS.
  • Strict Headers: Protect against clickjacking, MIME-sniffing, and cross-site scripting.
  • Rate Limiting: Mitigate credential stuffing and aggressive crawling.

Add these baseline directives to /etc/nginx/nginx.conf and site server blocks:

# Hide server signature
server_tokens off;
# Client payload constraints
client_max_body_size 10M;
client_body_buffer_size 128k;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
# Timeouts to prevent Slowloris attacks
client_body_timeout 12;
client_header_timeout 12;
keepalive_timeout 15;
send_timeout 10;

Include standard defensive HTTP response headers in every TLS server block:

# HTTP Strict Transport Security (HSTS)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# Prevent MIME sniffing
add_header X-Content-Type-Options "nosniff" always;
# Clickjacking mitigation
add_header X-Frame-Options "DENY" always;
# Referrer Policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Permissions Policy
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;
# Content Security Policy (Sample strict baseline)
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; object-src 'none'; base-uri 'self';" always;

Configure /etc/nginx/snippets/ssl-params.conf:

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;
# Session caching
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;

Throttle abusive clients and scanners using memory-efficient binary leaky buckets:

# Defined in http context: 10MB zone tracks ~160,000 IP states
limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m;
server {
...
# Enforce inside server or sensitive location blocks
limit_req zone=req_limit_per_ip burst=20 nodelay;
limit_conn conn_limit_per_ip 20;
# Limit sensitive auth endpoints further
location /api/auth/ {
limit_req zone=req_limit_per_ip burst=5;
proxy_pass http://auth_upstream;
}
}

Audit your hardened endpoint using standard security CLI and scanners:

Terminal window
# Verify headers locally
curl -I https://example.com
# Test SSL configuration and TLS 1.3 support
testssl.sh https://example.com