📚 全栈开发学习系列
第 33 篇 · 阶段五:扩展与部署
✅ 阶段一:编程基础(1-8篇) 已完成
✅ 阶段二:Web 后端(9-16篇) 已完成
✅ 阶段三:前端深化(17-25篇) 已完成
✅ 阶段四:跨平台 App(26-30篇) 已完成
📌 阶段五:扩展与部署 进行中
✓ 31 Tauri 桌面应用入门 ✓ 32 Docker 容器化入门 ✓ 33 Nginx 反向代理 34 CI/CD 自动化部署
读完本篇你将能:
✓ 理解反向代理的核心作用与 Nginx 架构
✓ 掌握 Nginx 基础配置:server、location、upstream
✓ 配置反向代理与负载均衡(轮询/权重/IP哈希)
✓ 实现静态资源缓存与 Gzip 压缩优化
✓ 配置 HTTPS 与常见安全加固手段

Nginx 反向代理:从请求转发到负载均衡

全栈开发学习系列 · 第 33 篇 · 阶段五扩展层
📑 本篇目录
一、为什么需要反向代理:从单台服务器说起
二、Nginx 核心概念与安装
三、配置文件结构:events、http、server、location
四、反向代理实战:proxy_pass 详解
五、负载均衡:upstream 与分配策略
六、静态资源优化:缓存与 Gzip 压缩
七、HTTPS 配置与安全加固
八、常见错误与实战练习

一、为什么需要反向代理:从单台服务器说起

早期的 Web 应用很简单——用户请求直接打到一台服务器,服务器处理完返回结果。但随着业务增长,单台服务器很快就扛不住了:流量高峰时响应变慢,服务器挂了全站就崩,而且所有服务都暴露在公网上,安全风险极高。

这时候就需要一个"前台接待",它站在用户和后端服务之间,负责接收所有请求,然后智能地分配给后面的服务器。这就是反向代理(Reverse Proxy)。

💡 生活中的比喻
反向代理就像公司的前台接待。客户(用户)只知道公司地址(域名),不知道具体哪个部门(后端服务)在哪个办公室(端口)。前台收到来访后,根据来访事由(URL路径)把人领到对应的部门,办完事后再把结果反馈给客户。客户全程不知道也不需要知道内部结构。

反向代理 vs 正向代理

很多人会混淆这两个概念,其实区别只在代理的是谁:

对比项 正向代理 反向代理
代理对象 客户端 服务端
典型场景 翻墙、公司内网出口 负载均衡、统一入口
服务端知道谁在访问吗 不知道,只知道代理IP 不知道,只收到代理转发
代表工具 Squid、Shadowsocks Nginx、HAProxy、Traefik

反向代理的五大核心价值

⚖️ 负载均衡
将请求分散到多台后端服务器,避免单点过载,提升整体吞吐量。
🛡️ 安全防护
后端服务不直接暴露公网,所有请求经过代理过滤,降低攻击面。
🚀 性能加速
缓存静态资源、Gzip 压缩、SSL 卸载,减轻后端压力。
🏷️ 统一入口
一个域名下通过路径分发到不同服务,支持多服务统一管理。

二、Nginx 核心概念与安装

Nginx(发音 "engine-x")是一款高性能的 HTTP 和反向代理服务器,由 Igor Sysoev 于 2004 年发布。它以事件驱动、异步非阻塞的架构著称,单台机器就能轻松处理数万并发连接,资源占用却极低。

