主题
10 · 实战:一份生产级 Nginx 配置
你已经学完了 9 章基础知识,这一章我们把所有知识揉成一份真实可用、能直接抄的 nginx.conf——前端 SPA + 后端 API + WebSocket + 多后端 + HTTPS + 缓存压缩 + 监控全套,配套 docker-compose 一键起。
1. 业务场景
┌────────────────┐
│ Internet │
└────────┬───────┘
│
▼
┌────────────────┐
│ Nginx │ :80, :443
│ (网关 / 入口) │
└────────┬───────┘
┌──────────────┼──────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌──────────┐
│ / → │ │ /api/ → │ │ /ws/ → │
│ SPA 前端│ │ 3 个 Node│ │ Go WS │
│ dist/ │ │ (LB) │ │ Service │
└─────────┘ └─────────┘ └──────────┘功能清单:
- ✅ HTTPS(HTTP/2、HSTS、A+ 评分)
- ✅ SPA fallback(history 模式刷新不 404)
- ✅ API 反向代理 + 负载均衡(3 台后端)
- ✅ WebSocket 反向代理
- ✅ 静态资源强缓存 + 接口短缓存
- ✅ gzip 压缩
- ✅ 限流(防恶意刷接口)
- ✅ 健康检查端点
- ✅ access 日志带 RT / upstream RT
- ✅ 安全响应头
2. 完整目录结构
deploy/
├── docker-compose.yml ← 一键起所有服务
├── nginx/
│ ├── nginx.conf ← 主配置(main + events + http)
│ ├── conf.d/
│ │ ├── default.conf ← 业务 server 块
│ │ └── upstream.conf ← upstream 后端池
│ └── certs/ ← Let's Encrypt 证书
├── html/ ← 前端打包产物
│ ├── index.html
│ └── assets/
└── logs/
├── access.log
└── error.log3. 各文件简介
3.1 nginx.conf · 主配置
参见"💻 示例代码"中的 nginx.conf。关键看点:
worker_processes auto、worker_connections 10240- 自定义
log_format带上$request_time、$upstream_response_time(强烈建议) - 全局开 gzip
limit_req_zone全局定义,子 location 引用
3.2 upstream.conf · 后端池
nginx
upstream api_backend {
least_conn;
keepalive 64;
server 10.0.0.11:3000 weight=2 max_fails=3 fail_timeout=30s;
server 10.0.0.12:3000 weight=2 max_fails=3 fail_timeout=30s;
server 10.0.0.13:3000 weight=1 max_fails=3 fail_timeout=30s;
server 10.0.0.99:3000 backup;
}
upstream ws_backend {
server 10.0.0.20:4000;
server 10.0.0.21:4000;
}3.3 default.conf · 业务路由
参见"💻 示例代码"。主要看点:
- 80 → 443 强制跳转
- 443 server 配 SSL + HTTP/2 + HSTS
- 5 个 location:SPA / 静态资源 / API / WS / health
- API 加了
limit_req限流 - 有
error_page兜底
3.4 docker-compose.yml
参见"💻 示例代码"。一行 docker compose up -d 起 Nginx + 模拟 3 个 Node 后端。
4. 部署流程(5 分钟搞定)
bash
# 1. 克隆 / 准备代码
git clone <你的仓库>
cd deploy
# 2. 把前端打包结果放到 html/ 目录
cp -r ~/myapp/dist/* html/
# 3. (首次)申请证书
docker run --rm -it \
-v $PWD/nginx/certs:/etc/letsencrypt \
-v $PWD/html:/var/www/html \
-p 80:80 \
certbot/certbot certonly --standalone -d example.com -d www.example.com
# 4. 启动
docker compose up -d
# 5. 看日志
docker compose logs -f nginx
# 6. 验证
curl -I https://example.com/ # 应该返回 200 + 一堆安全头
curl -I https://example.com/api/healthz # 应该 200
curl -I https://example.com/static/index.js # X-Cache-Status: ...
# 7. 改完配置 reload(不断现有连接)
docker compose exec nginx nginx -t && \
docker compose exec nginx nginx -s reload5. 调试排错命令小抄
bash
# 看 nginx 进程
docker compose exec nginx ps aux | grep nginx
# 检测语法
docker compose exec nginx nginx -t
# 看 access log(带 rt / urt)
tail -f logs/access.log
# 慢请求 Top 10
awk '{print $NF, $7}' logs/access.log | sort -rn | head
# 5xx Top 10
awk '$9>=500' logs/access.log | awk '{print $7, $9}' | sort | uniq -c | sort -rn | head
# 实时 QPS
tail -f logs/access.log | awk '{print $4}' | uniq -c
# 看后端 RT
awk '{print $NF}' logs/access.log | awk -F'urt=' '{print $2}'6. 上线 Checklist(直接抄)
上线前对一遍这 12 项,能避免 90% 的事故。
- [ ]
nginx -t通过 - [ ] 配 HTTPS + HTTP/2 + HSTS
- [ ] 80 → 443 强制 301
- [ ] SPA fallback
try_files $uri $uri/ /index.html - [ ] API
proxy_set_header Host / X-Real-IP / X-Forwarded-For / X-Forwarded-Proto - [ ] WebSocket 三件套(Upgrade / Connection / read_timeout)
- [ ] gzip 开启 + 类型够全
- [ ] 静态资源带 hash +
immutable强缓存 - [ ] HTML
no-cache - [ ]
client_max_body_size调大(按业务) - [ ]
limit_req限流防刷 - [ ] 监控告警(5xx 率、RT、QPS)
- [ ] 日志轮转(logrotate / docker
max-size) - [ ] 证书自动续签(cron / systemd timer)
7. 进阶方向(学完这 10 章之后)
| 方向 | 推荐工具 | 一句话 |
|---|---|---|
| 主动健康检查 / 动态配置 | Tengine / OpenResty | 阿里 / 腾讯都在用,开源版的"加强版 Nginx" |
| 现代 API 网关 | APISIX / Kong | 基于 Nginx,有控制台、支持热加载和插件 |
| Kubernetes 入口控制器 | ingress-nginx | K8s 原生路由,工程师标配 |
| Service Mesh | Envoy / Istio | 下一代代理,内部服务间通信用 |
| 在 Nginx 里写业务逻辑 | OpenResty + Lua | 限流 / 鉴权 / WAF 都能在边缘搞定 |
| 性能调优 | wrk、hey、/proc 指标 | 压测找瓶颈、调 worker_connections / so_keepalive |
8. 一句话总结这 10 章
Nginx 的工作 = 路由 + 缓存 + 流量管控——10 个章节、3 个 demo、1 份生产配置,已经把这 3 件事讲透了。后续你需要的,都是在此基础上的"做大、做精、做稳"。
下一站 → QA · 高频面试题(30+):把所学转化为面试白板上的子弹。
💻 示例代码
💻 示例代码
txt
###############################################################################
# default.conf · 业务入口(SPA + API + WebSocket)
###############################################################################
# ============================================================
# HTTP → HTTPS 301 跳转
# ============================================================
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# 留给 Let's Encrypt 验证
location /.well-known/acme-challenge/ {
root /var/www/html;
}
location / {
return 301 https://$host$request_uri;
}
}
# ============================================================
# HTTPS 主站
# ============================================================
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# ---- 证书 ----
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# ---- TLS 配置(A+) ----
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
# ---- 安全响应头 ----
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# ---- 站点根目录(前端打包产物) ----
root /var/www/html;
index index.html;
# ============================================================
# 1. 健康检查(Nginx 自身)
# ============================================================
location = /healthz {
access_log off;
return 200 "ok\n";
add_header Content-Type text/plain;
}
# ============================================================
# 2. API 反向代理 + 限流 + 短缓存
# ============================================================
location /api/ {
# 限流:每 IP 20 r/s,突发 40
limit_req zone=api_limit burst=40 nodelay;
proxy_pass http://api_backend/;
proxy_http_version 1.1;
proxy_set_header Connection "";
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 5s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
proxy_next_upstream error timeout http_502 http_503 http_504;
proxy_next_upstream_tries 2;
proxy_next_upstream_timeout 10s;
# 仅 GET /api/products 这类接口可短缓存(按需开启)
# proxy_cache api_cache;
# proxy_cache_valid 200 5m;
# proxy_cache_key "$scheme$request_method$host$request_uri";
# proxy_cache_bypass $http_authorization $cookie_nocache;
# proxy_no_cache $http_authorization $cookie_nocache;
# add_header X-Cache-Status $upstream_cache_status always;
}
# ============================================================
# 3. WebSocket
# ============================================================
location /ws/ {
proxy_pass http://ws_backend/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
# ============================================================
# 4. 静态资源(带 hash → 强缓存 1 年)
# ============================================================
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable" always;
access_log off;
}
location ~* \.[a-f0-9]{8,}\.(?:js|css|png|jpg|webp|svg|woff2?)$ {
expires 1y;
add_header Cache-Control "public, immutable" always;
access_log off;
}
# ============================================================
# 5. SPA history 模式 fallback
# ============================================================
location = /index.html {
expires -1;
add_header Cache-Control "no-cache, must-revalidate" always;
}
location / {
try_files $uri $uri/ /index.html;
}
# ============================================================
# 6. 隐藏文件 / 错误页
# ============================================================
location ~ /\. {
deny all;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}yaml
version: "3.8"
# 一键起 Nginx + 3 个模拟后端 + 1 个 WebSocket 服务
# 前置:把前端 dist 拷贝到 ./html 目录
services:
nginx:
image: nginx:1.25-alpine
container_name: gateway
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./conf.d:/etc/nginx/conf.d:ro
- ./certs:/etc/letsencrypt:ro
- ./html:/var/www/html:ro
- ./logs:/var/log/nginx
depends_on:
- api1
- api2
- api3
- ws1
networks: [edge]
# ----- 模拟 3 个后端:用 hashicorp/http-echo 起一个返回 JSON 的 mock -----
api1:
image: hashicorp/http-echo:latest
command: ["-listen=:3000", "-text={\"server\":\"api1\",\"data\":\"hello\"}"]
networks: [edge]
api2:
image: hashicorp/http-echo:latest
command: ["-listen=:3000", "-text={\"server\":\"api2\",\"data\":\"hello\"}"]
networks: [edge]
api3:
image: hashicorp/http-echo:latest
command: ["-listen=:3000", "-text={\"server\":\"api3\",\"data\":\"hello\"}"]
networks: [edge]
api4:
image: hashicorp/http-echo:latest
command: ["-listen=:3000", "-text={\"server\":\"backup\",\"data\":\"hello\"}"]
networks: [edge]
# ----- WebSocket 用一个简单 echo(生产换成你自己的服务)-----
ws1:
image: solsson/websocat
command: ["-s", "0.0.0.0:4000"]
networks: [edge]
ws2:
image: solsson/websocat
command: ["-s", "0.0.0.0:4000"]
networks: [edge]
networks:
edge:
driver: bridgetxt
###############################################################################
# nginx.conf · 生产级主配置
###############################################################################
user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
use epoll;
worker_connections 10240;
multi_accept on;
accept_mutex off;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# ------- 日志:带请求时长 / upstream 时长,方便排障 -------
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time uct="$upstream_connect_time" '
'urt="$upstream_response_time" '
'cache="$upstream_cache_status"';
access_log /var/log/nginx/access.log main;
# ------- 性能 -------
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 1000;
server_tokens off;
client_max_body_size 50m;
# ------- gzip 压缩 -------
gzip on;
gzip_min_length 1k;
gzip_comp_level 5;
gzip_vary on;
gzip_proxied any;
gzip_types
text/plain text/css text/xml
application/json application/javascript application/xml+rss
image/svg+xml;
# ------- 限流:每 IP 每秒 20 个 API 请求 -------
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=20r/s;
limit_req_status 429;
# ------- proxy_cache 区 -------
proxy_cache_path /var/cache/nginx
levels=1:2
keys_zone=api_cache:50m
max_size=2g
inactive=60m
use_temp_path=off;
# ------- 上游池 / 业务 server 拆到子文件 -------
include /etc/nginx/conf.d/*.conf;
}txt
###############################################################################
# upstream.conf · 后端服务池定义
###############################################################################
# ------- API 后端:3 台 + 1 备用 -------
upstream api_backend {
least_conn;
keepalive 64;
server api1:3000 weight=2 max_fails=3 fail_timeout=30s;
server api2:3000 weight=2 max_fails=3 fail_timeout=30s;
server api3:3000 weight=1 max_fails=3 fail_timeout=30s;
server api4:3000 backup;
}
# ------- WebSocket 后端 -------
upstream ws_backend {
ip_hash; # 同一用户固定一台(保证连接粘性)
keepalive 32;
server ws1:4000 max_fails=3 fail_timeout=30s;
server ws2:4000 max_fails=3 fail_timeout=30s;
}default.conf ↗ · docker-compose.yml ↗ · nginx.conf ↗ · upstream.conf ↗