反向代理(Reverse Proxy)是自托管最核心的概念之一。理解了它,你就能用一台服务器、一个公网 IP 跑几十个网站/服务。

先理解”代理”

代理(Proxy)就是”中间人”。根据中间人站在哪一边,分为正向代理和反向代理。

正向代理(Forward Proxy)

代理的是客户端,帮客户端去访问外部资源。

你(客户端) → 正向代理 → 互联网 → 目标服务器
                │
                └─ 目标服务器只知道代理的 IP,不知道你的真实 IP

典型例子:

  • VPN:你通过 VPN 服务器访问外网,网站看到的是 VPN 服务器的 IP
  • 公司上网代理:公司内网通过统一出口访问互联网
  • 科学上网工具:本质就是正向代理

关键:正向代理是客户端主动配置的,服务器不知道客户端是谁。

反向代理(Reverse Proxy)

代理的是服务器,帮服务器接收请求、再转发给真正处理请求的服务。

用户 → 互联网 → 反向代理(Nginx/Caddy/Cloudflare)→ 后端服务1(Memos,端口 5230)
                                          → 后端服务2(博客,端口 4000)
                                          → 后端服务3(网盘,端口 8080)
                │
                └─ 用户只知道反向代理的 IP/域名,不知道后端有几个服务、跑在哪个端口

典型例子:

  • Nginx:最经典的反向代理软件
  • Caddy:自动配 HTTPS 的新一代反代
  • Cloudflare:你访问 Cloudflare 保护的网站时,Cloudflare 就是反向代理
  • Traefik:Docker 部署时自动发现服务的反代

关键:反向代理对客户端是透明的,用户不知道自己访问的是代理。

一张图看懂区别

正向代理:代理客户端,隐藏"我是谁"
  [客户端] → [代理] → [服务器]
     你      VPN      网站

反向代理:代理服务器,隐藏"服务在哪"
  [客户端] → [代理] → [服务器]
    用户     Nginx    你家的各种服务

为什么需要反向代理

1. 一台服务器跑多个服务(虚拟主机)

你的服务器只有一个公网 IP 1.2.3.4,但你想跑博客、Memos、网盘、数字花园四个服务。

没有反向代理的话,你只能用不同端口区分:

  • http://1.2.3.4:4000 → 博客
  • http://1.2.3.4:5230 → Memos
  • http://1.2.3.4:8080 → 网盘
  • http://1.2.3.4:80 → 数字花园

问题:端口号难记、不美观,而且 80/443 端口只能给一个服务用。

有了反向代理,用域名区分:

反向代理监听 80/443 端口,根据请求里的域名(Host 头)转发到不同的后端服务:

  • blog.linqin.xyz → 转发到 127.0.0.1:4000(博客)
  • memos.linqin.xyz → 转发到 127.0.0.1:5230(Memos)
  • pan.linqin.xyz → 转发到 127.0.0.1:8080(网盘)
  • garden.linqin.xyz → 转发到 Cloudflare Pages(或者本地服务)

用户访问的都是标准的 80/443 端口,不需要带端口号,干净漂亮。

这也解释了为什么 01-域名与DNS 里说”同一个 IP 可以挂无限多个子域名”——区分工作是反向代理做的,不是 DNS 做的。DNS 只是把这些子域名都指向同一个 IP。

2. 统一处理 HTTPS

SSL 证书的申请、续期、加密解密都可以在反向代理层统一处理,后端服务只管跑 HTTP 就行。这叫 SSL 终止(SSL Termination)。

用户 --HTTPS(加密)--> Nginx(解密)--HTTP(明文)--> 后端服务
                         │
                         └─ 证书只需要在 Nginx 上配一次

3. 其他好处

  • 负载均衡:把请求分发到多台后端服务器
  • 缓存静态资源:图片、CSS、JS 直接由 Nginx 返回,不用打到后端
  • 压缩:gzip/brotli 压缩响应,加快传输
  • 安全防护:限流、屏蔽恶意请求、隐藏后端真实端口
  • WebSocket 支持:Nginx 也能代理 WebSocket 连接

Nginx 反向代理配置示例

一个典型的 Nginx 配置,用域名区分不同服务:

# /etc/nginx/conf.d/memos.conf
server {
    listen 80;
    server_name memos.linqin.xyz;  # 这个域名的请求

    location / {
        proxy_pass http://127.0.0.1:5230;  # 转发到本机 5230 端口
        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;
    }
}

# /etc/nginx/conf.d/blog.conf
server {
    listen 80;
    server_name blog.linqin.xyz;

    location / {
        proxy_pass http://127.0.0.1:4000;
    }
}

proxy_set_header 几行的作用是把用户的真实信息传给后端,否则后端服务看到的请求全是来自 127.0.0.1(Nginx 自己):

  • Host:原始域名
  • X-Real-IP:用户真实 IP
  • X-Forwarded-For:经过的代理链
  • X-Forwarded-Proto:用户是用 HTTP 还是 HTTPS 访问的

路径反代 vs 子域名反代

除了用子域名区分,也可以用路径区分:

