一台云服务器跑多个网站:Nginx 反向代理与端口转发实操
一台云服务器跑多个网站:Nginx 反向代理与端口转发实操
很多小项目上云之后都会遇到同一个问题:手里只有一台 1 核 2G 的小服务器,上面却要跑两三个东西——一个博客、一个小工具站、一个 API 服务。每个服务各占一个端口,访问时要记 http://IP:8000、http://IP:3000 这种带端口的地址,又难记又难看,还容易被安全组和浏览器拦截。正确的做法是让 Nginx 站在最前面做反向代理:80 端口只留给 Nginx,后面的服务都躲在本地端口上,对外只暴露干净的域名或路径。下面记录一套在普通云服务器上能直接照做的流程。
一、先想清楚要怎么分
反向代理之前,先定好分流规则,免得后面越配越乱。常见的分法有两种,按域名分和按路径分。
按域名分最干净:blog.example.com 走博客,tool.example.com 走工具站,api.example.com 走接口服务。每个域名一个 server 块,互不干扰,以后加新服务就加一个块。缺点是每个子域名都要做 DNS 解析,域名不够用时不太方便。
按路径分最省事:只有一个域名,example.com/blog/ 走博客,example.com/tool/ 走工具站,example.com/api/ 走接口。优点是只用一个域名、一个证书,缺点是有些程序对路径前缀很敏感,静态资源引用写死成绝对路径时容易 404,需要额外处理。
我的建议是:服务超过两个、或者以后还要加的,按域名分;只有一个域名、服务之间没什么牵扯的,按路径分也能跑。本文以按域名分为主,路径分法在后面顺带讲。
二、装 Nginx,确认 80 端口归它管
Debian/Ubuntu 上安装很简单:sudo apt update && sudo apt install -y nginx;sudo systemctl enable --now nginx。装完先跑 curl -I http://127.0.0.1,看到 200 OK 和 Nginx 的欢迎页,说明 Nginx 已经在 80 端口上工作了。再跑 ss -tlnp | grep :80,确认监听 80 的进程是 nginx,而不是之前某个服务直接占着 80。如果之前有服务占了 80,先把它改到别的端口(比如 8000),再启动 Nginx,两个服务抢一个端口是谁都起不来的。
安全组里只需要放行 80 和 443,服务自己的端口(8000、3000 这些)不用对外放行,只留本地访问。这样做还有一个好处:外面的人扫端口时只能看到 Nginx,真实服务的端口是扫不到的。
三、写第一个反向代理配置
假设博客跑在本地 8000 端口,工具站跑在本地 3000 端口。新建两个配置文件:/etc/nginx/sites-available/blog 和 tool。博客的配置:server 块 listen 80,server_name blog.example.com,location / 里 proxy_pass http://127.0.0.1:8000,并带上四个请求头:proxy_set_header Host $host;X-Real-IP $remote_addr;X-Forwarded-For $proxy_add_x_forwarded_for;X-Forwarded-Proto $scheme。工具站同理,server_name 改成 tool.example.com,proxy_pass 改成 http://127.0.0.1:3000。写完做软链接启用到 sites-enabled,跑 sudo nginx -t && sudo systemctl reload nginx。
nginx -t 这一步不要省,它会在重载之前先校验语法,配置文件写错了会在这里报错,而不是把线上正在跑的 Nginx 一起拖垮。reload 是平滑重载,不会断开正在进行的连接,比 restart 安全得多。
这里有三个请求头必须带上,否则后端服务会拿到错误的信息:Host 让后端知道用户访问的是哪个域名;X-Real-IP 和 X-Forwarded-For 把真实访客 IP 传过去,否则后端日志里看到的全是 127.0.0.1,出了问题根本没法定位是谁在访问;X-Forwarded-Proto 告诉后端原始请求是 http 还是 https,做重定向时才不会出现 http/https 来回跳的死循环。
四、按路径分流时要注意的坑
如果只有一个域名,想用路径分流,配置大概长这样:一个 server 块 listen 80,server_name example.com,location /tool/ 里 proxy_pass http://127.0.0.1:3000/(带斜杠),location /api/ 里 proxy_pass http://127.0.0.1:8000/(带斜杠)。
注意 proxy_pass 后面那个斜杠,有它没它行为完全不同。带斜杠时,Nginx 会把匹配到的 /tool/ 前缀去掉再转发,后端收到的是 / 开头的路径;不带斜杠时,完整路径原样转发,后端收到的是 /tool/xxx。后端程序如果没有处理前缀,带斜杠的写法通常更不容易出错。
另一个常见坑是静态资源:页面 HTML 里引用的 /static/app.js 这种绝对路径,不会带上 /tool/ 前缀,浏览器会直接去根路径找,结果 404。解决办法有两个:要么给这个服务单独配一个域名,要么在程序里设置一个基础路径(比如前端打包时指定 base 为 /tool/),让它生成的所有资源地址都带上前缀。部署之前先在浏览器开发者工具里看一遍网络请求,确认没有 404,再算真正跑通。
五、HTTPS 一步到位,别留 http 裸奔
反向代理配通之后,马上把 HTTPS 接上。最省事的是用 acme.sh 或 certbot 申请 Let’s Encrypt 证书,证书申请下来之后,在每个 server 块里加三行:listen 443 ssl;ssl_certificate 证书 fullchain 路径;ssl_certificate_key 私钥路径。再加一个 80 端口的 server 块做强制跳转:return 301 https://$host$request_uri。这样不管用户输入 http 还是 https,最后都会落在加密连接上。后端服务本身不需要改任何 HTTPS 配置,它和 Nginx 之间走本地 http 就够了,加密只发生在用户到 Nginx 这一段,这也是反向代理最常见的部署形态:证书只在 Nginx 这一层管理,换证书、续期都只改一个地方。
六、出问题先看这三处
反向代理配完访问不通,先别急着改配置,按这个顺序排查,多数问题十分钟内能定位。
第一,看 Nginx 的错误日志:sudo tail -50 /var/log/nginx/error.log。最常见的报错是 connect() failed (111: Connection refused),意思是后端服务根本没在跑,或者端口写错了——先确认服务进程在不在、端口对不对。
第二,看是不是 502 网关错误。502 几乎一定是 Nginx 到后端这段出了问题:后端挂了、端口不对、或者后端只监听了 IPv6 而 Nginx 连的是 IPv4。跑 curl http://127.0.0.1:8000 直接测后端,通了就是 Nginx 配置问题,不通就是后端自己的问题。
第三,看静态资源和接口是不是 404。页面能打开但样式全丢、接口全报 404,多数是路径前缀问题(见第四节),或者是 location 块里少写了斜杠。对照着上面那条斜杠规则逐行检查,一般都能找到。
七、日常维护的两条习惯
一是配置文件按服务拆文件,别全塞进一个 nginx.conf。一个服务一个文件,出问题先 nginx -t 再 reload,改错了也只影响这一个服务,排查时直接禁用对应软链接就能隔离。
二是给每个后端服务配好自启动(systemd 或 Docker 的 restart 策略),机器重启后 Nginx 先起来、后端随后起来,整个站就自己恢复了。如果后端没配自启动,重启一次机器就要手动起一遍所有服务,早晚会漏掉一个。
一台小服务器跑多个网站,核心就一句话:Nginx 管入口,后端服务只管自己那一摊。入口统一了,域名、证书、限流、日志就都有了统一的落点,后面再加服务只是多写一个 server 块的事。
- 点赞
- 收藏
- 关注作者
评论(0)