Nginx Performance Optimization with Security
Nginx Performance Optimization with Security
Nginx is designed for high performance, but proper configuration maximizes its potential:
# /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 65535;
pid /run/nginx.pid;
events {
worker_connections 4096;
use epoll;
multi_accept on;
}
http {
# Basic settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 100;
reset_timedout_connection on;
client_body_timeout 10;
client_header_timeout 10;
send_timeout 10;
# Security limits
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_conn_zone $binary_remote_addr zone=addr:10m;
# Buffer sizes (prevent buffer overflow attacks)
client_body_buffer_size 128k;
client_max_body_size 10m;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
output_buffers 1 32k;
postpone_output 1460;
# File cache
open_file_cache max=1000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# Gzip settings
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml application/atom+xml image/svg+xml;
gzip_disable "msie6";
gzip_min_length 1000;
# Brotli compression (if module available)
# brotli on;
# brotli_comp_level 6;
# brotli_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml application/atom+xml image/svg+xml;
# FastCGI cache for dynamic content
fastcgi_cache_path /var/cache/nginx/fastcgi levels=1:2 keys_zone=WORDPRESS:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header http_500;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
# Proxy cache settings
proxy_cache_path /var/cache/nginx/proxy levels=1:2 keys_zone=STATIC:10m inactive=7d max_size=1g;
proxy_temp_path /var/cache/nginx/temp;
server {
listen 443 ssl http2;
server_name example.com;
# SSL optimization
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
ssl_buffer_size 4k;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# Rate limiting
limit_req zone=one burst=10 nodelay;
limit_conn addr 10;
# Security headers with caching considerations
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# Static file caching
location ~* \.(jpg|jpeg|png|gif|ico|css|js|pdf|txt|woff|woff2|ttf|svg|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header X-Content-Type-Options "nosniff" always;
# Enable sendfile for static files
sendfile on;
tcp_nopush on;
# Disable logging for static files
access_log off;
log_not_found off;
}
# PHP-FPM with caching
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
# FastCGI cache
fastcgi_cache WORDPRESS;
fastcgi_cache_valid 200 60m;
fastcgi_cache_valid 404 10m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
# Security headers for dynamic content
add_header X-Cache-Status $upstream_cache_status;
add_header Cache-Control "no-cache, must-revalidate, max-age=0";
add_header X-Frame-Options "SAMEORIGIN" always;
}
# Cache bypass rules
set $skip_cache 0;
# POST requests and URLs with query strings should always go to PHP
if ($request_method = POST) {
set $skip_cache 1;
}
if ($query_string != "") {
set $skip_cache 1;
}
# Don't cache URLs containing the following segments
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
set $skip_cache 1;
}
# Don't use the cache for logged-in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}
}
}