POST

反向代理到底是什么?一篇讲清楚它为什么几乎无处不在

从概念、原理到 Nginx/Caddy 配置和常见坑,把反向代理一次说透。

如果你在服务器或 NAS 上跑过几个服务,大概率碰到过两个问题:每个服务一个端口,记不住;想给它们都上 HTTPS,一个个配证书太麻烦。反向代理基本就是为这类问题生的。

先分清正反向代理

代理这东西分两种,方向不同。

正向代理站在客户端这边,替客户端去访问外网。你翻墙用的工具、公司内网的上网代理,都是正向代理——服务器不知道真正的请求是谁发的。

反向代理反过来,站在服务器这边,替后端服务接收请求。客户端以为自己在跟一台服务器打交道,其实背后可能是一堆服务。对用户来说,它是透明的。

一句话概括:正向代理隐藏客户端,反向代理隐藏服务器。

一次请求的旅程

假设你用浏览器访问 https://example.com,背后是一台反向代理:

  1. 浏览器和反向代理建立 TLS 连接;
  2. 反向代理根据域名、路径等规则,决定把请求转给哪个后端;
  3. 它把请求转发给内网服务,比如 127.0.0.1:3000;
  4. 后端处理完,把响应交回给反向代理;
  5. 反向代理再把响应返回给浏览器。

整个过程中,后端服务不需要有公网 IP,也不需要自己处理 HTTPS 证书,这些活都被前置的代理接走了。

它到底解决了哪些问题

很多人以为反向代理就是「端口转发」,其实它能做的事多得多。

统一入口。 一台机器上跑着博客、网盘、监控、API,全都能挂在同一个域名下,用路径或子域名区分。用户只记一个地址,不用记端口。

TLS 终止。 证书只在反向代理这一层配一次,后端用明文 HTTP 就行。Caddy 这种工具还能自动申请和续期证书,省掉一大半运维工作。

负载均衡。 同一个服务起多个实例,反向代理按轮询、最少连接等策略分流量,某个实例挂了还能自动摘掉。

缓存与压缩。 静态资源、图片可以在代理层缓存,减少后端压力;gzip、brotli 压缩也可以在这一层统一做。

路由与灰度。 /api 转给后端,/ 交给静态文件;按请求头把 1% 的流量送到新版本,做灰度发布。

安全与限流。 隐藏后端真实地址、统一做 IP 白名单、基础认证、请求限速、拦截明显异常的请求。

协议适配。 对外 HTTP/2、HTTP/3,对内还是老式 HTTP/1.1,这些差异由代理层抹平。

常用工具,各自适合什么

  • Nginx:最经典,功能全、性能好、资料多。配置稍显啰嗦,但生态最成熟。
  • Caddy:配置极简,默认自动 HTTPS,适合个人站和小团队。V2 之后能力已经够用。
  • Traefik:为容器和微服务设计,能自动发现 Docker/K8s 里的服务,配置跟标签走。
  • HAProxy:四层/七层负载均衡的老牌选手,高并发场景口碑很好。
  • Envoy:云原生时代的主力,常和 Istio 这类服务网格一起出现,能力很强但学习曲线陡。
  • Cloudflare / 各家 CDN:本质也是反向代理,只是把入口放在了全球边缘节点。

个人或小团队,我一般推荐 Caddy 或 Nginx,够用且不容易踩坑。

最小可用配置

Nginx 的经典写法:

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;

        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;
    }
}

同样的需求,Caddy 只要两行:

example.com {
    reverse_proxy 127.0.0.1:3000
}

Caddy 会自动申请证书、自动把 HTTP 跳到 HTTPS,Host、X-Forwarded-* 这些头也默认帮你处理好,这也是它上手快的原因。

如果要做路径分流,Caddy 里大概是这样:

example.com {
    handle /api/* {
        reverse_proxy 127.0.0.1:8080
    }
    handle {
        root * /var/www/site
        file_server
    }
}

Nginx 做负载均衡,则要一个 upstream 块:

upstream backend {
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;
}

server {
    location / {
        proxy_pass http://backend;
    }
}

几个必须知道的坑

Host 头。 转发时如果不带原始 Host,后端可能生成错误的跳转地址、或者识别不到是哪个站点。上面例子里的 proxy_set_header Host $host 就是干这个的。

真实 IP。 后端看到的来源 IP 永远是代理的地址(常见是 127.0.0.1 或内网 IP)。想拿到真实 IP,要靠 X-Forwarded-For / X-Real-IP,而且应用本身得信任这些头。不做这一步,日志里的 IP、限流、封禁全都会失效。

WebSocket。 普通 HTTP 反代配置跑 WebSocket 经常会 400 或直接断。Nginx 需要显式升级:

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

Caddy 默认就支持,不用额外配。

超时。 默认的 60 秒对上传大文件、导出报表、AI 流式输出都不够。该调 proxy_read_timeout / proxy_send_timeout 就得调。

缓冲。 流式接口(SSE)、大文件下载如果被代理缓冲,会表现为「卡住不动」。这类场景通常要关掉 proxy_buffering,或者调大缓冲区。

上传大小。 Nginx 默认只允许 1MB 的请求体,传文件会直接 413,需要改 client_max_body_size。

gzip 重复压缩。 如果后端已经压过,代理再压一遍,既浪费 CPU 又可能出问题,最好只在一层做。

HTTPS 的两种模式。 一种是 TLS 终止,代理解密后明文转给后端,简单但内网流量不加密;另一种是透传(SNI 转发),后端自己持证书,适合有合规要求的场景,但代理就看不到内容、也没法做缓存和改写。

反向代理、负载均衡、API 网关

这三个经常被混着叫,其实侧重点不同:

  • 反向代理:核心是「转发」和「统一入口」;
  • 负载均衡:核心是「把流量分给多个后端」,通常建立在反向代理之上;
  • API 网关:核心是「管理 API」,在转发之外还管鉴权、限流、计费、日志、协议转换。

实际产品里它们经常长在一起,不用太纠结名字,看你要解决什么问题就行。

什么时候需要,什么时候不需要

需要的情况很明确:多个服务要共用域名和证书、要做负载均衡、要隐藏后端、要做统一的安全策略——这些基本都绕不开反向代理。

如果只是单台机器跑一个静态站,直接把文件扔给 Caddy 或者干脆用对象存储 + CDN,反而更简单,没必要为了「架构完整」硬加一层。

小结

反向代理本质上是一个「站到后端前面的门卫」:它负责接收所有请求,再按规则分发给里面的服务。

它不神秘,也不高深,但确实是现代 Web 基础设施里最常被用到的一层。理解了它,再看「为什么后端拿不到真实 IP」「为什么 WebSocket 连不上」「为什么大文件传一半断了」这些问题,思路会清楚很多。

👁 - 次浏览

留言

← 返回首页