Chapter 10

实战与部署

把前九章的知识拼成一套完整的生产方案:前端 SPA + 后端 API + HTTPS,容器化运行,配上日志、checklist 与故障排查手册。

10.1 核心概念

SPA 部署(Single-Page Application)
前端打包成静态文件(React/Vue 的 dist),Nginx 发静态资源并用 try_files 回退到 index.html 支持前端路由。
API 反代同域
/api/ 反代到后端服务,让前后端同域,从根本上规避跨域(CORS)问题,也统一了入口和 HTTPS。
Docker 化 Nginx
用官方 nginx 镜像跑 Nginx,把配置和静态文件挂载或打包进镜像,实现环境一致、可复制部署。
多站点(Multi-tenant)
一台 Nginx 通过多个 server 块 + include 拆分,托管多个域名/项目,各自独立配置。
日志分析
从 access.log / error.log 中统计流量、状态码、慢请求,定位性能与故障——排障的第一手资料。
配置 checklist
上线前的核对清单:语法校验、TLS、安全头、限流、日志、reload 而非 restart,确保稳妥上线。

10.2 完整生产配置:SPA + API + HTTPS

# /etc/nginx/conf.d/app.conf

upstream api_backend {
    server  127.0.0.1:3000;
    keepalive  32;
}

# HTTP 只做跳转
server {
    listen  80;
    server_name  app.example.com;
    return  301  https://$host$request_uri;
}

# HTTPS 主站
server {
    listen  443  ssl;
    http2  on;
    server_name  app.example.com;

    ssl_certificate      /etc/letsencrypt/live/app.example.com/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/app.example.com/privkey.pem;
    ssl_protocols  TLSv1.2 TLSv1.3;
    ssl_session_cache  shared:SSL:10m;

    add_header  Strict-Transport-Security  "max-age=31536000; includeSubDomains"  always;

    root  /var/www/app/dist;

    # API 反代(前后端同域,无 CORS)
    location /api/ {
        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;
    }

    # 带哈希指纹的静态资源,长缓存
    location /assets/ {
        expires  1y;
        add_header  Cache-Control  "public, immutable";
    }

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

10.3 用 Docker 运行 Nginx

# Dockerfile —— 多阶段:构建前端 + 打进 Nginx 镜像
FROM node:20 AS build
WORKDIR /app
COPY . .
RUN npm ci && npm run build

FROM nginx:1.27-alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
# 官方镜像默认前台运行 nginx,无需 CMD
# 或直接挂载运行,改配置无需重建镜像
$ docker run -d --name web -p 80:80 \
    -v $(pwd)/dist:/usr/share/nginx/html:ro \
    -v $(pwd)/nginx.conf:/etc/nginx/conf.d/default.conf:ro \
    nginx:1.27-alpine

# 改完配置后热重载容器内 Nginx
$ docker exec web nginx -s reload
容器里日志走标准输出

官方 nginx 镜像已把 access.log 软链到 /dev/stdout、error.log 到 /dev/stderr,日志直接进 docker logs 和日志采集系统。别再在容器里配写文件日志——那会让日志收集失灵。

10.4 多站点托管

# 每个项目一个文件,主配置统一 include
# /etc/nginx/conf.d/blog.conf、shop.conf、admin.conf ...
http {
    include  /etc/nginx/conf.d/*.conf;
}

# 各文件里各写各的 server 块,靠 server_name 区分
server { server_name  blog.example.com;  root /var/www/blog; }
server { server_name  shop.example.com;  root /var/www/shop; }

10.5 日志分析常用命令

# 访问量 Top 10 的 IP
$ awk '{print $1}' access.log | sort | uniq -c | sort -rn | head

# 各状态码分布
$ awk '{print $9}' access.log | sort | uniq -c | sort -rn

# 找 5xx 错误请求
$ awk '$9 ~ /^5/' access.log | tail -20

# 实时盯错误日志
$ tail -f /var/log/nginx/error.log

10.6 上线配置 checklist

检查项命令 / 说明
配置语法nginx -t 通过
用 reload 而非 restartsystemctl reload nginx
HTTPS 与跳转80→443、证书有效、自动续期已装
安全头HSTS / X-Frame-Options / server_tokens off
限流登录、API 有 limit_req
gzip / 缓存头文本压缩、静态资源长缓存
请求体上限client_max_body_size 匹配业务
日志access/error 正常写,或走 stdout
SPA 回退try_files 到 index.html 生效

10.7 常见故障排查

现象可能原因与排查
502 Bad Gateway后端没起 / 端口错 / 崩溃。查后端进程、error.log、proxy_pass 地址
504 Gateway Timeout后端太慢。调大 proxy_read_timeout,或优化后端
404(SPA 刷新)缺 try_files 回退,加 try_files $uri /index.html;
403 Forbidden文件权限 / autoindex 关 / deny 命中。查目录权限与 error.log
413 请求体过大调大 client_max_body_size
改配置不生效忘了 reload;或 nginx -t 没过沿用旧配置;或改动需 restart
CORS 报错前后端未同域,用 /api/ 反代到同域即可根治
502 的头号嫌疑

看到 502 别急着改 Nginx——九成是后端本身没运行、崩溃或监听地址不对。第一步永远是确认后端进程健在(curl 127.0.0.1:3000 直连试试),再看 error.log 里 Nginx 报的 connect() failed 具体信息。

结课

从事件驱动架构,到 server/location 匹配、静态服务、反向代理、负载均衡、HTTPS、缓存、安全,再到这份完整的生产部署方案——你已经掌握了用 Nginx 搭建现代 web 入口所需的全部核心技能。剩下的,就是在真实项目里把它们用熟。

10.8 全课总结