反向代理(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→ Memoshttp://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:用户真实 IPX-Forwarded-For:经过的代理链X-Forwarded-Proto:用户是用 HTTP 还是 HTTPS 访问的
路径反代 vs 子域名反代
除了用子域名区分,也可以用路径区分:
| 方式 | URL | Nginx 配置 |
|---|---|---|
| 子域名反代 | memos.linqin.xyz | server_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