Nginx 完全指南

相关文档:Docker Compose完全指南(/docker-compose-wan-quan-zhi-nan/) Docker初级指南(/docker-chu-ji-zhi-nan/) FastAPI完全指南(/fastapi-wan-quan-zhi-nan/) Nginx 是高性能的 HTTP 服务器和反向代理服务器,常见用途: 子 location 块使用 add_header 后,父块的 add_header 会失效。需在每个 location 都添加,或使用 headers-more-nginx-module 模块。 每次修改配置前先 ng

分享

官方文档:https://nginx.org/en/docs/
适用版本:Nginx 1.26(2026-05-07 核实)

相关文档:Docker Compose完全指南 Docker初级指南 FastAPI完全指南


1. 基础概念

Nginx 是什么

Nginx 是高性能的 HTTP 服务器和反向代理服务器,常见用途:

用途 说明
静态文件服务 直接托管 HTML/CSS/JS/图片,性能极高
反向代理 将请求转发给后端服务(FastAPI/Node/Django)
负载均衡 将流量分发到多个后端实例
SSL 终止 在 Nginx 层处理 HTTPS,后端用 HTTP
缓存 缓存后端响应,减少后端压力
限流 防止请求过多压垮后端

配置文件结构

/etc/nginx/
  nginx.conf           主配置文件
  conf.d/              额外配置目录(nginx.conf 会 include 这里)
    default.conf
    myapp.conf
  sites-available/     站点配置(Ubuntu/Debian)
  sites-enabled/       已启用站点的软链接

2. 配置文件语法

