配置 nginx 反向代理
目标
能够将 nginx 配置为反向代理,并按照生产实践配置转发请求头、超时、正文大小、压缩、静态资源分离、 访问阻止和日志格式。
为什么重要
六行代理配置不应靠背诵,而应通过缺少它们时会发生什么来记忆。
如果不转发 Host,应用程序生成的绝对 URL 会变成 127.0.0.1:8080,
导致支付回调无法返回。如果没有 X-Forwarded-For,所有访问记录都会显示为代理 IP,
审计时将无从回答。如果没有 X-Forwarded-Proto,则会发生无限重定向循环。
此外,如果不知道 client_max_body_size 的默认值是 1MB,就可能在后端日志毫无记录的情况下,
花费数天排查文件上传故障。
步骤
- 准备:启动 Tomcat,并将
/opt/lab/samples/labhub-1.0.0.war部署为/opt/tomcat/webapps/labhub.war。 nginx 工作目录使用/root/ng。 - 编写
/root/ng/nginx.conf并启动 nginx。 监听端口 8088,并将/代理到http://127.0.0.1:8080。http://127.0.0.1:8088/labhub/version必须返回 200。 - 配置四个代理请求头并 reload。
Host、X-Real-IP、X-Forwarded-For、X-Forwarded-Proto。 检查:curl -s http://127.0.0.1:8088/labhub/echo返回的 JSON 中 必须包含x-forwarded-for和x-forwarded-proto, 且host的值不能是127.0.0.1:8080。 - 配置
proxy_connect_timeout 3s、proxy_send_timeout 30s、proxy_read_timeout 60s。 - 将
client_max_body_size设置为20m并 reload。 5MB 正文的 POST 不应返回 413,25MB 正文的 POST 必须返回 413。 - 配置
gzip on、gzip_min_length 1000、gzip_vary on, 并在gzip_types中加入application/json。curl -H 'Accept-Encoding: gzip' -I http://127.0.0.1:8088/labhub/big.html的 响应中必须包含Content-Encoding: gzip。 - 创建
/root/ng/static/app.js文件(内容不限), 并将其配置为通过/assets/路径提供服务。也就是说,http://127.0.0.1:8088/assets/app.js必须返回 200, 且响应头中必须包含Expires或Cache-Control。 - 配置所有以
/manager/开头的请求返回 403。http://127.0.0.1:8088/manager/html必须返回 403。 - 定义
log_format,使其包含$upstream_addr、$upstream_status、$upstream_response_time、$request_time四个变量, 并将访问日志写入/root/ng/logs/access.log。 reload 后发送一次请求,日志必须确实得到写入。
参考
- 启动:
nginx -c /root/ng/nginx.conf -p /root/ng - 语法检查:
nginx -t -c /root/ng/nginx.conf -p /root/ng - 重新应用:
nginx -s reload -c /root/ng/nginx.conf -p /root/ng - 发送大正文:
head -c 26000000 /dev/zero | curl -s -o /dev/null -w '%{http_code}' --data-binary @- <URL> - 常见错误 1:反复添加或删除
proxy_pass后面的斜杠,导致 404。 如果存在 URI 部分,与 location 匹配的部分会被截掉。 - 常见错误 2:遗漏
events {}块。它是 nginx.conf 的必需内容。 - 常见错误 3:未创建日志目录就 reload,导致启动失败。
最小代理配置与启动
编写 /root/ng/nginx.conf 并启动 nginx。
监听端口 8088,并将 / 代理到 http://127.0.0.1:8080。
http://127.0.0.1:8088/labhub/version 必须返回 200。
nginx 可以用 -c 指定配置文件,用 -p 指定 prefix(相对路径的基准)。请记住,此环境无法绑定低于 1024 的端口。养成启动前先用 -t 检查语法的习惯。
配置转发请求头
配置四个代理请求头并 reload。
Host、X-Real-IP、X-Forwarded-For、X-Forwarded-Proto。
检查:curl -s http://127.0.0.1:8088/labhub/echo 返回的 JSON 中
必须包含 x-forwarded-for 和 x-forwarded-proto,
且 host 的值不能是 127.0.0.1:8080。
有一个端点可以确认后端实际收到了什么。请亲自检查不转发 Host 时,后端看到的 Host 会是什么。
三类代理超时
配置 proxy_connect_timeout 3s、proxy_send_timeout 30s、proxy_read_timeout 60s。
连接、发送、读取超时分别测量不同区段。思考 504 与其中哪一种关系最密切。
限制请求正文大小
将 client_max_body_size 设置为 20m 并 reload。
5MB 正文的 POST 不应返回 413,25MB 正文的 POST 必须返回 413。
超过此限制时,nginx 会直接响应,因此后端日志中不会留下任何痕迹。只有知道默认值是多少,才能迅速定位文件上传故障。
压缩响应
配置 gzip on、gzip_min_length 1000、gzip_vary on,
并在 gzip_types 中加入 application/json。
curl -H 'Accept-Encoding: gzip' -I http://127.0.0.1:8088/labhub/big.html 的
响应中必须包含 Content-Encoding: gzip。
小于最小长度标准的响应不会被压缩。还需要同时启用一个用于防止缓存异常的指令。
分离静态文件
创建 /root/ng/static/app.js 文件(内容不限),
并将其配置为通过 /assets/ 路径提供服务。也就是说,
http://127.0.0.1:8088/assets/app.js 必须返回 200,
且响应头中必须包含 Expires 或 Cache-Control。
当 location 路径与实际目录名不同时,可以使用一个相应的指令。还要一并设置缓存过期响应头。
阻止管理路径
配置所有以 /manager/ 开头的请求返回 403。
http://127.0.0.1:8088/manager/html 必须返回 403。
在代理处阻止访问,无需部署应用程序即可更改策略。请思考正则表达式 location 与前缀 location 的优先级。
用于故障分析的日志格式
定义 log_format,使其包含 $upstream_addr、$upstream_status、
$upstream_response_time、$request_time 四个变量,
并将访问日志写入 /root/ng/logs/access.log。
reload 后发送一次请求,日志必须确实得到写入。
只有同时记录后端耗时和总耗时,才能区分“后端缓慢”和“传输缓慢”。要产生日志,必须实际发送请求。