Nginx配置深度解析
前端部署的"看门人":静态资源与 SPA 路由怎么配、反向代理怎么解决跨域、负载均衡与限流怎么写,以及 root/alias、location 优先级等易错点。
一句话概括
Nginx 是高性能的 HTTP 服务器和反向代理,事件驱动 + 异步非阻塞,几 MB 内存就能扛上万并发。对前端来说它干三件最实在的事:托管打包后的静态资源、把 API 请求反代到后端(顺手解决跨域)、在多台服务间做负载均衡。
面试常问的不是”你会不会配”,而是”root 和 alias 区别、location 匹配顺序、反向代理怎么透传真实 IP、SPA 刷新 404 怎么解“。这些配错一个,页面就白屏或接口就跨域。
核心知识点
1. SPA 静态部署:最关键的一行 try_files
前端 npm run build 出 dist,交给 Nginx 托管。最容易翻车的点是前端路由刷新 404——浏览器直接请求 /user/123,磁盘上没有这个文件,必须用 try_files 兜底回 index.html。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server {
listen 80;
server_name example.com;
root /var/www/my-app/dist;
index index.html;
# 静态资源:长缓存 + 关日志,省 IO
location ~* \.(js|css|png|jpg|svg|woff2?)$ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
# SPA 路由兜底:先找文件 → 找目录 → 都没有就回 index.html
location / {
try_files $uri $uri/ /index.html;
}
}
try_files $uri $uri/ /index.html 是单页应用部署的命根子:没它,刷新非根路由就 404。
2. 反向代理:跨域的终极解法
前后端分离时,让 Nginx 同时代理页面和 API,浏览器眼里都在同源,跨域自然消失——比在 Node 里写一堆 CORS 中间件优雅得多。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/example.com.pem;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
location /api/ {
proxy_pass http://127.0.0.1:3000; # 转发到 Node 后端
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; # 透传真实客户端 IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket 必须加这两行,否则长连接建立不起来
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
}
}
1
2
3
4
// ❌ 不推荐:把跨域甩给代码层,每个服务都得配一遍
app.use(cors({ origin: 'http://localhost:8080' }));
// ✅ 推荐:Nginx 同域反代,前端根本感知不到跨域
3. 负载均衡:把流量分到多台后端
单台 Node 扛不住时,用 upstream 定义后端组,Nginx 按算法分发。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
upstream backend_nodes {
# 默认 round-robin;可选 least_conn / ip_hash
server 192.168.1.10:3000 weight=5 max_fails=3 fail_timeout=30s;
server 192.168.1.11:3000 weight=3;
server 192.168.1.12:3000 backup; # 备用节点,主全挂才顶上
keepalive 32; # 与后端保持长连接
}
server {
location / {
proxy_pass http://backend_nodes;
proxy_http_version 1.1;
proxy_set_header Connection ""; # 配合 keepalive 必须清空 Connection
}
}
4. 限流与安全:别让后端被刷爆
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 按客户端 IP 限流:每秒 10 个,突发允许 20 个
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
server {
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
limit_req_status 429;
proxy_pass http://backend_nodes;
}
# IP 白名单保护后台
location /admin/ {
allow 192.168.1.0/24;
deny all;
}
}
5. HTTPS 与跳转
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# HTTP 强制跳 HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# HSTS:告诉浏览器以后只走 HTTPS
add_header Strict-Transport-Security "max-age=63072000" always;
}
其实你每天都在用
- 部署 Vue/React 打包产物:
dist丢进root,配try_files兜底路由 - 本地开发联调:
vite/webpack-dev-server的 proxy 本质就是 Nginx 反代思路 - 线上跨域:前后端同域反代,接口直接
/api/xxx调用,不用配 CORS - 刷新子路由白屏:忘了
try_files才会 404,这是新手最常见的部署事故 - 灰度发布:按 Cookie / IP 把部分流量导到新版本(见 FAQ)
- 接口限流防爬虫:
limit_req挡住恶意刷接口 - Gzip 压缩:
gzip on让 JS/CSS 体积砍掉一大半,首屏更快 - WebSocket 代理:聊天室 / 实时推送靠
Upgrade头透传
常见误解(FAQ)
❌ 误区一:”root 和 alias 差不多,随便用”
差很多,配错路径直接 404。root 是拼接完整 URI:
1
2
location /static/ { root /var/www/app; }
# 请求 /static/a.css → 实际读 /var/www/app/static/a.css
alias 是替换掉匹配的 location 部分:
1
2
location /static/ { alias /var/www/app/public/; }
# 请求 /static/a.css → 实际读 /var/www/app/public/a.css
记住:root 拼、alias 换;且 alias 路径末尾必须带 /。
❌ 误区二:”location 写在前面就优先匹配”
Nginx 的 location 不是按顺序,而是按优先级匹配:
1
2
3
4
5
1. = 精确匹配(最高)
2. ^~ 前缀匹配且停止后续正则搜索
3. ~ / ~* 正则匹配(区分/不区分大小写,按出现顺序)
4. 普通前缀 最长前缀匹配
5. / 通用兜底
所以即使正则写在文件后面,也可能优先于前面的普通前缀 location 命中。排配置前先想清楚优先级,否则”明明配了却不生效”。
❌ 误区三:”X-XSS-Protection 加上就安全了”
X-XSS-Protection 这个响应头现代浏览器已废弃并默认关闭(Chrome/Edge 早就不用它,反而可能引入漏洞)。正确做法是靠 CSP(Content-Security-Policy) 限制脚本来源,而不是依赖这个过时的头。生产里可以保留 X-Content-Type-Options: nosniff、Strict-Transport-Security,但别把 XSS 防护押在 X-XSS-Protection 上。
❌ 误区四:”灰度发布就是再起一个 upstream 随便切”
基于 Cookie/IP 的灰度配置里有个常见笔误——有人的示例把 upstream 关键字写成 upstable(少了个 t),Nginx 起都起不来。正确写法:
1
2
3
4
5
6
7
upstream production { server 10.0.1.1:3000; }
upstream canary { server 10.0.1.3:3000; } # 新版本
server {
set $group production;
if ($http_cookie ~* "canary=true") { set $group canary; }
location / { proxy_pass http://$group; }
}
灰度本质是”按规则把一小撮流量导到新版本”,配置要可回滚、可观测,别一刀切。
一句话总结
Nginx 是前端部署的”前门”——用 try_files 兜住 SPA 路由、用反代吃掉跨域、用 upstream 分摊流量、用 limit_req 挡住刷子,搞懂 root/alias 与 location 优先级这两个坑,你部署时就不再靠玄学。