正解是选择一台入门级云服务器作为流量总入口,部署Nginx反向代理,用不同端口或子路径把请求转发给内网或本机的多个后端服务,这样前端只需暴露一个公网地址,后续加服务只需改一行配置,扩展和运维都更轻松。
这套方案是我近期帮朋友整理个人项目时反复验证过的,他手头有七八个自用服务,比如博客、API接口、文件同步工具,以前每个服务都各自开一个端口,域名解析换来换去,端口号自己都记不住,更别提有些服务没有用户认证,直接裸奔在公网上。
下面我把整套思路和配置过程拆开讲清楚,包括架构选择、Nginx安装、具体配置写法、常见坑,以及一台低配机器能承担多大流量,如果你也在为云服务器反向代理配置头疼,这篇文章应该能帮你省下半天查资料的功夫。
为什么要用反向代理统一收口
先明确一个概念:反向代理是站在服务器这边的,它接收外部请求,再根据规则转发给内部不同的服务,外部看不到后端真实结构。
传统直连方式有两个绕不开的痛点:
- 端口杂乱,每个服务占一个端口,HTTP用80,HTTPS用443,其他服务只能用8080、9000、3000这类高位端口,服务多了,端口号记不住,防火墙规则也越加越多。
- 安全边界模糊,后端服务直接暴露公网,遭遇恶意扫描和攻击的风险增加了,加上很多自用服务没有完善的身份验证机制,等于把内部工具直接亮在门口。
用了Nginx反向代理之后,效果是结构性的改变:
- 对外只保留一个入口(通常是80/443端口),所有服务都收敛在这一个入口之下。
- 后端服务可以全部绑定内网IP或仅监听127.0.0.1,公网直接访问不了,安全性提升一个层级。
- TLS证书统一管理,只需在Nginx层面配置一次,所有后端服务自动获得HTTPS加密能力。
- 新增服务时不用动防火墙规则,只需在Nginx配置里加一段转发规则,然后reload,秒级生效。
这就是多个后端服务统一入口的标准解法。
部署前需要想清楚的事
开始动手前,有几个选择会影响后面的工作量和踩坑概率。
选哪种反代方案:Nginx还是Caddy
目前主流的国产替代方案也不少,比如OpenResty、Apache APISIX,但在轻量级场景下,Nginx和Caddy是大多数人的首选,两者的取舍很清晰:
| 对比维度 | Nginx | Caddy |
|---|---|---|
| 上手难度 | 中等,配置文件结构清晰 | 较低,简单几行就能跑 |
| 配置语法 | 关键字段少,但逻辑要理解 | 语法简洁,能自动签发证书 |
| 插件生态 | 丰富,第三方模块多 | 相对少,但够用 |
| 性能表现 | 稳定,资源占用略高 | 更轻量,自带并发能力不错 |
| 适合场景 | 项目多、需要精细控制 | 个人博客、简单服务 |
我个人的使用习惯是:自用项目推荐Nginx,因为社区资料最全,遇到问题搜得到答案;如果是纯个人博客且懒得折腾证书,Caddy能少写不少配置。
一台低配服务器够用吗
业内专家指出,反向代理的性能瓶颈通常在连接数和管理规则上,而非计算量,只要不是高并发大流量场景,1核2G的入门级云服务器足够应对日常需求。
以我的经验来看,像宝塔这类面板自带的Nginx,十来个站点、日几千次请求,资源占用都不明显,选服务器时重点看网络带宽和流量包,而不是堆CPU和内存。
域名解析怎么规划
建议在域名服务商处建一个主域名,然后用子域名或路径区分服务:
blog.example.com
对应博客服务
api.example.com对应接口服务files.example.com对应文件服务
这种子域名方案的优点是运维时心里有数,尤其是TLS证书配置时,可以按子域名分别配置,互不干扰。
Nginx反向代理配置实操
以下操作以Ubuntu 22.04系统为例,其他Linux发行版大同小异。
第一步:安装Nginx
更新软件源并安装:
apt update apt install nginx -y
安装完成后,启动服务并设置开机自启:
systemctl start nginx systemctl enable nginx
检查是否正常运行:
nginx -v
看到版本号输出,说明安装成功。
第二步:认识核心配置文件
Nginx的配置主文件在/etc/nginx/nginx.conf,它负责加载/etc/nginx/sites-enabled/下的所有站点配置,建议不要直接改主文件,而是在/etc/nginx/sites-available/里新建配置文件,然后软链接到sites-enabled/。
创建配置文件:
touch /etc/nginx/sites-available/reverse-proxy ln -s /etc/nginx/sites-available/reverse-proxy /etc/nginx/sites-enabled/
这样做的好处是:禁用某个站点时只需删掉软链接,不破坏原始文件,日后追溯也方便。
第三步:核心配置写法
这里以一个真实场景为例:本机8080端口跑着Java后端API,3000端口跑着Node.js博客应用,后台管理界面监听在9001端口,我想通过统一域名service.example.com的不同子路径来访问这些服务。
server {
listen 80;
server_name service.example.com;
# 后端 API 服务
location /api/ {
proxy_pass http://127.0.0.1:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# 博客应用
location /blog/ {
proxy_pass http://127.0.0.1:3000/;
proxy_set_header Host $host;
}
# 后台管理
location /admin/ {
proxy_pass http://127.0.0.1:9001/;
proxy_set_header Host $host;
# 额外加一层访问控制
allow 192.168.1.0/24;
deny all;
}
}
保存后检查配置并重载:
nginx -t nginx -s reload
注意proxy_pass末尾的很关键,带斜杠表示把/api/部分去掉后再转发,不带斜杠则会把完整路径传给后端。
/api/user经过上述配置后转发给后端的是/user- 如果
proxy_pass http://127.0.0.1:8080;(无斜杠),转发给后端的是/api/user
这个细节会导致接口404,排查的时候最容易忽略。
第四步:用stream模块转发TCP流量
除了HTTP,有些服务走的是TCP协议(比如MySQL、SSH、Redis),Nginx的stream模块可以处理这类流量。
在nginx.conf的http{}块外添加:
stream {
upstream mysql_server {
server 10.0.0.5:3306;
}
server {
listen 3306;
proxy_pass mysql_server;
proxy_timeout 30s;
proxy_buffer_size 16k;
}
}
这样外部客户端连接服务器的3306端口,就能直接映射到内网真实数据库的3306端口,需要注意stream模块在部分Nginx编译版本中默认不包含,需要安装nginx-extras包或自行编译。
第五步:完整配置HTTPS
现在免费证书申请很方便,用acme.sh或certbot都可以,以acme.sh为例:
curl https://get.acme.sh | sh acme.sh --issue -d service.example.com --webroot /var/www/html
证书生成后,在Nginx配置中启用SSL:
server {
listen 443 ssl ht
tp2;
server_name service.example.com;
ssl_certificate /etc/nginx/ssl/service.example.com/fullchain.cer;
ssl_certificate_key /etc/nginx/ssl/service.example.com/service.example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# 性能和容量优化
gzip on;
gzip_types text/plain text/css application/json application/javascript;
client_max_body_size 100m;
proxy_connect_timeout 30s;
proxy_read_timeout 60s;
# 反向代理配置...
}
这里client_max_body_size特别提一下,如果你是做文件服务器反向代理,很多人上传大文件时会遇到413 Request Entity Too Large错误,就是由于这个参数默认值只有1m导致的,把它调到100m甚至更高能一并解决这类问题。
第六步:动态添加新服务
过段时间又加了一个服务,怎么收口?不需要动旧配置,只需在原有server块里加一段新location:
location /notion/ {
proxy_pass http://127.0.0.1:8000/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
然后重新加载:
nginx -s reload
整个操作过程不超过十秒钟,上线新服务时省去改域名解析和防火墙规则的环节,加上云服务器反向代理统一入口的设计本就支持平滑扩展,后续维护成本会保持得很低。
生产环境的关键优化
本地能跑通和线上稳定运行是两回事,以下几个环节在生产场景中几乎都会遇到,属于必须调好的范围。
处理WebSocket长连接
如果你的后端服务里有在线聊天、实时推送这类功能,WebSocket代理的配置里需要提升长连接支持:
location /ws/ {
proxy_pass http://127.0.0.1:8000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
WebSocket本质是TCP长连接,如果不加Upgrade头,客户端握手阶段就会失败,表现为连接一直pending然后断开。
后端服务故障转移
让Nginx在后端服务宕机时自动下线,是保证可用性的常见做法,适合多实例部署的情况:
upstream backend_servers {
server 127.0.0.1:8080 max_fails=3 fail_timeout=30s;
server 127.0.0.1:8081 max_fails=3 fail_timeout=30s;
server 127.0.0.1:8082 backup;
}
server {
listen 80;
server_name service.example.com;
location / {
proxy_pass http://backend_servers;
proxy_next_upstream error timeout http_502 http_503;
}
}
含义是:前两台机器在30秒内失败3次则标记为不可用,请求自动切换到备用服务器。proxy_next_upstream定义了触发切换的异常条件,这层配置对保证服务整体可用性极为关键,尤其是后端服务需要维护重启时,不用打断公网访问。
静态资源直出
如果Nginx代理的是前端项目,把静态资源直接交给Nginx处理,能显著降低后端压力:
location ~ .(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
root /var/www/frontend/dist;
expires 30d;
access_log off;
}
这样静态资源请求不会穿透到后端,图片、样式等完全由Nginx响应,并发承载能力提升一倍以上是比较常见的效果,搭配expires缓存头,浏览器端也能减少重复请求。
全局限流配置
自用服务最怕被别人拿来刷流量或爆破密码,用Nginx的limit_req模块可以做个基础防护:
http { limit_req_zone $binary_remote_addr zone=general_limit:10m rate=5r/s; limit_req_zone $binary_remote_addr zone=auth_limit:10m rate=1r/s; } server { location /api/ { limit_req zone=general_limit burst=10 nodelay; proxy_pass http://127.0.0.1:8080/; } location /admin/ { limit_req zone=auth_limit burst=3 nodelay; proxy_pass http://127.0.0.1:9001/; } }
对登录接口设置更低的速率限制,能有效减缓暴力破解的风险,register/login这类接口建议单独设置zone,不要和普通业务共用同一个限流配置,否则正常用户也可能被误伤。
常见排障方法
配置过程中总会遇到奇怪的问题,我习惯按这个顺序排查:
- 看日志,Nginx的错误日志是最直接的线索,查看方式:
tail -f /var/log/nginx/error.log
- 确认端口监听状态,排查后端服务是否真正在监听预期端口:
netstat -tlnp | grep LISTEN
- 现场验证转发结果,看Nginx实际转发给后端的路径和请求头:
curl -v http://127.0.0.1:8080/api/user
- 对比安全组和系统防火墙,云服务商控制台的安全组规则和服务器内部防火墙(ufw/firewalld)都必须放行相应入口端口。
不同云厂商的国产Linux镜像预装环境有差异,如果遇到类似端口不可达的报错,先检查这两层,再手动关闭SELinux这类附加配置很多镜像默认开启SELinux,会让Nginx的代理行为变得难以捉摸。
这样设计带来的实际收益
按这套方案把所有服务收口到一台低价云服务器上之后,实际变化很明显:
- 域名解析只需要建一条A记录指向服务器IP,其余所有子路径都在Nginx这一层分配。
- 每个后端服务可以只监听127.0.0.1,公网扫描器扫不到任何额外端口。
- 证书只需要在Nginx统一配置一次,且各子域名都能复用同一张通配证书。
- 服务升级时,重启后端进程不影响对外入口,请求重试几次就能自动恢复。
从资源消耗角度看,这类纯转发性质的代理进程负载极低,即便后端同时跑着数据库、缓存和应用进程,只要没有突发流量,1核2G的配置也普遍够用。
常见问题解答
问:云服务器反向代理和负载均衡是什么关系?
反向代理负责把外部请求按规则转发到不同的后端服务,它本身不关心后端有多少实例;负载均衡则是在同一个服务的多个后端实例之间分发流量,解决的是单点压力问题,Nginx既支持反向代理,也原生支持基于upstream的负载均衡组合,因此在同一套配置里可以同时实现路径转发和实例分发两层能力,很多线上方案就是用Nginx做入口,先反向代理到不同服务,再对关键服务做多实例轮询,一次配置两层收益。
问:Nginx反向代理和宝塔面板搭建的服务器环境冲突吗?
不会,宝塔面板安装的Nginx本质上就是同一个软件,区别只在于面板会接管配置文件的生成和维护,手动部署反代配置时,建议在宝塔的站点设置里新增配置段,避免直接覆盖面板生成的默认文件,需要特别留意的是,面板自身的端口(通常是8888)也是监听在公网上的,建议只把面板管理入口授权给内网IP访问,或至少开启面板的BasicAuth认证,以免给人留下后门。
问:反向代理服务器都要部署在公网吗?
不一定,如果多个后端服务都部署在同一台内网机器上,反向代理也可以直接部署在这台机器上,只监听本机回环地址,再统一暴露有限的对外端口,若有多台内网服务器需要统一入口,则需一台处于公网可达位置的服务器作为跳板机,同时配置好安全组规则,仅放行代理层需要用到的端口(通常80、443),后者就是常见的多机反向代理架构,国内云服务器不同地域间内网互联延迟较低,跨地域部署时优先选择同地域的机器作为代理层入口,可有效降低端到端转发延迟。
