Skip to content

nginx 常用配置

大白话解释: nginx 就像"门卫"。用户访问你的网站时,先经过 nginx,nginx 决定把请求转发给谁:

  • 静态文件(HTML、CSS、图片):nginx 直接返回
  • API 请求:转发给后端服务器(Node.js、Python、Java)
  • 多个后端服务器:nginx 分配请求,实现负载均衡

为什么需要 nginx?

  • 反向代理:隐藏后端服务器的真实地址,更安全
  • 负载均衡:多个服务器分担压力,提高性能
  • 静态资源服务:nginx 处理静态文件比 Node.js 快得多
  • HTTPS:配置 SSL 证书,支持 HTTPS 访问

什么时候用 nginx?

  • 生产环境部署前端项目
  • 需要反向代理 API 请求
  • 需要负载均衡多个后端服务
  • 需要配置 HTTPS

nginx 是高性能的 HTTP 和反向代理服务器,常用于静态资源服务、反向代理、负载均衡。

安装

bash
# Ubuntu/Debian
sudo apt update
sudo apt install nginx

# CentOS/RHEL
sudo yum install nginx

# macOS
brew install nginx

# 验证
nginx -v

基本命令

bash
# 启动
sudo systemctl start nginx

# 停止
sudo systemctl stop nginx

# 重启
sudo systemctl restart nginx

# 重新加载配置(不中断服务)
sudo systemctl reload nginx

# 查看状态
sudo systemctl status nginx

# 测试配置文件
sudo nginx -t

配置文件结构

nginx
# /etc/nginx/nginx.conf 主配置文件
# nginx 配置由多个"块"组成,层级关系:main → http → server → location

# ---- 全局块:影响 nginx 整体运行 ----
user nginx;                          # worker 进程运行的用户(生产环境建议用 nginx 或 www-data)
worker_processes auto;               # worker 进程数,auto = 自动匹配 CPU 核心数
error_log /var/log/nginx/error.log;  # 错误日志路径

# ---- events 块:连接处理相关配置 ----
events {
    worker_connections 1024;         # 每个 worker 进程的最大并发连接数
}

