How to configure security in Nginx? What are the security best practices?
Nginx security configuration is crucial for protecting web servers from various attacks. Proper security configuration can effectively prevent common security threats.
Basic Security Configuration:
nginx# Hide Nginx version number server_tokens off; # Limit request methods if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 405; } # Limit request body size client_max_body_size 10m; # Limit request header size client_header_buffer_size 1k; large_client_header_buffers 4 4k; # Timeout settings client_body_timeout 10; client_header_timeout 10; keepalive_timeout 5 5; send_timeout 10;
Preventing Common Attacks:
1. Prevent SQL Injection:
nginxlocation ~* \.(php|jsp|asp)$ { if ($args ~* "union.*select.*\(") { return 403; } if ($args ~* "concat.*\(") { return 403; } }
2. Prevent XSS Attacks:
nginxlocation ~* \.(php|html|htm)$ { if ($args ~* "<script>|</script>|javascript:|onerror=|onload=|onclick=") { return 403; } }
3. Prevent File Inclusion Attacks:
nginxlocation ~* \.(php|inc|config)$ { if ($args ~* "\.\./") { return 403; } }
4. Prevent Directory Traversal:
nginxlocation ~* /\.\. { deny all; }
Access Control:
nginx# IP whitelist location /admin { allow 192.168.1.0/24; allow 10.0.0.0/8; deny all; } # IP blacklist location / { deny 192.168.1.100; deny 192.168.1.101; allow all; } # Basic authentication location /admin { auth_basic "Restricted Area"; auth_basic_user_file /etc/nginx/.htpasswd; }
Preventing DDoS Attacks:
nginx# Limit connections limit_conn_zone $binary_remote_addr zone=conn_limit:10m; server { limit_conn conn_limit 10; # Limit request rate limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s; limit_req zone=req_limit burst=20 nodelay; # Limit bandwidth limit_rate_after 10m; limit_rate 1m; }
SSL/TLS Security Configuration:
nginxserver { listen 443 ssl http2; server_name example.com; # Certificate configuration ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; # SSL protocols ssl_protocols TLSv1.2 TLSv1.3; # Cipher suites ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers on; # SSL session cache ssl_session_cache shared:SSL:50m; ssl_session_timeout 1d; ssl_session_tickets off; # OCSP Stapling ssl_stapling on; ssl_stapling_verify on; ssl_trusted_certificate /etc/nginx/ssl/chain.crt; # HSTS add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # Other security headers 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 Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';" always; }
File Security:
nginx# Deny access to hidden files location ~ /\. { deny all; access_log off; log_not_found off; } # Deny access to sensitive files location ~* \.(htaccess|htpasswd|ini|log|sh|sql|bak|old|swp|tmp)$ { deny all; access_log off; log_not_found off; } # Deny access to backup files location ~* \~$ { deny all; access_log off; log_not_found off; } # Disable directory browsing autoindex off; # Deny access to specific directories location ~* ^/(admin|config|backup|tmp)/ { deny all; }
Prevent Malicious User-Agents:
nginx# Block malicious crawlers if ($http_user_agent ~* (bot|crawl|spider|scraper)) { return 403; } # Block specific User-Agents if ($http_user_agent ~* (wget|curl|python-requests)) { return 403; }
Prevent Image Hotlinking:
nginxlocation ~* \.(jpg|jpeg|png|gif|ico|svg)$ { valid_referers none blocked example.com *.example.com; if ($invalid_referer) { return 403; } }
Log Security:
nginx# Custom log format with more security information log_format security '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$request_time $upstream_response_time ' '$http_x_forwarded_for'; # Access log access_log /var/log/nginx/access.log security; # Error log error_log /var/log/nginx/error.log warn; # Don't log sensitive paths location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ { access_log off; }
Prevent Buffer Overflow:
nginx# Limit buffer sizes client_body_buffer_size 128k; client_header_buffer_size 1k; large_client_header_buffers 4 4k; client_max_body_size 10m; # Proxy buffers proxy_buffer_size 4k; proxy_buffers 8 4k; proxy_busy_buffers_size 8k;
Security Best Practices:
- Regular updates: Keep Nginx and system patches up to date
- Principle of least privilege: Run Nginx as non-root user
- Disable unnecessary modules: Reduce attack surface
- Configure firewall: Restrict unnecessary port access
- Use HTTPS: Enable SSL/TLS encryption
- Regular log auditing: Monitor abnormal access
- Implement WAF: Use Web Application Firewall
- Backup configuration: Regularly backup configuration files
- Test configuration: Use
nginx -tto test configuration - Monitor performance: Use monitoring tools to track performance metrics
Complete Security Configuration Example:
nginxuser nginx; worker_processes auto; worker_rlimit_nofile 65535; # Hide version number server_tokens off; events { worker_connections 1024; use epoll; } http { # Basic security client_max_body_size 10m; client_header_buffer_size 1k; large_client_header_buffers 4 4k; # Timeout settings client_body_timeout 10; client_header_timeout 10; keepalive_timeout 5 5; send_timeout 10; # Rate limiting limit_req_zone $binary_remote_addr zone=req_limit:10m rate=10r/s; limit_conn_zone $binary_remote_addr zone=conn_limit:10m; # Logging log_format security '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"'; access_log /var/log/nginx/access.log security; error_log /var/log/nginx/error.log warn; # Gzip gzip on; gzip_vary on; gzip_min_length 1024; gzip_types text/plain text/css text/xml text/javascript application/json application/javascript; server { listen 80; server_name example.com; # Redirect to HTTPS return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name example.com; # SSL configuration ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:50m; ssl_session_timeout 1d; # Security headers add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; # Rate limiting limit_req zone=req_limit burst=20 nodelay; limit_conn conn_limit 10; # Deny access to hidden files location ~ /\. { deny all; access_log off; } # Deny access to sensitive files location ~* \.(htaccess|htpasswd|ini|log|sh|sql|bak|old|swp|tmp)$ { deny all; access_log off; } # Admin panel access control location /admin { allow 192.168.1.0/24; deny all; auth_basic "Restricted"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://backend; } # Main site location / { proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } }