How to Harden Nginx: Essential Security Configurations and Best Practices
This comprehensive guide walks system administrators and developers through essential Nginx hardening steps—including hiding version info, restricting sensitive directories, custom error pages, CSP, HTTPS, SSL tuning, file permissions, security headers, rate limiting, IP whitelisting, and logging—to dramatically improve web server security.
Introduction
In today’s digital landscape, securing web servers is critical. Nginx is popular for its performance, but its default configuration may expose vulnerabilities. This guide provides a detailed hardening roadmap for administrators and developers, covering basic to advanced measures.
Hide Version Information
Nginx reveals its version in the HTTP response header by default, which attackers can use to target specific exploits. Add server_tokens off; in the http, server, or location block to disable it.
Open the Nginx configuration file (e.g., /etc/nginx/nginx.conf or /usr/local/nginx/conf/nginx.conf).
Edit the http block and add server_tokens off;. Apply the same directive in each server block if needed.
Save the file.
Test the syntax with nginx -t.
Reload Nginx with nginx -s reload.
# nginx.conf or a specific server file
http {
# other configuration...
server_tokens off;
server {
listen 80;
server_name example.com;
location / {
root /var/www/html;
index index.html index.htm;
}
}
}Restrict Access to Sensitive Directories
Prevent external users from accessing files such as .htaccess or the .git repository by using location blocks with deny all;.
server {
listen 80;
server_name example.com;
root /var/www/html;
location ~ /\.git { deny all; }
location ~ /\.ht { deny all; }
}Configure Custom Error Pages
Define custom pages for common errors (e.g., 404, 500) to improve user experience and avoid leaking server details.
server {
listen 80;
server_name example.com;
root /var/www/html;
server_tokens off;
error_page 404 /custom_404.html;
error_page 500 502 503 504 /custom_50x.html;
location = /custom_404.html { root /usr/share/nginx/html; internal; }
location = /custom_50x.html { root /usr/share/nginx/html; internal; }
}Enable HTTPS
Obtain an SSL/TLS certificate (e.g., from Let’s Encrypt), generate a CSR with OpenSSL, and configure Nginx to use the certificate.
openssl req -new -newkey rsa:2048 -nodes -out yourdomain.csr -keyout yourdomain.keyAfter receiving the certificate files, add the following server blocks:
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com www.yourdomain.com;
ssl_certificate /path/to/yourdomain.crt;
ssl_certificate_key /path/to/yourdomain.key;
ssl_trusted_certificate /path/to/intermediate.crt;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
location / { root /var/www/html; index index.html index.htm; }
}Apply Content Security Policy (CSP)
CSP mitigates XSS and data‑injection attacks by restricting which resources can be loaded.
server {
listen 80;
server_name example.com;
add_header Content-Security-Policy "default-src 'self'; img-src *; script-src 'self' 'unsafe-inline' 'unsafe-eval'";
}For stricter environments, a more detailed policy can be used:
add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://trustedscripts.example.com; style-src 'self' https://trustedstyles.example.com; img-src 'self' data: https://trustedimages.example.com; connect-src 'self' https://api.example.com; object-src 'none'; frame-src 'none';";Set Correct File Permissions
Secure Nginx by applying proper permissions to configuration files, logs, and web‑root files.
Files: chmod 644 Directories: chmod 755 Owner: run Nginx as a non‑root user (e.g., nginx or www-data).
# Example structure
/var/www/html/ # web root
/etc/nginx/nginx.conf # main config
/var/log/nginx/access.log
# Set permissions
sudo chmod 644 /var/www/html/index.html
sudo chmod 644 /etc/nginx/nginx.conf
sudo chmod 644 /var/log/nginx/access.log
sudo chmod 755 /var/www/html/
# Change ownership
sudo chown nginx:nginx /var/www/html/index.html
sudo chown root:nginx /etc/nginx/nginx.conf
sudo chown nginx:nginx /var/log/nginx/access.logConfigure Security Headers
Add HTTP response headers to defend against common attacks.
# Clickjacking protection
add_header X-Frame-Options SAMEORIGIN;
add_header Content-Security-Policy "frame-ancestors 'self';";
# XSS protection
add_header X-XSS-Protection "1; mode=block";
# MIME‑type sniffing protection
add_header X-Content-Type-Options nosniff;
# Referrer policy
add_header Referrer-Policy "strict-origin-when-cross-origin";
# Additional CSP
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'self'; upgrade-insecure-requests;";Limit Connections
Mitigate DoS attacks by restricting concurrent connections and request rates per IP.
# Limit concurrent connections
http {
limit_conn_zone $binary_remote_addr zone=addr:10m;
server {
location / { limit_conn addr 10; }
}
}
# Limit request rate
http {
limit_req_zone $binary_remote_addr zone=req_zone:10m rate=20r/s;
server {
location / { limit_req zone=req_zone burst=5 nodelay; }
}
}Configure IP Whitelist
Restrict access to sensitive paths (e.g., admin panels) to specific trusted IPs.
server {
listen 80;
server_name yourdomain.com;
location /admin/ {
allow 192.168.1.1;
deny all;
proxy_pass http://backend;
}
}Optimize SSL Configuration
Enforce modern TLS versions, strong cipher suites, OCSP stapling, HSTS, and session tickets.
# TLS versions
ssl_protocols TLSv1.2 TLSv1.3;
# Strong ciphers
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 10s;
# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Session tickets
ssl_session_tickets on;File Upload Security
Limit upload size, set proper directory permissions, and block execution of scripts in upload folders.
# Limit upload size to 10 MB
client_max_body_size 10m;
server {
listen 80;
server_name example.com;
location /upload {
proxy_pass http://backend_server;
client_max_body_size 10m;
}
location /uploads {
alias /path/to/uploads;
location ~* \.(php|pl|py|jsp|asp|sh|cgi)$ { deny all; }
}
}Prevent Common Attacks
Prevent DDoS
http {
limit_req_zone $binary_remote_addr zone=one:10m rate=30r/m;
server {
location /login.html { limit_req zone=one; }
limit_conn_zone $binary_remote_addr zone=addr:10m;
location /shopping/ { limit_conn addr 10; }
client_body_timeout 5s;
client_header_timeout 5s;
}
}Prevent SQL Injection
location / {
if ($request_uri ~* [;'<>&]) { return 444; }
if ($args ~* [;'<>&]) { return 444; }
location ~* /(admin|backup|config|db|src)/ { deny all; }
}Prevent XSS
add_header X-XSS-Protection "1; mode=block";Clickjacking Defense
add_header X-Frame-Options SAMEORIGIN;Directory Traversal Protection
# Disable autoindex
autoindex off;
# Block "../" patterns
location ~ /\.\./ { deny all; }
# Correct alias usage
location /static/ { alias /var/www/static_files/; autoindex off; }IP‑Based Access Control
location /admin/ { allow 192.168.1.100; deny all; }URL Decoding Filter
if ($uri ~* "\.\.") { return 403; }Log Security
Define detailed log formats and set appropriate log levels.
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for" $msec "$connection" "$connection_requests" "$upstream_addr" "$upstream_response_time" "$request_time" "$gzip_ratio"';
access_log /var/log/nginx/access.log main buffer=32k flush=1m;
error_log /var/log/nginx/error.log warn;
server {
listen 80;
server_name example.com;
location / { root /var/www/html; index index.html; }
error_log /var/log/nginx/example.error.log error;
}
}Other Security Measures
Disable Script Execution
server {
listen 80;
server_name example.com;
location /uploads/ {
location ~* \.php$ { deny all; }
}
}Configure Timeouts
Set reasonable timeout values to mitigate slow‑loris attacks.
http {
client_body_timeout 10s;
client_header_timeout 10s;
send_timeout 10s;
keepalive_timeout 60s;
client_max_body_size 1M;
limit_rate 100k;
}Conclusion
By disabling unnecessary HTTP methods, hiding version details, limiting request rates, enforcing HTTPS with strong TLS settings, applying CSP and other security headers, and maintaining strict file permissions and logging practices, you can significantly harden Nginx against known and emerging threats while ensuring a robust, secure web service.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
