Nginx反向代理实战:一台VPS托管你的全部服务,端口不再满天飞


导读:本站之前讲过用Nginx虚拟主机在一台VPS上跑多个网站,那篇解决的是“多个域名指向不同目录”的问题。但玩法再进一层:你机器上跑的可能不只是静态网站——密码管理器、RSS阅读器、监控面板、下载工具,这些全是监听各自端口的独立进程。难道每个服务都占用一个端口、配一套证书、让用户记一串端口号?完全不必。这篇讲透反向代理:用Nginx把所有服务收拢到80/443端口后面,按域名分发,统一证书、统一日志、统一防护。配置思路、完整实操、WebSocket与大文件这些细节坑,一次讲完。


一、反向代理到底是什么:和虚拟主机是什么关系


先把概念捋顺。虚拟主机解决的是“同一台机器、同一个80端口,靠域名区分不同网站目录”;反向代理(reverse proxy)解决的是“域名进来之后,把请求转交给机器内部或外部的另一个服务端口”。


举个例子:你在VPS上装了一个Vaultwarden密码管理器,它监听8222端口。没做反代之前,访问方式是 http://你的IP:8222 ——裸HTTP、带端口、没法挂证书。做了反代之后,访问方式变成 https://pw.example.com ——域名、HTTPS、干净利落。


中间发生了什么?用户请求打到Nginx的443端口,Nginx看Host头是 pw.example.com,命中对应的server块,把这个请求原样转发给本机127.0.0.1:8222,再把Vaultwarden的响应原样递回给用户。对用户来说,仿佛Nginx本身就是那个服务。


这就是“反向”二字的含义:普通代理替用户去访问别人,反向代理替服务接待用户。用户全程只跟Nginx打交道,后面藏了什么服务、跑在哪个端口、部署在哪台机器,一概不知。


它带来的好处远不止“去掉端口号”这一条:


统一证书管理:所有服务的HTTPS都在Nginx一层配置,后端服务完全不用管证书。

隐藏真实端口:后端服务只监听本机回环地址,外网根本扫不到。

统一访问日志:谁访问了什么服务、什么时候、什么状态码,全在一份日志里。

灵活调度:后端服务重启、迁移、换端口,只改Nginx一行配置,域名不变。

额外防护:限速、屏蔽恶意IP、过滤异常请求,都在入口统一做。


二、最小可用的反代配置:五分钟把8000端口挂上域名


不绕弯子,直接上手。假设你有个服务跑在本机8000端口,想通过 app.example.com 访问。


在 /etc/nginx/conf.d/ 目录下新建一个 app.conf(如果是宝塔或1Panel用户,在面板里新建反向代理效果等同):


server {

listen 80;

server_name app.example.com;


location / {

proxy_pass http://127.0.0.1:8000;

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;

}

}


保存后先测语法再重载:


nginx -t && nginx -s reload


把DNS的A记录指到VPS的IP,浏览器访问 http://app.example.com ,能看到8000端口的服务,最小配置就通了。


四个proxy_set_header是这段配置的灵魂,逐个解释:


Host $host:把用户访问的域名传给后端。很多应用靠这个值生成链接、做域名绑定校验,丢了它页面里的资源链接会变成IP加端口,样式全崩。


X-Real-IP:把用户的真实IP传给后端。不传的话,后端日志里记录的来访者全是127.0.0.1,等于失明。


X-Forwarded-For:传递完整的代理链路IP。有些应用只认这个头。


X-Forwarded-Proto:告诉后端用户用的是HTTP还是HTTPS。不少框架靠它判断“当前是安全连接”,进而影响Cookie的secure标记和跳转行为。


经验之谈:这四行是标准起手式,写反代配置时先无脑带上,能避开八成的“页面能开但奇奇怪怪”的问题。


三、补上HTTPS:证书配在Nginx层,后端不用动