截至 2026 年 9 月,Nginx 最新稳定版为 1.30.4,主线开发版为 1.31.5。生产环境推荐使用稳定版(Stable),尝鲜新特性可使用主线版(Mainline)。[$TRAE_REF](https://nginx.org/en/download.html)

Nginx 的架构特点

Nginx 采用 Master-Worker 多进程模型:

安装 Nginx

不同系统的安装方式略有差异,以下是最常用的几种:

Bash - 各平台安装命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Ubuntu / Debian
sudo apt update
sudo apt install nginx
# CentOS / RHEL
sudo yum install nginx
# macOS (Homebrew)
brew install nginx
# Docker 方式(推荐本地测试)
docker run -d -p 8080:80 nginx:alpine
# 验证安装
nginx -v # 输出版本号,如 nginx version: nginx/1.30.4

常用运维命令

Bash - Nginx 常用命令
1
2
3
4
5
6
7
8
9
10
11
12
sudo systemctl start nginx # 启动
sudo systemctl stop nginx # 停止
sudo systemctl restart nginx # 重启(会中断服务)
sudo systemctl reload nginx # 平滑重载配置(不中断)⭐
sudo systemctl status nginx # 查看运行状态
nginx -t # 测试配置文件语法 ⭐⭐
nginx -T # 打印完整配置(含 include)
nginx -s reload # 直接发送 reload 信号
nginx -s quit # 优雅退出(处理完请求再停)
nginx -s stop # 立即停止
💡 好习惯:改完配置先 nginx -t,再 reload

三、配置文件结构:events、http、server、location

Nginx 的配置文件默认位于 /etc/nginx/nginx.conf。它采用块指令(block directive)的层级结构,类似 JSON 但用花括号包裹,从外到内逐层缩小作用范围。

四层嵌套结构

Nginx - nginx.conf 层级结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 全局块(main context)
user nginx;
worker_processes auto; # 通常设为 CPU 核心数
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
# events 块:连接处理配置
events {
    worker_connections 1024; # 每个 worker 最大连接数
    use epoll; # Linux 高效事件模型
}
# http 块:HTTP 相关配置(核心)
http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    sendfile on;
    keepalive_timeout 65;
    # server 块:虚拟主机(一个域名对应一个 server)

继续深入,server 块内部还可以有多个 location 块,用于匹配不同 URL 路径:

Nginx - server 与 location 示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
    listen 80; # 监听端口
    server_name example.com; # 匹配的域名
    root /usr/share/nginx/html;
    index index.html index.htm;
    # 精确匹配:访问 / 时返回首页
    location = / {
        try_files $uri $uri/ /index.html;
    }
    # 前缀匹配:/api 开头的请求转发给后端
    location /api/ {
        proxy_pass http://127.0.0.1:3000/;
    }
    # 正则匹配:.jpg .png 等图片设置缓存

location 匹配优先级

这是 Nginx 最容易踩坑的地方。location 有四种匹配方式,优先级从高到低:

修饰符 匹配方式 优先级
= 精确匹配 最高
^~ 前缀匹配(优先于正则) 第二
~ / ~* 正则匹配(区分/不区分大小写) 第三
(无修饰符) 普通前缀匹配 最低

记忆口诀:精确 > 前缀优先(^~) > 正则 > 普通前缀。同级别下正则按书写顺序匹配,前缀匹配取最长的。

四、反向代理实战:proxy_pass 详解

反向代理是 Nginx 最常用的功能之一,核心就是一条 proxy_pass 指令。但这条指令藏着很多细节,尤其是尾部斜杠的问题,几乎每个新手都踩过坑。

最基础的反向代理

假设你有一个 Node.js 应用跑在 127.0.0.1:3000,想用 Nginx 对外暴露 80 端口:

Nginx - 基础反向代理配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
server {
    listen 80;
    server_name api.example.com;
    # 转发客户端真实 IP(后端日志能看到用户 IP)
    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;
    # 所有请求转发到后端 3000 端口
    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_read_timeout 30s; # 后端响应超时
    }
}

proxy_pass 尾部斜杠的坑

这是 Nginx 最经典的面试题。proxy_pass 后面有没有 /,效果完全不同:

配置 用户请求 后端实际收到
proxy_pass http://backend; /api/users /api/users
proxy_pass http://backend/; /api/users /users

原理很简单:如果 proxy_pass 末尾带 /,Nginx 会把 location 匹配到的前缀"替换掉"。不带斜杠则是"拼接"。

💡 实用建议
如果 location 用的是正则匹配(~ 或 ~*),proxy_pass 后面不能带 URI(包括斜杠),否则会报错。这种情况下如果需要去掉前缀,用 rewrite 配合 break 实现。

常用 proxy_* 指令速查

指令 作用 常用值
proxy_set_header 设置转发给后端的请求头 Host / X-Real-IP
proxy_read_timeout 后端响应超时时间 30s / 60s
proxy_connect_timeout 与后端建立连接超时 10s
proxy_buffering 是否缓冲后端响应 on(默认)
proxy_redirect 修改后端返回的重定向地址 default
proxy_pass_request_body 是否转发请求体 on(默认)

五、负载均衡:upstream 与分配策略

当单台后端服务器扛不住流量时,就需要把请求分散到多台服务器上。Nginx 通过 upstream 块定义服务器组,然后把 proxy_pass 指向这个组,就能自动分配流量了。

基础配置