# nginx.conf 总体结构
user nginx;
worker_processes auto;          # 工作进程数(auto = CPU 核数)
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;    # 每个 worker 最大连接数
    use epoll;                  # Linux 使用 epoll(高性能)
    multi_accept on;            # 一次接受多个连接
}

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

    sendfile on;
    tcp_nopush on;
    keepalive_timeout 65;
    gzip on;

    # 包含所有站点配置
    include /etc/nginx/conf.d/*.conf;
}

3. server 块 — 虚拟主机

server {
    listen 80;                      # 监听端口
    listen [::]:80;                 # IPv6
    server_name example.com www.example.com;  # 匹配的域名

    root /var/www/html;             # 根目录
    index index.html index.htm;

    # 访问日志
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    location / {
        try_files $uri $uri/ /index.html;  # SPA 路由
    }
}

4. location 块

匹配规则(优先级从高到低)

修饰符 说明 示例
= 精确匹配 location = /favicon.ico
^~ 前缀匹配(优先,不走正则) location ^~ /static/
~ 正则匹配(区分大小写) location ~ \.php$
~* 正则匹配(不区分大小写) location ~* \.(jpg|png)$
无修饰符 普通前缀匹配 location /api/
# 精确匹配根路径
location = / {
    return 301 /index.html;
}

# 静态文件(前缀优先,不走正则)
location ^~ /static/ {
    alias /var/www/static/;
    expires 30d;
    add_header Cache-Control "public, immutable";
}

# API 反向代理
location /api/ {
    proxy_pass http://backend:8000/;
    include /etc/nginx/proxy_params;
}

# 正则匹配图片
location ~* \.(jpg|jpeg|png|gif|ico|svg|webp)$ {
    expires 7d;
    add_header Cache-Control "public";
}

5. 反向代理

基础反向代理

# /etc/nginx/conf.d/myapp.conf
upstream backend {
    server 127.0.0.1:8000;
}

server {
    listen 80;
    server_name api.example.com;

    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;

        # 超时设置
        proxy_connect_timeout 60s;
        proxy_read_timeout 60s;
        proxy_send_timeout 60s;

        # 缓冲区
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 4k;
    }
}

创建 proxy_params 文件(复用)

# /etc/nginx/proxy_params
proxy_set_header Host $http_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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;  # WebSocket

6. HTTPS 配置

手动证书

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

    ssl_certificate /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;

    # SSL 优化
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;
    ssl_session_tickets off;

    # 现代 TLS 配置(来自 Mozilla SSL Config Generator)
    ssl_protocols TLSv1.2 TLSv1.3;
    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 off;

    # HSTS
    add_header Strict-Transport-Security "max-age=63072000" always;

    location / {
        proxy_pass http://backend;
        include /etc/nginx/proxy_params;
    }
}

# HTTP 重定向到 HTTPS
server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

Let's Encrypt(Certbot)

# 安装 certbot
apt install certbot python3-certbot-nginx

# 自动申请证书并配置 Nginx
certbot --nginx -d example.com -d www.example.com

# 自动续期测试
certbot renew --dry-run

# 自动续期(通常 certbot 安装时会自动创建 cron 任务)
# 0 12 * * * /usr/bin/certbot renew --quiet

7. 负载均衡

upstream backend {
    # 轮询(默认)
    server 10.0.0.1:8000;
    server 10.0.0.2:8000;
    server 10.0.0.3:8000;

    # 权重
    server 10.0.0.1:8000 weight=3;
    server 10.0.0.2:8000 weight=1;

    # IP Hash(同一 IP 总路由到同一服务器,保持会话)
    ip_hash;

    # 最少连接数
    least_conn;

    # 健康检查(商业版 Nginx Plus 支持主动检查,开源版用 max_fails)
    server 10.0.0.1:8000 max_fails=3 fail_timeout=30s;
    server 10.0.0.2:8000 backup;  # 备用服务器
}

8. 常用功能

Gzip 压缩

http {
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;       # 小于 1KB 不压缩
    gzip_comp_level 6;          # 压缩级别 1-9(6 是性价比最高)
    gzip_types
        text/plain
        text/css
        text/javascript
        application/javascript
        application/json
        application/xml
        image/svg+xml;
}

限流

http {
    # 定义限流区域($binary_remote_addr 按 IP 限流)
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=login:10m rate=1r/m;

    server {
        # API 接口:每秒 10 个请求,允许突发 20 个
        location /api/ {
            limit_req zone=api burst=20 nodelay;
            limit_req_status 429;
            proxy_pass http://backend;
        }

        # 登录接口:每分钟 1 次(防止暴力破解)
        location /api/login {
            limit_req zone=login;
            proxy_pass http://backend;
        }
    }
}

跨域(CORS)

location /api/ {
    add_header Access-Control-Allow-Origin "https://frontend.example.com" always;
    add_header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
    add_header Access-Control-Allow-Credentials "true" always;

    if ($request_method = OPTIONS) {
        add_header Access-Control-Max-Age 1728000;
        add_header Content-Length 0;
        return 204;
    }

    proxy_pass http://backend;
}

WebSocket 代理

http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        "" close;
    }

    server {
        location /ws/ {
            proxy_pass http://backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            proxy_read_timeout 3600s;  # WebSocket 长连接,加大超时
        }
    }
}

9. 完整 FastAPI 部署配置

# /etc/nginx/conf.d/fastapi.conf

upstream fastapi {
    server 127.0.0.1:8000;
    keepalive 32;  # 保持连接池
}

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

    ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;

    # 安全头
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # 文件上传大小限制
    client_max_body_size 10M;

    # API 文档(不限流)
    location ~ ^/(docs|redoc|openapi.json)$ {
        proxy_pass http://fastapi;
        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 https;
    }

    # API 接口(限流)
    location /api/ {
        limit_req zone=api burst=30 nodelay;
        proxy_pass http://fastapi;
        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 https;
        proxy_http_version 1.1;
        proxy_set_header Connection "";  # HTTP keepalive
    }

    # WebSocket
    location /ws/ {
        proxy_pass http://fastapi;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_read_timeout 3600s;
    }
}

server {
    listen 80;
    server_name api.example.com;
    return 301 https://$host$request_uri;
}

10. 前端 SPA 部署配置

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    root /var/www/dist;
    index index.html;

    # SPA 路由:所有路径回退到 index.html
    location / {
        try_files $uri $uri/ /index.html;
    }

    # 静态资源(Vite 构建的哈希文件名,永久缓存)
    location ~* \.(js|css|woff2?|ttf|eot|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # 图片缓存
    location ~* \.(jpg|jpeg|png|gif|ico|webp)$ {
        expires 30d;
        add_header Cache-Control "public";
    }

    # 接口代理(前后端同域,避免跨域)
    location /api/ {
        proxy_pass http://backend:8000/api/;
        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 https;
    }
}

11. 常用命令

# 测试配置文件语法
nginx -t

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

# 优雅停止
nginx -s quit

# 强制停止
nginx -s stop

# 查看进程
ps aux | grep nginx

# Docker 中重载
docker exec nginx nginx -s reload
docker compose exec nginx nginx -s reload

12. 踩坑与注意事项

proxy_pass 末尾斜杠的影响

# 有斜杠:转发时去掉 location 前缀
location /api/ {
    proxy_pass http://backend/;
    # /api/users → http://backend/users
}

# 无斜杠:转发时保留 location 前缀
location /api/ {
    proxy_pass http://backend;
    # /api/users → http://backend/api/users
}

add_header 不能继承

子 location 块使用 add_header 后,父块的 add_header 会失效。需在每个 location 都添加,或使用 headers-more-nginx-module 模块。

配置修改后必须 reload

# 先测试语法,再重载
nginx -t && nginx -s reload

最佳实践

每次修改配置前先 nginx -t 测试语法:直接 reload 语法错误的配置会导致 Nginx 拒绝加载新配置(保留旧配置运行),但部分情况下会导致 worker 进程退出,服务中断。养成 nginx -t && nginx -s reload 的习惯。

include 拆分配置文件:把每个虚拟主机的 server 块拆到 /etc/nginx/conf.d/sites-enabled/ 目录下,主配置文件保持简洁,也方便用 Ansible / 脚本管理多站点。

# nginx.conf
http {
    include /etc/nginx/conf.d/*.conf;
}

代理后端时设置必要的 Header:不传 X-Real-IPHost 会导致后端看到的客户端 IP 是 Nginx 的 IP,以及 Host 不正确。

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;
}

静态文件用 root 而非 alias:两者行为不同,alias 需要精确匹配 location 路径,用错会导致 404。静态文件优先考虑 root

开启 Gzip 压缩减少传输体积:HTML/CSS/JS 文件 Gzip 后通常减少 60–80% 体积,对首屏性能影响显著。

gzip on;
gzip_types text/plain text/css application/json application/javascript;
gzip_min_length 1024;
gzip_comp_level 6;

常见陷阱

陷阱:proxy_pass 末尾斜杠影响路径拼接

现象: location /api/ 配置后,访问 /api/users 有时转发到 http://backend/users,有时是 http://backend/api/users,行为不一致。

原因: proxy_pass 末尾有无 / 决定是否保留 location 路径:

  • proxy_pass http://backend(无斜杠):保留完整 URI(/api/users/api/users
  • proxy_pass http://backend/(有斜杠):去掉 location 前缀(/api/users/users

解决: 明确选择语义,并与后端路由约定一致。

# 转发包含 /api 前缀
location /api/ { proxy_pass http://backend; }    # /api/users → /api/users

# 去掉 /api 前缀再转发
location /api/ { proxy_pass http://backend/; }   # /api/users → /users

陷阱:add_header 只在当前 location 生效,子 location 不继承

现象:server 块设置了 CORS header,但某个 location 内没有该 header。

原因: add_header 在子 location 块中不继承父级的 add_header 指令。子 location 只要有自己的 add_header,父级的全部失效。

解决: 在每个需要 header 的 location 块内都显式添加,或使用 headers-more-nginx-module(需要编译安装)。

location /api/ {
    add_header Access-Control-Allow-Origin *;   # 必须在此重复声明
    proxy_pass http://backend/;
}

陷阱:WebSocket 代理不加 Upgrade header 导致连接失败

现象: 前端 WebSocket 连接到 Nginx 代理后报 101 Switching Protocols 失败,或 1006 Connection closed abnormally

原因: WebSocket 升级需要在 HTTP/1.1 之上协商,Nginx 默认用 HTTP/1.0 和后端通信,且不传递 Upgrade header。

解决: 在 WebSocket location 块中设置 proxy_http_version 1.1 并传递 Upgrade 相关 header。

location /ws/ {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade    $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 3600s;   # WebSocket 长连接,防止超时断开
}

参见

阅读更多

Web 安全基础

1. HTML 转义(服务端渲染必须): 2. CSP(Content Security Policy): 3. HttpOnly Cookie:防止 JS 读取会话 Cookie: 4. 前端框架防护: 攻击者在第三方网站构造一个表单,诱导已登录用户提交,浏览器会自动携带目标站的 Cookie。 触发条件: 1. 用户已登录目标网站(Cookie 有效) 2. 目标 API 仅凭 Cookie 识别用户身份 3. 请求来源未验证 1. CSRF Token(推荐): 2. SameSite Cookie: 3. 验证 Origin/Referer 头:

By yellowdog

HTTP 协议深度指南

HTTP(HyperText Transfer Protocol)是 Web 的基础传输协议,基于 TCP/IP,采用请求/响应模型。 相关文档:Web安全基础(/web-an-quan-ji-chu/) FastAPI完全指南(/fastapi-wan-quan-zhi-nan/) Nginx完全指南(/nginx-wan-quan-zhi-nan/) 幂等性:多次执行相同请求,服务器状态结果相同。PUT /users/1 多次执行结果一致;POST /users 每次创建新资源,非幂等。 浏览器直接从本地缓存读取,不向服务器发送请求。 缓存命中时,状

By yellowdog

系统设计基础

SLA 对照表: 选择建议:无状态服务(Web 层、API 层)优先水平扩展;数据库初期垂直扩展,达到瓶颈后考虑分库分表或读写分离。 缓存穿透(查询不存在的 key,每次都打到 DB): 缓存击穿(热点 key 过期,瞬间大量请求打到 DB): 缓存雪崩(大量 key 同时过期,或缓存服务宕机): 令牌桶 Python 实现: Redis 实现分布式限流(滑动窗口): URL 命名规则: Cursor 分页响应格式: 雪花算法结构(64 bit): 定义:分布式系统不能同时满足以下三个特性: 在分布式环境中 P 是必须保证的,所以实际是 CP vs AP

By yellowdog

算法思路与模板

二分查找要求序列有序,每次将搜索范围缩减一半,时间复杂度 O(log n)。 两个指针从两端向中间收缩,常用于有序数组。 滑动窗口维护一个满足条件的区间 left, right,right 不断向右扩张,条件不满足时收缩 left。 滑动窗口通用框架: 1. 确定"子问题":原问题可以分解为哪些规模更小的同类问题 2. 定义 dpi 或 dpij 的含义,要足够清晰 3. 推导状态转移方程 4. 确定初始状态(边界条件) 5. 确定计算顺序(确保依赖的子问题先计算) 每件物品最多选一次。dpj = 容量为 j 时的最大价值,逆序遍历容量防止重复选取。 每

By yellowdog