方式URLNginx 配置
子域名反代memos.linqin.xyzserver_name memos.linqin.xyz; proxy_pass http://127.0.0.1:5230;
路径反代linqin.xyz/memos/location /memos/ { proxy_pass http://127.0.0.1:5230/; }

子域名反代(推荐):

  • ✅ 配置简单,每个服务独立
  • ✅ 不会和后端的路径冲突
  • ✅ Cookie 隔离,不会串号
  • ❌ 需要加 DNS 记录(不过子域名本来就免费)

路径反代:

  • ✅ 不需要额外 DNS 记录
  • ❌ 很多前端应用不支持部署在子路径下(资源路径写死了 /),会出问题
  • ❌ 配置容易踩坑(末尾斜杠问题)

建议

优先用子域名反代。路径反代只有在子域名不方便的时候(比如域名数量受限、某些特殊场景)才用。

Nginx 末尾斜杠的坑

proxy_pass 后面带不带斜杠,行为完全不同,这是最容易踩的坑:

# 情况1:proxy_pass 后面有 URI(哪怕只是 /)
location /memos/ {
    proxy_pass http://127.0.0.1:5230/;  # 注意末尾的 /
}
# 请求 /memos/api/xxx → 转发为 /api/xxx (把 /memos/ 替换成 /)

# 情况2:proxy_pass 后面只有 IP:端口,没有路径
location /memos/ {
    proxy_pass http://127.0.0.1:5230;   # 注意:没有 /
}
# 请求 /memos/api/xxx → 转发为 /memos/api/xxx (完整路径原样传过去)

记忆方法:有斜杠就”替换前缀”,没斜杠就”原样透传”。

Caddy:更简单的选择

Caddy 自动申请和续期 HTTPS 证书,配置比 Nginx 简洁很多:

# Caddyfile
memos.linqin.xyz {
    reverse_proxy 127.0.0.1:5230
}

blog.linqin.xyz {
    reverse_proxy 127.0.0.1:4000
}

pan.linqin.xyz {
    reverse_proxy 127.0.0.1:8080
}

写完 caddy reload 就生效,HTTPS 证书自动搞定。对新手更友好。

Cloudflare 也是反向代理

当你在 Cloudflare 开了橙色云朵,Cloudflare 就充当了一个”全球级反向代理”:

用户 → Cloudflare 边缘节点(全球几百个)→ 你的服务器(Nginx)→ 后端服务

Cloudflare 做的事情包括:

  • 缓存静态资源(CDN 功能)
  • 提供 HTTPS 证书(你甚至可以不用在自己服务器上配证书,用 Cloudflare 的 Flexible 模式,但推荐 Full 模式)
  • 隐藏你的真实服务器 IP
  • DDoS 防护、WAF(Web 应用防火墙)

反向代理与端口的关系

典型的自托管架构:

                        互联网
                           │
                    ┌──────▼──────┐
                    │   域名解析   │  *.linqin.xyz → 1.2.3.4 (Cloudflare 或你的服务器IP)
                    └──────┬──────┘
                           │
                    ┌──────▼──────┐
                    │   防火墙    │  只开放 80/443 端口
                    └──────┬──────┘
                           │
              ┌────────────▼────────────┐
              │  Nginx/Caddy (反代)      │  监听 80/443,根据域名分发
              │  统一处理 HTTPS、证书    │
              └──┬──────┬──────┬──────┬─┘
                 │      │      │      │
            ┌────▼─┐ ┌──▼───┐ ┌▼────┐ ┌▼────┐
            │Memos │ │博客  │ │网盘 │ │花园 │  这些服务只监听 127.0.0.1
            │:5230 │ │:4000 │ │:8080│ │:3000│  不对外暴露端口!
            └──────┘ └──────┘ └─────┘ └─────┘

安全建议

后端服务只监听 127.0.0.1(本机回环地址),不要监听 0.0.0.0。这样外部只能通过 Nginx 反代访问,不能直接用 IP:端口 绕过反代访问你的服务,安全性高很多。

常见问题

Q: 反向代理会不会很慢? 不会。Nginx 转发本身的延迟在微秒级,你感知不到。真正的网络延迟来自用户到服务器的物理距离。

Q: 我用 Docker 部署服务,反代怎么配? Docker 容器之间可以用容器名通信。如果用 Docker Compose,把 Nginx 和服务放在同一个 network 里,proxy_pass 直接写服务名即可:proxy_pass http://memos:5230。Traefik 和 Nginx Proxy Manager 还能自动发现容器,不用手动写配置。

Q: Cloudflare 和我自己的 Nginx 是什么关系? 可以同时用。Cloudflare 在最前面(CDN+防护),请求到了你服务器后再由 Nginx 分发给后端服务。这就是”CDN → 反代 → 服务”的两层架构。

Q: 我需要反代非 HTTP 服务(SSH、游戏、数据库)怎么办? HTTP 反代基于域名(Host 头)工作,非 HTTP 协议没有域名概念。这些服务:

  • SSH:直接用 IP+端口(22),或者用 端口转发/frp 内网穿透
  • 也可以用 Cloudflare Spectrum(付费)或 TCP 层反向代理(如 HAProxy streams)
  • 或者走 VPN(WireGuard 等),更安全

下一步:03-端口与HTTPS

相关:01-域名与DNS返回目录