裸HTTP的反代只能算半成品,下一步上证书。用certbot一行命令搞定(以Let's Encrypt为例):


apt install certbot python3-certbot-nginx -y

certbot --nginx -d app.example.com


certbot会自动改写你的server块:加443监听、配证书路径、把80的流量301跳转到https,全自动。之后它自带的systemd定时任务会处理续期,不用管。


要点在于:证书只存在于Nginx这一层,后端服务继续裸跑HTTP。加密由 Nginx到用户 这一段负责,Nginx到后端 这一截走本机回环,不出机器,明文也无所谓。


如果你有多个服务,每个域名各跑一遍 certbot --nginx -d 对应域名 即可。证书互相独立,一个域名到期不影响别的。


四、细节坑:WebSocket、上传大小、超时


最小配置能跑通大部分页面型应用,但有三类场景会翻车,提前打补丁。


场景一:WebSocket连不上。监控面板、在线终端、实时日志这类应用靠WebSocket维持长连接,默认配置下握手直接失败,表现为页面能开但实时数据不刷新。补几行:


location / {

proxy_pass http://127.0.0.1:8000;

proxy_http_version 1.1;

proxy_set_header Upgrade $http_upgrade;

proxy_set_header Connection 'upgrade';

}


WebSocket的建立依赖HTTP/1.1的Upgrade机制,这几行就是把升级请求原样透传给后端。


场景二:上传大文件报413。Nginx默认限制请求体1M,往网盘、图床传文件超过这个数就吃413错误。在server块里放宽:


client_max_body_size 512m;


按你的实际业务设,下载站可以给到2g。


场景三:长任务504。有些操作(导入数据、打包下载)耗时超过默认60秒,Nginx等不及就把连接掐了,用户看到504 Gateway Timeout。放宽超时:


proxy_connect_timeout 60s;

proxy_read_timeout 300s;

proxy_send_timeout 300s;


read_timeout是“后端多久没回话就掐线”,按最长任务耗时再加一倍余量。


另外一个高频坑:服务用的是HTTPS重定向。不少应用检测到X-Forwarded-Proto是http就疯狂重定向到自己,形成死循环,浏览器报“重定向次数过多”。确认配置里X-Forwarded-Proto有传,且后端应用开启了“信任反向代理头”的选项(Django的SECURE_PROXY_SSL_HEADER、Flask的ProxyFix中间件都是干这个的)。


五、完整示例:一台机器收拢四个服务


看一个真实一点的编排。一台2G内存的VPS上跑着:密码管理器(8222)、RSS阅读器(8080)、书签站(9090)、监控面板(3001)。Nginx配置分四个文件,每个域名一份,结构完全一样:


server {

listen 443 ssl http2;

server_name pw.example.com;

ssl_certificate /etc/letsencrypt/live/pw.example.com/fullchain.pem;

ssl_certificate_key /etc/letsencrypt/live/pw.example.com/privkey.pem;

client_max_body_size 64m;


location / {

proxy_pass http://127.0.0.1:8222;

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;

}

}


其余三个域名照抄,只改server_name、证书路径和proxy_pass的端口。80端口的HTTP统一跳转HTTPS,certbot会帮你生成对应的跳转块。


这套结构的美妙之处在于扩展性:明天想加第五个服务,复制一份conf改三个地方,reload一下完事;某个服务要从本机迁到另一台机器,把proxy_pass里的127.0.0.1换成那台机器的内网IP,域名无感切换。


六、安全收尾:只留80/443,其余端口全关


反代建好之后,最重要的一步安全动作:把后端服务的监听地址从0.0.0.0改成127.0.0.1,让它们只接受来自本机Nginx的连接。


以Docker为例,端口映射不要写 -p 8222:8222(这会监听所有网卡),改写 -p 127.0.0.1:8222:8222。普通进程则在其配置文件里找bind或listen相关设置,改成127.0.0.1。


然后防火墙只放行22、80、443:


ufw allow 22/tcp

ufw allow 80/tcp

ufw allow 443/tcp

ufw enable


用nmap或在线端口扫描验证一下,除了这三个端口,其余全部不通。此时就算某个服务本身有漏洞,攻击者也摸不到它——唯一入口是被你严格控制的Nginx。


七、排查思路:502和504到底是谁的锅


反代架起来后,出问题先看错误码,定位效率翻倍。


502 Bad Gateway:Nginx活着,但后端没应答。九成是后端服务挂了或端口写错。先用 curl http://127.0.0.1:8000 在机器上直接戳后端:戳得通,检查Nginx配置里的端口和协议(http还是https、要不要加路径前缀);戳不通,去看后端服务日志,十有八九是崩了或者没起来。


504 Gateway Timeout:后端活着但太慢。按第四节的超时参数排查,同时看看机器负载——内存耗尽触发OOM杀进程、CPU被邻居超售抢爆,都会表现为504。


页面开得了但样式全乱、跳转到IP端口:Host头没传对,回去检查proxy_set_header。


循环重定向:X-Forwarded-Proto没传或后端不信任代理头,按第四节的方案处理。


最后一条心得:Nginx的日志是排查总开关。出问题先 tail -f /var/log/nginx/error.log ,九成疑问这一条命令就能给出答案。


结语


反向代理是VPS玩法从“能跑”到“专业”的分水岭:一台机器、一套证书、一个入口,收拢所有服务。配合本站之前讲的虚拟主机和SSH管理技巧,一台廉价小鸡完全能撑起你个人的整个线上工具箱。下一篇我们继续往下挖——用Docker Compose把这些自托管服务标准化管理起来,起停、更新、备份一条命令搞定。


手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

Docker Compose自托管实战:一台小鸡跑起密码管理器、RSS阅读器与书签站

流量计费、带宽计费、按时计费:看懂VPS套餐页的门道再下单

评 论
更换验证码