手上有个 VPS,想跑多个网站和应用,但只有一台服务器、一个 80/443 端口,怎么办?答案就是 Nginx 反向代理。它可以把不同域名过来的请求,转发给本机不同端口上的各种服务(Node、Java、Golang、另一个 Nginx),统一对外暴露 80/443。这一篇把反向代理的原理、配置和实战讲清楚。
一、什么是反向代理
反向代理(Reverse Proxy)站在用户和真实服务之间:用户访问的是代理(Nginx),Nginx 再把请求转发给后端真实服务,并把它返回的内容转交回给用户。
典型用途:
- 一个服务器上跑多个站点:每个站点一个域名,按域名转发到不同端口
- 给纯端口应用加域名:比如 8080 跑的应用,配好 SSL 用域名安全访问
- 负载均衡:同一套后端多台机器,按策略分发请求
- 缓存与安全:前置一层缓存、限流、WAF
用户看到的始终是 Nginx 的 80/443,后端服务甚至可以只监听内网。
二、反向代理与正向代理的区别
记忆要点:
- 正向代理:站在客户端一侧,替客户端去访问目标(如 VPN、公司网代理),目标是服务器
- 反向代理:站在服务器一侧,替后端容器接客,访问人的是用户
用户访问反向代理时,以为是真实服务,其实后面还有一层。
三、最简单的反向代理配置
Nginx 站点配置一般放在 /etc/nginx/sites-available/需要打开的域名.conf 或 conf.d/博客名.conf,再软链到 sites-enabled。这里以反向代理到本机 127.0.0.1:3000 的 Node 应用为例:
server {
listen 80;
server_name api.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;
}
}
关键参数:
proxy_pass:把请求转发到哪里proxy_set_header Host $host:让后端看到用户真正访问的域名X-Real-IP/X-Forwarded-For:让后端记录用户真实 IP(否则全是 Nginx 的 IP)X-Forwarded-Proto:告诉后端用的是 http 还是 https
检查并重载生效:
nginx -t
nginx -s reload
访问 http://api.example.com 就能看到 3000 端口的应用了。
四、同一服务器搭多个网站(多域名)
一个 Nginx 配多个 server 块,每个一个域名,分别指向不同后端:
server {
listen 80;
server_name site1.com;
location / {
proxy_pass http://127.0.0.1:8081;
# headers 同上...
}
}
server {
listen 80;
server_name site2.com;
location / {
proxy_pass http://127.0.0.1:8082;
}
}
这样一台 VPS、一个端口,就能通过不同域名访问不同应用,互不干扰。
五、按路径转发(一个域名分给不同服务)
同一域名按路径分发到不同后端:
server {
listen 80;
server_name app.com;
location /api/ {
proxy_pass http://127.0.0.1:3000; # 后端接口
}
location / {
proxy_pass http://127.0.0.1:8080; # 前端/其他
}
}
注意:location /api/ 最后带不带 / 会影响转发路径拼接,容易踩坑(见常见问题)。
六、配合 HTTPS(SSL)使用
先给域名签发证书(可用免费的 Let's Encrypt / 本站 HTTPS 教程),再在反向代理上加上:
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
}
}
把全部 HTTP 请求跳转到 HTTPS:
server {
listen 80;
server_name api.example.com;
return 301 https://$host$request_uri;
}
七、负载均衡(多台后端)
后端有多台机器时,用 upstream 定义后端组:
upstream backend {
ip_hash; # 可选:同一用户走同一后端
server 10.0.0.2:8080;
server 10.0.0.3:8080;
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
}
}
Nginx 默认轮询分发,也可以配 weight(权重)、max_fails、fail_timeout 做故障转移。
八、WebSocket 反向代理
如果用到了实时推送(聊天、通知),要加 Upgrade 头:
location /ws/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 60s;
}
九、常见问题
Q1:proxy_pass 斜杠陷阱?
proxy_pass http://127.0.0.1:3000;(不带路径)时,location /api/ 会保留 /api/ 前缀传给后端;proxy_pass http://127.0.0.1:3000/;(带 /)会把 /api/ 去掉。根据后端期望决定带不带。
Q2:后端拿不到用户真实 IP?
必须设置 X-Real-IP 和 X-Forwarded-For,否则应用里拿到的是 127.0.0.1(Nginx 的地址)。
Q3:反向代理后静态资源/大文件上传失败?
调大相关参数:
client_max_body_size 50m;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
Q4:502 Bad Gateway?
一般是后端服务没启动或连不上。用 curl http://127.0.0.1:3000 直接测后端,确认端口、进程、防火墙是否正常。
十、和正向代理、负载均衡、缓存的关系
反向代理常和本站的 Nginx 缓存(proxy_cache)、限流(limit_req)配合:代理层既做转发,又能缓存静态内容和限流防刷。把这几篇串起来,Nginx 就从"转发器"升级成了完整的高可用接入层。
总结
反向代理让一台服务器能承载多个域名应用,还能统一做 HTTPS、负载均衡和缓存。核心就四个字:按域名或路径,把请求转发给后端,把 Headers 传对。配合 HTTPS、缓存、限流一起用,一台低配 VPS 也能优雅地跑起多个线上服务。