# ---- http 块:HTTP 服务器相关配置(最常用的配置区域)----
http {
    include /etc/nginx/mime.types;   # 引入 MIME 类型映射(让浏览器正确识别文件类型)
    default_type application/octet-stream;  # 未识别类型的默认 MIME

    # 自定义日志格式:记录客户端 IP、时间、请求、状态码等
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer"';

    # 引入 server 配置(每个 .conf 文件定义一个或多个虚拟主机)
    include /etc/nginx/conf.d/*.conf;
}

配置字段详解

全局块

全局块定义影响 nginx 整体运行的参数,位于 nginx.conf 最外层。

字段说明语法默认值示例
user设置 worker 进程运行的用户和用户组user username [groupname];nobody nobodyuser nginx nginx;
worker_processesworker 进程数,auto 表示自动检测 CPU 核心数worker_processes number | auto;1worker_processes auto;
worker_cpu_affinity绑定 worker 进程到指定 CPU 核心worker_cpu_affinity cpumask ...;无绑定worker_cpu_affinity 01 10;
worker_rlimit_nofile每个 worker 进程可打开的最大文件描述符数worker_rlimit_nofile number;操作系统限制worker_rlimit_nofile 65535;
error_log错误日志路径和级别error_log file [level];logs/error.log errorerror_log /var/log/nginx/error.log warn;
pidPID 文件路径pid file;logs/nginx.pidpid /run/nginx.pid;
daemon是否以守护进程方式运行daemon on | off;ondaemon off;

error_log 日志级别(从低到高):

级别说明
debug调试信息,需要编译时开启 --with-debug
info一般信息
notice正常但值得注意的信息
warn警告信息
error错误信息
crit严重错误
alert需要立即处理
emerg系统不可用

💡 生产环境建议使用 warnerror 级别,debug 会产生大量日志影响性能。

nginx
user nginx nginx;
worker_processes auto;
worker_cpu_affinity auto;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;
daemon on;

events 块

events 块配置 nginx 的事件处理模型和连接相关参数。

字段说明语法默认值示例
worker_connections每个 worker 进程的最大并发连接数worker_connections number;512worker_connections 65535;
use指定事件驱动模型use method;自动选择最优use epoll;
multi_accept是否允许一个 worker 进程同时接受多个新连接multi_accept on | off;offmulti_accept on;
accept_mutex是否启用互斥锁接受新连接(避免惊群效应)accept_mutex on | off;offaccept_mutex on;

事件驱动模型对比

模型平台特点
epollLinux 2.6+高性能,适合大量并发连接,推荐
kqueueFreeBSD/macOSBSD 系统的高性能模型
select所有平台兼容性最好,性能最差,连接数受限(默认 1024)
poll大多数 Unix类似 select,无连接数硬限制

💡 最大并发连接数 = worker_processes × worker_connections。作为反向代理时实际为 worker_processes × worker_connections ÷ 2(因为浏览器和后端各占一个连接)。

nginx
events {
    worker_connections 65535;
    use epoll;
    multi_accept on;
    accept_mutex off;
}

http 块

http 块是配置最密集的部分,包含 HTTP 服务器相关的全局设置。

基础设置

字段说明语法默认值示例
include引入其他配置文件include file | mask;-include /etc/nginx/mime.types;
default_type默认 MIME 类型(未匹配到类型时使用)default_type mime/type;text/plaindefault_type application/octet-stream;
sendfile是否启用 sendfile 系统调用(零拷贝传输)sendfile on | off;offsendfile on;
tcp_nopush在 sendfile 开启时,合并数据包发送(需配合 sendfile)tcp_nopush on | off;offtcp_nopush on;
tcp_nodelay禁用 Nagle 算法,减少小数据包延迟tcp_nodelay on | off;ontcp_nodelay on;
keepalive_timeout客户端长连接超时时间keepalive_timeout timeout [header_timeout];75skeepalive_timeout 65s;
keepalive_requests单个长连接最大请求数keepalive_requests number;1000keepalive_requests 1000;
open_file_cache文件描述符缓存open_file_cache max=N [inactive=time];offopen_file_cache max=10000 inactive=60s;
open_file_cache_valid缓存有效性检查间隔open_file_cache_valid time;60sopen_file_cache_valid 30s;
open_file_cache_min_uses在 inactive 时间内最少被访问几次才保留在缓存中open_file_cache_min_uses number;1open_file_cache_min_uses 2;
open_file_cache_errors是否缓存文件查找错误open_file_cache_errors on | off;offopen_file_cache_errors on;
nginx
http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65s;
    keepalive_requests 1000;

    open_file_cache max=10000 inactive=60s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;
}

客户端请求限制

字段说明语法默认值示例
client_max_body_size客户端请求体最大值(文件上传大小限制)client_max_body_size size;1mclient_max_body_size 50m;
client_body_buffer_size请求体缓冲区大小,超过此值会写入临时文件client_body_buffer_size size;8k/16kclient_body_buffer_size 128k;
client_header_timeout读取请求头超时时间client_header_timeout time;60sclient_header_timeout 60s;
client_body_timeout读取请求体超时时间client_body_timeout time;60sclient_body_timeout 60s;
large_client_header_buffers大请求头缓冲区数量和大小large_client_header_buffers number size;4 8klarge_client_header_buffers 4 32k;

⚠️ client_max_body_size1m 时,上传大于 1MB 的文件会返回 413 Request Entity Too Large 错误。

安全与日志

字段说明语法默认值示例
server_tokens是否在响应头中显示 nginx 版本号server_tokens on | off | build;onserver_tokens off;
log_format定义日志格式log_format name string ...;combined见下方示例
access_log访问日志路径和格式access_log file [format [buffer=size]];logs/access.log combinedaccess_log /var/log/nginx/access.log main;

log_format 常用变量

变量说明
$remote_addr客户端 IP 地址
$remote_user客户端用户名(HTTP Basic Auth)
$time_local访问时间(本地格式)
$time_iso8601访问时间(ISO 8601 格式)
$request请求行(方法 + URI + 协议)
$status响应状态码
$body_bytes_sent响应体字节数
$http_referer来源页面
$http_user_agent客户端 User-Agent
$http_x_forwarded_for经过多级代理后的客户端真实 IP
$request_time请求处理时间(秒)
$upstream_response_time后端响应时间(秒)
$upstream_addr后端服务器地址
$request_uri完整请求 URI(含参数)
nginx
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent" "$http_x_forwarded_for" '
                '$request_time';

log_format json escape=json '{'
    '"time":"$time_iso8601",'
    '"remote_addr":"$remote_addr",'
    '"request":"$request",'
    '"status":$status,'
    '"body_bytes_sent":$body_bytes_sent,'
    '"request_time":$request_time,'
    '"http_user_agent":"$http_user_agent"'
'}';

access_log /var/log/nginx/access.log main;

完整 http 块示例

nginx
http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65s;
    keepalive_requests 1000;

    client_max_body_size 50m;
    client_body_buffer_size 128k;
    client_header_timeout 60s;
    client_body_timeout 60s;
    large_client_header_buffers 4 32k;

    open_file_cache max=10000 inactive=60s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;

    server_tokens off;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" $request_time';

    access_log /var/log/nginx/access.log main;

    include /etc/nginx/conf.d/*.conf;
}

server 块

server 块定义一个虚拟主机,可配置多个 server 块来服务不同域名。

listen 指令

语法说明
listen 80;监听 80 端口(IPv4 + IPv6)
listen 0.0.0.0:80;仅监听 IPv4 所有地址
listen [::]:80;仅监听 IPv6 所有地址
listen 443 ssl;启用 SSL
listen 443 ssl http2;启用 SSL + HTTP/2(nginx 1.9.5+,需编译时带 --with-http_v2_module
listen 80 default_server;设为默认服务器(未匹配到其他 server 时使用)
listen 80 backlog=1024;设置连接队列长度
listen 443 ssl http2 reuseport;启用端口复用(多 worker 共享端口,提升性能)

server_name 指令

匹配优先级从高到低:

类型语法示例说明
精确匹配server_name name;server_name example.com;完全匹配
前缀通配符server_name *.name;server_name *.example.com;匹配子域名
后缀通配符server_name name.*;server_name example.*;匹配所有后缀
正则匹配server_name ~pattern;server_name ~^www\d+\.example\.com$;正则表达式匹配
nginx
server {
    listen 80 default_server;
    server_name example.com www.example.com;
    root /var/www/html;
    index index.html;
    charset utf-8;
}

SSL 相关字段

字段说明语法示例
ssl_certificateSSL 证书文件路径(PEM 格式)ssl_certificate file;ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_keySSL 私钥文件路径ssl_certificate_key file;ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_protocols允许的 SSL/TLS 协议版本ssl_protocols ...;ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers加密套件配置ssl_ciphers string;ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers是否优先使用服务器端加密套件ssl_prefer_server_ciphers on | off;ssl_prefer_server_ciphers on;
ssl_session_cacheSSL 会话缓存ssl_session_cache off | none | [builtin[:size]];ssl_session_cache shared:SSL:10m;
ssl_session_timeoutSSL 会话超时时间ssl_session_timeout time;ssl_session_timeout 10m;
ssl_session_tickets是否启用 SSL 会话票据ssl_session_tickets on | off;ssl_session_tickets off;
ssl_stapling是否启用 OCSP Staplingssl_stapling on | off;ssl_stapling on;
ssl_stapling_verify是否验证 OCSP 响应ssl_stapling_verify on | off;ssl_stapling_verify on;

生成自签名证书(仅用于开发/测试环境):

bash
# 生成自签名证书(有效期 365 天)
openssl req -x509 -nodes -days 365 \
  -newkey rsa:2048 \
  -keyout /etc/nginx/ssl/key.pem \
  -out /etc/nginx/ssl/cert.pem \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=Dev/CN=example.com"

# 生成 DH 参数(增强安全性)
openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048
nginx
# 使用自签名证书
server {
    listen 443 ssl;
    server_name localhost;

    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;
}

HTTP/2 配置

HTTP/2 需要 SSL,nginx 1.9.5+ 支持,编译时需带 --with-http_v2_modulehttp2_* 系列指令需 nginx 1.19.7+。

nginx
server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;

    http2_max_concurrent_streams 128;
    http2_max_field_size 16k;
    http2_max_header_size 32k;
    http2_recv_timeout 30s;
    http2_idle_timeout 180s;
}
字段说明默认值示例
http2_max_concurrent_streams单连接最大并发流数128http2_max_concurrent_streams 256;
http2_max_field_size单个 HPACK 头字段最大值4khttp2_max_field_size 8k;
http2_max_header_size所有 HPACK 头字段总大小上限16khttp2_max_header_size 24k;
http2_recv_timeout读取客户端数据超时30shttp2_recv_timeout 30s;
http2_idle_timeout空闲连接超时180shttp2_idle_timeout 300s;

💡 HTTP/2 使用单连接多路复用,不再需要 keepalive 优化多个 TCP 连接。HTTP/2 下浏览器对同域名的并发连接限制不再适用。

安全响应头

nginx
server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_stapling on;
    ssl_stapling_verify on;

    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 Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header Content-Security-Policy "default-src 'self'" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}
安全头说明
X-Frame-Options防止页面被嵌入 iframe(DENY 禁止 / SAMEORIGIN 同源允许)
X-Content-Type-Options禁止浏览器嗅探 MIME 类型(nosniff
X-XSS-Protection启用浏览器 XSS 过滤
Strict-Transport-Security强制浏览器使用 HTTPS(HSTS)
Content-Security-Policy限制页面可加载的资源来源(CSP)
Referrer-Policy控制 Referer 头发送策略

location 块

location 块用于匹配请求 URI,并对匹配的请求执行特定处理。

匹配规则优先级

优先级语法说明是否停止搜索
1(最高)location = /path精确匹配
2location ^~ /path前缀匹配,不再检查正则
3location ~ pattern正则匹配(区分大小写)是(按顺序首个匹配)
4location ~* pattern正则匹配(不区分大小写)是(按顺序首个匹配)
5(最低)location /path前缀匹配否(继续搜索正则)
默认location /通用匹配(兜底)

匹配流程

  1. 先检查精确匹配(=),命中则立即返回
  2. 所有前缀匹配,记住最长匹配结果;如果最长匹配带 ^~,则直接返回
  3. 按配置顺序检查正则匹配(~ / ~*),首个命中则返回
  4. 如果正则都未命中,返回步骤 2 记住的最长前缀匹配
nginx
# 精确匹配首页(优先级最高,仅匹配 "/")
location = / {
    return 200 "homepage";
}

# 前缀匹配,带 ^~ 表示优先级高于正则(匹配 /static/ 下所有路径)
location ^~ /static/ {
    root /var/www;                   # 实际查找 /var/www/static/...
}

# 正则匹配(区分大小写):以 .php 结尾的请求
location ~ \.php$ {
    fastcgi_pass 127.0.0.1:9000;    # 转发给 PHP-FPM 处理
}

# 正则匹配(不区分大小写):图片文件设置 30 天缓存
location ~* \.(jpg|png|gif)$ {
    expires 30d;                     # 浏览器缓存 30 天
}

# 通用前缀匹配(兜底规则):SPA 应用的 history 路由
location / {
    try_files $uri $uri/ /index.html;  # 先找文件 → 再找目录 → 回退到 index.html
}

try_files 指令

语法说明
try_files file1 file2 ... uri;依次检查文件是否存在,最后一个参数为内部重定向 URI
try_files $uri $uri/ =404;检查文件和目录,不存在返回 404
try_files $uri $uri/ /index.html;SPA 应用常用,所有未匹配路由回退到 index.html

alias vs root 区别

指令行为示例(请求 /img/logo.png
root /var/www;将 URI 追加到 root 路径后面实际路径:/var/www/img/logo.png
alias /data/img;用 alias 路径替换 location 匹配部分实际路径:/data/img/logo.png

⚠️ alias 后面的路径必须以 / 结尾(location 带 / 时)。alias 不能在正则 location 中使用(除非用捕获组)。

nginx
# root 示例
location /img/ {
    root /var/www;  # 实际查找 /var/www/img/...
}

# alias 示例
location /img/ {
    alias /data/images/;  # 实际查找 /data/images/...
}

# 正则 location 中使用 alias
location ~ ^/download/(.*)$ {
    alias /data/files/$1;
}

return 与 rewrite

return 指令

语法说明示例
return code;返回指定状态码return 403;
return code URL;返回重定向return 301 https://new.example.com;
return code "text";返回文本响应return 200 "OK";

常用状态码:301(永久重定向)、302(临时重定向)、403(禁止)、404(未找到)、444(关闭连接不返回响应)。

rewrite 指令

语法说明
rewrite regex replacement [flag];按正则重写 URI
flag说明
last停止当前 rewrite,重新发起 location 匹配(内部跳转)
break停止当前 rewrite,在当前 location 内继续处理
redirect返回 302 临时重定向
permanent返回 301 永久重定向
nginx
# 去掉 www
if ($host = 'www.example.com') {
    return 301 https://example.com$request_uri;
}

# 强制 HTTPS
if ($scheme = 'http') {
    return 301 https://$server_name$request_uri;
}

# URL 重写
rewrite ^/old/(.*)$ /new/$1 permanent;

💡 能用 return 实现的重定向,尽量不用 if + rewrite,性能更好。

set 与 map 指令

set 指令:定义变量,可在 server/location/if 块中使用。

nginx
# 定义变量
set $backend "http://localhost:3000";
set $proto $scheme;

# 在 proxy_pass 中使用变量
location / {
    proxy_pass $backend;
}

map 指令:在 http 块中根据源变量值映射出新变量。

语法说明
map $source $target { ... }根据 $source 的值映射出 $target
default默认值
include引入映射规则文件
hostnames支持通配符域名匹配
nginx
# 根据 User-Agent 映射移动端标识
map $http_user_agent $is_mobile {
    default 0;
    "~*mobile" 1;
    "~*android" 1;
    "~*iphone" 1;
}

# 根据来源限制 CORS
map $http_origin $cors_origin {
    default "";
    "https://example.com" $http_origin;
    "https://admin.example.com" $http_origin;
}

server {
    location / {
        if ($is_mobile) {
            rewrite ^ /mobile$uri;
        }
        add_header Access-Control-Allow-Origin $cors_origin;
    }
}

⚠️ map 必须放在 http 块中,不能放在 server/location 内。映射结果可作为 proxy_passadd_header 等指令的参数。

if 指令注意事项("if is evil")

nginx 官方建议尽量避免使用 if,因为它在某些上下文中行为不可预测。

安全用法(仅限 returnrewrite):

nginx
# ✅ 安全:if + return
if ($scheme = 'http') {
    return 301 https://$server_name$request_uri;
}

# ✅ 安全:if + rewrite
if ($request_uri ~* "/old/") {
    rewrite ^ /new$request_uri? permanent;
}

危险用法(避免在 if 块中使用非 return/rewrite 指令):

nginx
# ❌ 危险:if 块中的 proxy_pass 可能不生效
location / {
    if ($arg_debug) {
        proxy_pass http://debug_backend;
    }
    proxy_pass http://backend;
}

# ❌ 危险:if 块中的 add_header 可能被忽略
location / {
    if ($arg_version = '2') {
        add_header X-API-Version 2;
    }
}

替代方案

nginx
# 用 map + try_files 替代 if 判断
map $arg_env $backend {
    default "http://production:3000";
    "staging" "http://staging:3000";
    "dev" "http://dev:3000";
}

location / {
    proxy_pass $backend;
}

💡 原则:能用 maptry_filesreturnerror_page 实现的逻辑,不要用 ifif 仅用于简单的 returnrewrite

proxy_pass 末尾斜杠区别

配置请求 /api/users 实际代理到
proxy_pass http://backend;http://backend/api/users(保留完整 URI)
proxy_pass http://backend/;http://backend/users(去掉 location 匹配部分)
proxy_pass http://backend/v1;http://backend/v1users(⚠️ 可能不符合预期)
proxy_pass http://backend/v1/;http://backend/v1/users(✅ 正确替换)

⚠️ 当 proxy_pass 包含 URI 部分(如 /v1/),nginx 会用它替换 location 匹配的部分。如果不包含 URI,则保留完整的原始请求 URI。

proxy_set_header 详解

变量说明
Host $host将原始请求的 Host 头传给后端(默认传的是 proxy_pass 的地址)
X-Real-IP $remote_addr客户端真实 IP 地址
X-Forwarded-For $proxy_add_x_forwarded_for代理链上所有 IP(逗号分隔)
X-Forwarded-Proto $scheme客户端原始协议(http/https)
X-Forwarded-Host $host客户端原始 Host
X-Forwarded-Port $server_port客户端原始端口
Upgrade $http_upgradeWebSocket 升级头
Connection "upgrade"WebSocket 连接升级
nginx
location /api/ {
    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;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Port $server_port;
}

proxy 超时、缓冲与缓存

超时配置

字段说明默认值推荐值
proxy_connect_timeout与后端建立连接的超时时间60s60s
proxy_send_timeout向后端发送请求的超时时间60s60s
proxy_read_timeout从后端读取响应的超时时间60s120s

缓冲配置

字段说明默认值推荐值
proxy_buffering是否启用响应缓冲onon
proxy_buffer_size读取响应头的缓冲区大小4k/8k4k
proxy_buffers读取响应体的缓冲区数量和大小8 4k/8k8 16k
proxy_busy_buffers_size在缓冲未全部写完时可向客户端发送的数据量8k/16k32k

缓存配置

字段说明示例
proxy_cache_path定义缓存路径和参数proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m;
proxy_cache使用已定义的缓存区域proxy_cache my_cache;
proxy_cache_valid不同状态码的缓存有效期proxy_cache_valid 200 302 10m;
proxy_cache_key缓存 key 的组成proxy_cache_key $host$uri$is_args$args;
proxy_cache_use_stale后端出错时是否使用过期缓存proxy_cache_use_stale error timeout;
proxy_cache_bypass跳过缓存的条件proxy_cache_bypass $cookie_nocache $arg_nocache;
proxy_no_cache不缓存的条件proxy_no_cache $cookie_nocache $arg_nocache;
nginx
location /api/ {
    proxy_pass http://backend/;

    proxy_connect_timeout 60s;
    proxy_send_timeout 60s;
    proxy_read_timeout 120s;

    proxy_buffering on;
    proxy_buffer_size 4k;
    proxy_buffers 8 16k;
    proxy_busy_buffers_size 32k;
}

expires 指令

用于设置响应头中的 Cache-ControlExpires,控制浏览器缓存。

语法说明
expires 30d;缓存 30 天
expires modified +1h;基于文件修改时间缓存 1 小时
expires epoch;禁用缓存(设为过期时间 0)
expires off;不添加 Expires/Cache-Control 头
expires max;缓存到 2037 年 12 月 31 日

upstream 块

upstream 块定义后端服务器组,用于负载均衡。

server 参数

参数说明语法示例
weight权重,数值越大分配请求越多weight=nserver 10.0.0.1:3000 weight=5;
max_fails允许的最大失败次数,超过后标记为不可用max_fails=nserver 10.0.0.1:3000 max_fails=3;
fail_timeout标记不可用的持续时间;同时是失败检测的时间窗口fail_timeout=timeserver 10.0.0.1:3000 fail_timeout=30s;
backup备用服务器,仅在主服务器全部不可用时启用backupserver 10.0.0.3:3000 backup;
down标记服务器永久不可用downserver 10.0.0.4:3000 down;

负载均衡策略

策略说明配置方式
轮询(Round Robin)默认策略,按顺序依次分配不需要额外指令
加权轮询按 weight 比例分配server ... weight=n;
IP Hash同一客户端 IP 始终分配到同一服务器ip_hash;
最少连接将请求分配到当前连接数最少的服务器least_conn;
随机随机选择服务器random two least_conn;
Hash按自定义 key 的 hash 值分配hash $request_uri consistent;

keepalive 连接池

字段说明语法示例
keepalive每个 worker 进程与后端保持的空闲长连接数keepalive connections;keepalive 32;
keepalive_requests每个长连接最大请求数keepalive_requests number;keepalive_requests 100;
keepalive_time长连接最大存活时间keepalive_time time;keepalive_time 1h;
keepalive_timeout空闲长连接超时时间keepalive_timeout time;keepalive_timeout 60s;

⚠️ 使用 keepalive 时,proxy_pass 必须使用域名(不能带 URI),且需要设置 proxy_http_version 1.1 和清除 Connection 头。

⚠️ 当 proxy_passupstream 中使用域名(如 proxy_pass http://api.example.com)时,nginx 启动时会尝试解析域名。如果域名无法解析,nginx 会启动失败。需在 http 块中配置 resolver

nginx
http {
    resolver 8.8.8.8 valid=30s;  # 使用 Google DNS,缓存 30 秒
    # 或使用系统 DNS
    # resolver 127.0.0.53 valid=10s;
}
nginx
upstream backend {
    least_conn;                                    # 负载均衡策略:最少连接(将请求分配到连接数最少的服务器)
    server 10.0.0.1:3000 weight=3 max_fails=3 fail_timeout=30s;  # 主服务器1:权重 3(分到更多请求),失败 3 次后暂停 30 秒
    server 10.0.0.2:3000 weight=2;                # 主服务器2:权重 2
    server 10.0.0.3:3000 backup;                  # 备用服务器:仅在主服务器全部不可用时启用

    keepalive 32;                                  # 保持 32 个空闲长连接到后端(减少 TCP 握手开销)
    keepalive_requests 100;                        # 每个长连接最多处理 100 个请求后关闭
    keepalive_timeout 60s;                         # 空闲 60 秒后关闭长连接
}

server {
    listen 80;                                     # 监听 80 端口
    server_name example.com;                       # 域名

    location / {
        proxy_pass http://backend;                 # 转发到 upstream 定义的 backend 组
        proxy_http_version 1.1;                    # 使用 HTTP/1.1(keepalive 必需)
        proxy_set_header Connection "";            # 清除 Connection 头(让 keepalive 生效)
    }
}

Gzip 压缩

字段说明语法默认值示例
gzip是否启用 gzip 压缩gzip on | off;offgzip on;
gzip_types需要压缩的 MIME 类型gzip_types type ...;text/htmlgzip_types text/css application/javascript application/json;
gzip_min_length启用压缩的最小响应体大小gzip_min_length length;20gzip_min_length 1024;
gzip_comp_level压缩级别(1-9),越高压缩比越大但 CPU 开销越大gzip_comp_level level;1gzip_comp_level 5;
gzip_vary是否添加 Vary: Accept-Encoding 响应头gzip_vary on | off;offgzip_vary on;
gzip_proxied对代理请求是否启用压缩gzip_proxied off | expired | no-cache | ...;offgzip_proxied any;
gzip_static是否优先使用预压缩的 .gz 文件(需 ngx_http_gzip_static_modulegzip_static on | off;offgzip_static on;

💡 压缩级别建议设为 5(性能和压缩比的平衡点)。不要压缩图片、视频等已经压缩过的格式。gzip_min_length 建议设为 1024,过小的响应体压缩后可能反而变大。

nginx
# Gzip 压缩配置:减少传输体积,加快页面加载
gzip on;                                         # 启用 Gzip 压缩
gzip_vary on;                                    # 添加 Vary: Accept-Encoding 头(CDN 缓存区分压缩/非压缩版本)
gzip_proxied any;                                # 对所有代理请求启用压缩
gzip_comp_level 5;                               # 压缩级别 5(1-9,5 是性能和压缩比的平衡点)
gzip_min_length 1024;                            # 小于 1KB 的响应不压缩(压缩后可能更大)
gzip_static on;                                  # 优先使用预压缩的 .gz 文件(需 ngx_http_gzip_static_module)

# 需要压缩的文件类型(图片/视频已经是压缩格式,不需要再压缩)
gzip_types
    text/plain
    text/css
    text/javascript
    text/xml
    application/json
    application/javascript
    application/xml
    application/rss+xml
    image/svg+xml;

限流配置

请求速率限制

limit_req_zone 在 http 块定义,limit_req 在 location/server 块引用。

字段说明语法示例
limit_req_zone定义请求速率限制区域limit_req_zone key zone=name:size rate=rate;limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req应用请求速率限制limit_req zone=name [burst=n] [nodelay];limit_req zone=api burst=20 nodelay;
参数说明
key限流维度($binary_remote_addr 按 IP,$server_name 按域名)
zone共享内存区域名和大小(1m 约存储 16000 个 IP)
rate请求速率(r/s 每秒,r/m 每分钟)
burst突发容量,超出 rate 的排队请求数上限
nodelay突发请求不排队,直接处理(但仍受 burst 限制)

并发连接限制

limit_conn_zone 在 http 块定义,limit_conn 在 location/server 块引用。

字段说明语法示例
limit_conn_zone定义并发连接限制区域limit_conn_zone key zone=name:size;limit_conn_zone $binary_remote_addr zone=addr:10m;
limit_conn应用并发连接限制limit_conn zone number;limit_conn addr 10;
nginx
http {
    # 按 IP 限制请求速率:每秒 10 个请求
    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;

    # 按 IP 限制并发连接:最多 10 个
    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

    server {
        listen 80;
        server_name example.com;

        # API 接口限流:允许突发 20 个请求
        location /api/ {
            limit_req zone=api_limit burst=20 nodelay;
            limit_conn conn_limit 10;
            proxy_pass http://localhost:3000;
        }

        # 静态资源不限流
        location /static/ {
            root /var/www;
        }
    }
}

⚠️ 限流触发后默认返回 503 Service Temporarily Unavailable。可通过 limit_req_status 429; 自定义状态码。

常用内置变量

变量说明示例值
$remote_addr客户端 IP 地址192.168.1.100
$host请求头中的 Host 字段(不含端口)example.com
$server_name匹配的 server 块的 server_nameexample.com
$server_port服务器监听端口80
$request_uri完整请求 URI(含参数,不含域名)/api/users?page=1
$uri当前 URI(不含参数,经过 rewrite 后可能改变)/api/users
$args查询参数字符串page=1
$arg_name获取指定查询参数的值(name 替换为参数名)$arg_page1
$request_method请求方法GETPOST
$status响应状态码200
$body_bytes_sent响应体字节数1234
$scheme请求协议httphttps
$request_time请求处理时间(秒,毫秒精度)0.032
$upstream_addr后端服务器地址10.0.0.1:3000
$upstream_status后端返回的状态码200
$upstream_response_time后端响应时间(秒)0.025
$http_referer来源页面 URLhttps://google.com
$http_user_agent客户端 User-AgentMozilla/5.0 ...
$http_x_forwarded_for多级代理链 IPclient, proxy1, proxy2
$cookie_name获取指定 Cookie 的值$cookie_session
$request_filename请求对应的文件路径/var/www/html/index.html
$document_root当前 server 的 root 路径/var/www/html
$limit_req_status限流触发后的状态码503
nginx
# 使用变量实现条件判断
if ($request_method !~ ^(GET|HEAD|POST)$) {
    return 405;
}

# 使用 $arg_ 变量获取查询参数
if ($arg_token = '') {
    return 401;
}

常用配置

静态资源服务

nginx
server {
    listen 80;                                     # 监听 80 端口
    server_name example.com;                       # 你的域名

    root /var/www/html;                            # 静态文件根目录
    index index.html;                              # 默认首页文件

    # SPA 路由:所有未匹配的请求回退到 index.html
    location / {
        try_files $uri $uri/ /index.html;          # 先找文件 → 再找目录 → 回退到 index.html
    }

    # 静态资源缓存:js/css/图片等设置 1 年长期缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;                                # 缓存 1 年
        add_header Cache-Control "public, immutable";  # 公共缓存,内容不变
    }
}

反向代理

nginx
server {
    listen 80;                                     # 监听 80 端口
    server_name api.example.com;                   # API 域名

    location / {
        proxy_pass http://localhost:3000;           # 转发到本地 3000 端口的后端服务
        proxy_set_header Host $host;               # 显式传递原始 Host 头(确保后端收到的是请求域名而非 localhost)
        proxy_set_header X-Real-IP $remote_addr;   # 传递客户端真实 IP
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  # 传递代理链上所有 IP
        proxy_set_header X-Forwarded-Proto $scheme; # 传递原始协议(http/https)
    }
}

WebSocket 代理

nginx
# WebSocket 代理:支持 ws:// 或 wss:// 协议的实时双向通信
location /ws {
    proxy_pass http://localhost:3000;               # 转发到后端 WebSocket 服务
    proxy_http_version 1.1;                         # WebSocket 必须使用 HTTP/1.1
    proxy_set_header Upgrade $http_upgrade;         # 告诉后端要升级协议(HTTP → WebSocket)
    proxy_set_header Connection "upgrade";          # 升级连接类型
    proxy_set_header Host $host;                    # 传递原始 Host
}

负载均衡

nginx
upstream backend {
    # 轮询(默认)
    server 192.168.1.10:3000;
    server 192.168.1.11:3000;

    # 权重
    server 192.168.1.10:3000 weight=3;
    server 192.168.1.11:3000 weight=1;

    # ip_hash(同一 IP 固定到同一服务器)
    # ip_hash;

    # least_conn(最少连接)
    # least_conn;
}

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://backend;
    }
}

HTTPS 配置

nginx
# HTTPS 服务器配置
server {
    listen 443 ssl http2;                          # 监听 443 端口,启用 SSL 和 HTTP/2
    server_name example.com;                       # 你的域名

    # SSL 证书文件(使用 Let's Encrypt 或其他 CA 颁发的证书)
    ssl_certificate /etc/nginx/ssl/cert.pem;       # 证书文件(PEM 格式,含中间证书)
    ssl_certificate_key /etc/nginx/ssl/key.pem;    # 私钥文件

    # SSL 安全优化
    ssl_protocols TLSv1.2 TLSv1.3;                # 只允许 TLS 1.2 和 1.3(禁用不安全的旧版本)
    ssl_ciphers HIGH:!aNULL:!MD5;                  # 使用高强度加密套件
    ssl_prefer_server_ciphers on;                  # 优先使用服务器端的加密套件

    location / {
        root /var/www/html;                        # 静态文件目录
        try_files $uri $uri/ /index.html;          # SPA history 路由
    }
}

# HTTP 自动跳转到 HTTPS(301 永久重定向)
server {
    listen 80;                                     # 监听 80 端口
    server_name example.com;                       # 你的域名
    return 301 https://$server_name$request_uri;   # 永久重定向到 HTTPS(保留原始路径)
}

跨域配置

nginx
location /api {
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
    add_header Access-Control-Allow-Headers "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization";

    if ($request_method = 'OPTIONS') {
        return 204;
    }

    proxy_pass http://localhost:3000;
}

Vue/React 项目部署

💡 Vue Router 和 React Router 的 history 模式需要 nginx 配置 try_files,将所有未匹配的路由回退到 index.html,否则刷新页面会 404。

nginx
server {
    listen 80;                                    # 监听 80 端口
    server_name example.com;                      # 替换为你的域名

    root /var/www/dist;                           # 构建产物目录
    index index.html;                             # 默认首页

    # ---- 前端路由(SPA history 模式)----
    # Vue Router / React Router 的 history 模式必须配置此项
    # 用户访问 /about、/user/123 等路径时,实际返回 index.html
    # 由前端 JS 接管路由,从 URL 解析出对应页面
    location / {
        try_files $uri $uri/ /index.html;         # 先找文件 → 再找目录 → 回退到 index.html
    }

    # ---- API 反向代理 ----
    # 将 /api 开头的请求转发给后端 Node.js/Java/Python 服务
    location /api {
        proxy_pass http://localhost:3000;          # 转发到后端(地址根据实际修改)
        proxy_set_header Host $host;              # 传递原始 Host 头
        proxy_set_header X-Real-IP $remote_addr;  # 传递客户端真实 IP
    }

    # ---- 静态资源长期缓存 ----
    # js/css/图片等静态资源文件名通常带 hash(如 app.a1b2c3.js)
    # 内容变化时文件名也变,所以可以放心缓存 1 年
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        expires 1y;                               # 缓存 1 年
        add_header Cache-Control "public, immutable";  # 公共缓存,内容不变
    }

    # ---- HTML 不缓存 ----
    # HTML 文件是入口,必须每次获取最新版本
    location ~* \.html$ {
        expires -1;                                           # 立即过期
        add_header Cache-Control "no-cache, no-store, must-revalidate";  # 不缓存
    }
}

常见问题

403 Forbidden

bash
# 检查文件权限
ls -la /var/www/html

# 设置正确权限
sudo chown -R nginx:nginx /var/www/html
sudo chmod -R 755 /var/www/html

502 Bad Gateway

bash
# 检查后端服务是否运行
curl http://localhost:3000

# 查看错误日志
tail -f /var/log/nginx/error.log

配置不生效

bash
# 测试配置
sudo nginx -t

# 重新加载
sudo systemctl reload nginx

504 Gateway Timeout

504 表示 nginx 作为反向代理时,在规定时间内未收到后端响应。

bash
# 1. 检查后端服务是否正常
curl -v http://localhost:3000

# 2. 查看错误日志
tail -50 /var/log/nginx/error.log

# 3. 增大代理超时时间
nginx
location /api/ {
    proxy_pass http://backend;
    proxy_connect_timeout 60s;
    proxy_send_timeout 120s;
    proxy_read_timeout 120s;
}
排查方向检查项
后端服务后端进程是否存活、端口是否监听
超时配置proxy_read_timeout 是否过短
资源瓶颈后端 CPU/内存/数据库连接池是否耗尽
慢查询后端是否有慢 SQL 或长时间计算
网络nginx 到后端之间的网络是否通畅

HTTPS 混合内容

页面通过 HTTPS 加载,但部分资源(图片、JS、CSS)仍使用 HTTP,浏览器会阻止或警告。

nginx
# 方案一:使用 CSP 头强制升级
add_header Content-Security-Policy "upgrade-insecure-requests" always;

# 方案二:用反向代理统一资源路径
location /assets/ {
    proxy_pass http://internal-cdn/assets/;
}
bash
# 在浏览器控制台检查混合内容
# Chrome: F12 → Console → 筛选 "Mixed Content"
# 或在 Network 面板中查看哪些请求使用了 http://

💡 前端代码中避免硬编码 http://,使用 /// 开头的相对协议/路径。

自定义 404 页面

nginx
server {
    listen 80;
    server_name example.com;
    root /var/www/html;

    # 自定义 404 页面
    error_page 404 /404.html;
    location = /404.html {
        internal;
    }

    # 自定义 50x 页面
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        internal;
    }
}

⚠️ 自定义错误页面的 location 必须加 internal 指令,防止用户直接访问该页面。

域名重定向

nginx
# 旧域名跳转到新域名(301 永久重定向)
server {
    listen 80;
    server_name old.example.com;
    return 301 https://new.example.com$request_uri;
}

# 多个域名统一跳转到主域名
server {
    listen 80;
    server_name www.example.com example.com;
    return 301 https://example.com$request_uri;
}

# 带路径的重定向
server {
    listen 80;
    server_name old.example.com;
    location /blog {
        return 301 https://new.example.com/articles;
    }
    location / {
        return 301 https://new.example.com$request_uri;
    }
}

限制 IP 访问

nginx
# 只允许特定 IP 访问
location /admin {
    allow 192.168.1.0/24;
    allow 10.0.0.1;
    deny all;
    proxy_pass http://localhost:3000;
}

# 禁止特定 IP 访问
location / {
    deny 192.168.1.100;
    deny 10.0.0.0/8;
    allow all;
    proxy_pass http://localhost:3000;
}

⚠️ 如果有多层代理,需使用 set_real_ip_fromreal_ip_header 获取真实客户端 IP,否则限制的是代理服务器的 IP。

nginx
# 从 Cloudflare 等 CDN 获取真实 IP
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
real_ip_header CF-Connecting-IP;

查看并发连接数

nginx
# 启用 stub_status 模块
server {
    listen 80;
    server_name localhost;

    location /nginx_status {
        stub_status;
        allow 127.0.0.1;
        allow 192.168.1.0/24;
        deny all;
    }
}
bash
# 访问状态页
curl http://127.0.0.1/nginx_status

# 输出示例:
# Active connections: 291
# server accepts handled requests
#  16630948 16630948 31070465
# Reading: 6 Writing: 179 Waiting: 106
字段说明
Active connections当前活跃连接数
accepts已接受的总连接数
handled已处理的总连接数
requests已处理的总请求数
Reading正在读取请求头的连接数
Writing正在发送响应的连接数
Waiting等待请求的空闲长连接数
bash
# 统计当前各状态连接数
ss -s
# 或
netstat -ant | awk '{print $6}' | sort | uniq -c | sort -rn

参考

个人学习笔记,部分内容借助 AI 辅助整理,仅供查阅参考,请以官方文档为准