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-IP 和 Host 会导致后端看到的客户端 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 长连接,防止超时断开
}