个人常用 NGINX 配置片段速查

 

记录一些个人常用的 NGINX 配置,方便随时复制。

默认配置修改

worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 1048575;
charset utf-8;

events {
  worker_connections 4096;
}

http {
  client_max_body_size 0;
  server_tokens off; # make stupid scanners happy

  # gzip settings
  gzip on;
  gzip_comp_level 3;
  gzip_vary on;
  gzip_min_length 1024;
  gzip_proxied expired no-cache no-store private auth;
  gzip_http_version 1.0; # for downstream NGINX
  gzip_types text/plain text/css application/xml application/javascript application/json image/svg+xml font/x-woff font/opentype font/ttf;

  # gzip_static for pre-compressed files
  gzip_static on;

  # real IP in logs
  real_ip_header X-Forwarded-For;
  real_ip_recursive on;
  set_real_ip_from aaa.bbb.ccc.ddd/32;

  # SSL related
  ssl_dhparam /path/to/dhparam; # https://ssl-config.mozilla.org/ffdhe2048.txt
  ssl_session_timeout 1d;
  ssl_session_cache shared:SSL:10m;
  ssl_session_tickets off;
  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:DHE-RSA-CHACHA20-POLY1305;
  ssl_stapling on;
  # TLS1.3 early data
  ssl_early_data on;
  proxy_set_header Early-Data $ssl_early_data;
}

HTTPS 与强制跳转

server {
  listen 80;
  listen [::]:80;
  server_name example.com;

  location / {
    return 301 https://$host$request_uri;
  }
}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name example.com;

  ssl_certificate /path/to/cert.pem;
  ssl_certificate_key /path/to/key.pem;

  # HSTS
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}

带缓存的反向代理

upstream backend {
  server 127.0.0.1:8080;
  keepalive 32;
  keepalive_timeout 60s; # be careful with RST from upstream
}


# cache settings
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=foo_cache:10m max_size=10g inactive=60m use_temp_path=off;
proxy_cache_lock on;

map $request_uri $bypass_cache {
  default 0;
  ~*^/api/ 1;
}

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

location ^~ /foo/ {
  proxy_pass http://backend/bar/;
  proxy_http_version 1.1;
  # use resolver if upstream is a domain name
  resolver 101.6.6.6 valid=60s;
  # headers
  proxy_set_header Host $host;
  proxy_set_header X-Forwarded-Host $http_host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto; # hardcode to https when proxying HTTPS with HTTP
  # add upstream IP to XFF header
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # if not using remote_ip module
  proxy_set_header X-Forwarded-For "$http_x_forwarded_for, $realip_remote_addr"; # if using remote_ip module (because $remote_addr is changed)
  # WebSocket
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection $connection_upgrade;
  # set to off if not necessary
  proxy_redirect default;
  # set timeout
  proxy_connect_timeout 60s;
  proxy_read_timeout 60s;
  proxy_send_timeout 60s;
  # check ssl certificate
  proxy_ssl_certificate /path/to/cert.pem;
  proxy_ssl_name example.com;
  proxy_ssl_verify on;
  # cache settings
  proxy_cache foo_cache;
  proxy_cache_bypass $bypass_cache;
  proxy_cache_key $request_uri;
  proxy_cache_valid 200 10m;
  proxy_cache_valid 301 1m;
  proxy_cache_revalidate on;
  proxy_cache_use_stale updating;
  proxy_cache_background_update on;
  # buffering settings
  proxy_buffering off;
  proxy_request_buffering off;
  # if buffer is enabled
  proxy_temp_path /dev/shm/nginx 1 2; # use memory
}

NGINX buffering 的配置比较复杂,个人经验是应该在带宽较大一侧开启 buffer:如在客户端到前端的带宽显著大于前端到后端带宽时,应该启用 proxy_request_buffering,反过来则开启 proxy_buffering

PHP FastCGI / Python UWSGI

Server 配置:

server {
  location / {
    try_files $uri $uri/ /index.php?$args;
  }

  location ~ \.php {
    fastcgi_pass unix:/var/run/php/php-fpm.sock;
    include snippets/fastcgi-php.conf;
    try_files $fastcgi_script_name =404;
  }

  location ~^ /py/ {
    include snippets/python-uwsgi.conf;
  }
}

snippets/fastcgi-php.conf

include fastcgi_params;
fastcgi_buffering off;
fastcgi_index index.php;
fastcgi_param DOCUMENT_ROOT $realpath_root;
fastcgi_param SCRIPT_FILENAME$realpath_root$fastcgi_script_name;

snippets/python-uwsgi.conf

include uwsgi_params;
uwsgi_buffering off;
uwsgi_pass unix:/tmp/uwsgi.sock;
uwsgi_param Host              $host;
uwsgi_param X-Real-IP         $remote_addr;
uwsgi_param X-Forwarded-For   $proxy_add_x_forwarded_for;
uwsgi_param X-Forwarded-Proto $http_x_forwarded_proto;

fastcgiuwsgi 模块同样有 buffering 和 cache 的配置,基本和反代的配置大同小异。

客户端限制

请求数限制

http {
  limit_req_zone $binary_remote_addr zone=req_addr_limit:10m rate=5r/s;
}

location /bar/ {
  limit_req zone=req_addr_limit burst=30 delay=20;
  limit_req_dry_run on; # set to off to enable
  limit_req_status 429; # default is 503
}

连接数限制

注:在 HTTP/2 和 HTTP/3 中,每个并发请求都被视作一个单独的连接。所以限制请求数基本就可以满足要求。

http {
  limit_conn_zone $binary_remote_addr zone=conn_addr_limit:10m;
}

location /foo/ {
  limit_conn zone=conn_addr_limit 20;
  limit_conn_dry_run on; # set to off to enable
  limit_conn_status 429; # default is 503
}

静态路径映射

关键:如果 location 是正则表达式,则 alias 指令不会保留后缀。也就是说,必须使用绝对 URI 查找文件。

用户家目录(恒等映射)

location ~ ^\/~(\w+)(\/.*)?$ {
  alias /home/$1/public_html$2;
  index index.html index.htm;
  autoindex on;
}

非恒等映射

map $uri $actual_dir {
  ~^/foo/ alpha$1;
  ~^/bar/ bravo$1;
  ~^/baz/ charlie$1;
}

location ~ ^/(foo|bar|baz)(/|$) {
  rewrite ^/([^/]*)$ /$1/ redirect;
  root /common/root;
  try_files /$actual_dir /$actual_dir/ /$actual_dir/index.html =404;
}

其他