Nginx - upstream 负载均衡基础配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 在 http 块内定义 upstream 服务器组
upstream backend_servers {
    server 192.168.1.101:3000; # 后端服务器 1
    server 192.168.1.102:3000; # 后端服务器 2
    server 192.168.1.103:3000; # 后端服务器 3
}
# 在 server 块中使用
server {
    listen 80;
    server_name api.example.com;
    location / {
        proxy_pass http://backend_servers;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

五种分配策略

Nginx 提供了多种负载均衡算法,各有适用场景:

策略 说明 适用场景 模块
轮询(默认) 按顺序逐个分配 服务器配置相近 内置
weight 权重 按权重比例分配 服务器性能不均 内置
ip_hash 按客户端 IP 哈希分配 需要 session 保持 内置
least_conn 分配给连接数最少的 请求处理时间差异大 内置
fair 按响应时间分配(第三方) 追求最快响应 nginx-upstream-fair

权重 + 健康检查示例

实际项目中,服务器配置通常不完全一样,可以通过 weight 调整分配比例,用 backup 标记备用机,用 down 标记停机维护的服务器:

Nginx - 权重、备份与失败剔除配置
1
2
3
4
5
6
7
8
9
10
11
12
13
upstream backend_servers {
    # 服务器 A:高性能,分配 5 份流量
    server 192.168.1.101:3000 weight=5 max_fails=3 fail_timeout=30s;
    # 服务器 B:普通性能,分配 2 份流量
    server 192.168.1.102:3000 weight=2 max_fails=3 fail_timeout=30s;
    # 服务器 C:备用机,只有上面都挂了才启用
    server 192.168.1.103:3000 backup;
    # 服务器 D:正在维护,暂时不参与分配
    server 192.168.1.104:3000 down;
}

max_fails 和 fail_timeout 是 Nginx 内置的被动健康检查机制:在 fail_timeout 时间内,如果失败次数达到 max_fails,就暂时把这台服务器标记为不可用,过了 fail_timeout 再尝试重新接入。

六、静态资源优化:缓存与 Gzip 压缩

Nginx 不仅能做反向代理,处理静态资源也是它的拿手好戏。配合缓存和压缩,可以大幅减少带宽消耗、提升页面加载速度。

Gzip 压缩配置

启用 Gzip 后,文本类资源(HTML/CSS/JS/JSON)的体积通常能减少 60%-70%,效果非常显著:

Nginx - Gzip 压缩配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
http {
    gzip on; # 开启 gzip
    gzip_vary on; # 在响应头添加 Vary: Accept-Encoding
    gzip_comp_level 6; # 压缩级别 1-9,6 是性价比最高的选择
    gzip_min_length 1024; # 小于 1KB 的文件不压缩(压了反而更大)
    gzip_proxied any; # 对代理的响应也压缩
    gzip_disable "msie6"; # IE6 不支持 gzip,禁用
    gzip_types
        text/plain
        text/css
        text/xml
        application/json
        application/javascript
        application/xml+rss
        image/svg+xml;
}

浏览器缓存配置

对于不经常变化的静态资源(图片、CSS、JS),设置合适的缓存头可以让浏览器直接使用本地缓存,完全不请求服务器:

Nginx - 静态资源缓存配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
server {
    listen 80;
    server_name www.example.com;
    root /var/www/html;
    # HTML 文件:不缓存(每次都检查更新)
    location ~* \.html$ {
        expires -1; # 不缓存
        add_header Cache-Control "no-cache, no-store, must-revalidate";
    }
    # CSS/JS:缓存 7 天(配合文件名 hash 版本号更新)
    location ~* \.(css|js)$ {
        expires 7d;
        add_header Cache-Control "public, immutable";
    }
    # 图片/字体:缓存 30 天
    location ~* \.(jpg|jpeg|png|gif|ico|svg|woff2?|ttf|eot)$ {

Nginx 层缓存后端响应

除了让浏览器缓存,Nginx 自己也可以缓存后端的响应结果。对于不经常变化的接口数据,缓存后下一次相同请求直接从 Nginx 返回,完全不需要打到后端:

Nginx - proxy_cache 缓存后端响应
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 在 http 块中定义缓存区域
proxy_cache_path /var/cache/nginx/api_cache
    levels=1:2
    keys_zone=api_cache:10m # 内存中缓存 key 的区域,10m 约存 8 万个 key
    max_size=1g # 磁盘上最大缓存空间
    inactive=60m; # 60 分钟未被访问就清除
# 在 location 中使用缓存
location /api/public/ {
    proxy_cache api_cache;
    proxy_cache_valid 200 5m; # 200 响应缓存 5 分钟
    proxy_cache_valid 404 1m; # 404 缓存 1 分钟
    proxy_cache_key $scheme$request_method$host$request_uri;
    add_header X-Cache-Status $upstream_cache_status; # 显示命中状态
    proxy_pass http://backend_servers;
}

七、HTTPS 配置与安全加固

现在的网站几乎都要求 HTTPS。Nginx 配置 SSL 并不复杂,但要配得安全、配得高效,有不少细节。

基础 HTTPS 配置

Nginx - HTTPS 基础配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# HTTP 自动跳转 HTTPS
server {
    listen 80;
    server_name www.example.com example.com;
    return 301 https://$host$request_uri; # 301 永久重定向
}
# HTTPS 服务
server {
    listen 443 ssl;
    server_name www.example.com;
    # 证书文件路径
    ssl_certificate /etc/nginx/ssl/fullchain.pem; # 证书链
    ssl_certificate_key /etc/nginx/ssl/privkey.pem; # 私钥
    # SSL 协议与加密套件
    ssl_protocols TLSv1.2 TLSv1.3; # 禁用不安全的 SSLv3/TLS1.0/1.1
    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 on;

SSL 性能优化

HTTPS 握手比 HTTP 多几次往返,如果不优化会明显拖慢首次访问。以下是几个关键优化手段:

Nginx - SSL 性能与安全加固
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 在 http 块中配置 session 缓存
ssl_session_cache shared:SSL:10m; # 10MB 约存 4 万个会话
ssl_session_timeout 1d; # 会话有效期 1 天
ssl_session_tickets off; # 禁用 session ticket(用 cache 替代)
# 在 server 块中配置
listen 443 ssl http2; # 启用 HTTP/2
ssl_stapling on; # 启用 OCSP Stapling
ssl_stapling_verify on;
resolver 8.8.8.8 1.1.1.1 valid=300s;
# HSTS:强制 HTTPS,15768000 秒 = 6 个月
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains" always;
add_header X-Frame-Options "SAMEORIGIN" always; # 防点击劫持
add_header X-Content-Type-Options "nosniff" always; # 防 MIME 嗅探
💡 免费获取 SSL 证书
Let's Encrypt 提供免费的 SSL 证书,通过 certbot 工具可以自动申请和续期。只需安装 certbot 后执行 certbot --nginx -d example.com,它会自动修改 Nginx 配置并配置自动续期。

八、常见错误与实战练习

常见踩坑记录

❌ 错误 1:403 Forbidden
症状:访问静态资源返回 403 Forbidden
常见原因:Nginx 运行用户(如 www-data)没有文件读取权限,或 SELinux 阻止了访问
排查步骤:
  1. 检查文件权限:ls -l /var/www/html/index.html
  2. 检查 Nginx 运行用户:ps aux | grep nginx
  3. 修改权限:chmod -R 755 /var/www/html 或 chown -R www-data:www-data /var/www/html
  4. CentOS 下检查 SELinux:setenforce 0 临时关闭测试
❌ 错误 2:502 Bad Gateway
症状:反向代理返回 502 Bad Gateway
常见原因:后端服务没启动、端口不对、防火墙拦截
排查步骤:
  1. 确认后端服务在运行:curl http://127.0.0.1:3000
  2. 检查 error.log 看具体错误:tail -f /var/log/nginx/error.log
  3. 确认 proxy_pass 地址正确,没有多写或少写斜杠
  4. 检查防火墙是否放行:ufw status 或 firewall-cmd --list-ports
❌ 错误 3:配置文件语法错误
症状:nginx -t 报错 "directive is not allowed here" 或 "unexpected end of file"
常见原因:花括号不配对、指令放错层级、缺少分号
排查技巧:
  1. 每次改完配置先执行 nginx -t,确认没问题再 reload
  2. 报错会提示行号,直接定位到那一行检查
  3. 注意 Nginx 每条指令必须以分号 ; 结尾
  4. 花括号要成对,用编辑器的括号匹配功能检查

动手练习

🏋️ 练习:搭建一个完整的 Nginx 反向代理
目标:用 Docker 快速搭建 Nginx + 两个后端服务,验证负载均衡效果

步骤:
1. 启动两个简单的 HTTP 服务(可以用 nginx 镜像分别返回不同内容模拟后端)
2. 配置 Nginx 反向代理,使用 upstream 轮询分配到两个后端
3. 多次访问验证轮询效果
4. 停掉一个后端,验证自动故障转移
5. 配置 Gzip 压缩,用 curl -I -H "Accept-Encoding: gzip" 地址 验证
6. (选做)配置 HTTPS(可以用自签名证书测试)

验证命令:
for i in {1..10}; do curl -s http://localhost | grep "server"; done
📝 知识回顾
核心概念
反向代理、正向代理、Master-Worker 模型、事件驱动
配置层级
全局块 → events → http → server → location,逐层缩小作用域
location 匹配
精确(=) > 前缀优先(^~) > 正则(~) > 普通前缀,前缀取最长
负载均衡
轮询/权重/ip_hash/least_conn,max_fails + fail_timeout 被动健康检查
性能优化
Gzip 压缩、浏览器缓存、proxy_cache、HTTP/2、SSL Session 复用
安全加固
HTTPS + TLS1.2/1.3、HSTS、X-Frame-Options、X-Content-Type-Options
📅 下一篇预告
下一篇是第 34 篇:CI/CD 自动化部署。我们将从手动部署的痛点出发,带你了解持续集成与持续部署的完整流程,用 GitHub Actions 实战一条从代码提交到自动上线的流水线。
觉得有帮助?点个赞 + 在看,分享给更多朋友 🎉
全栈开发学习系列 · 每周更新