thumbnail

写在前面

如果你手头有一台云服务器,域名却有好几个——AI 工具站、即时通讯、博客、论坛、公司官网……你会怎么办?每站一台服务器?钱包受不了。全堆一起?怕性能扛不住。

这篇文章就是我的实战记录:如何用一台 2核4G 的轻量云服务器,通过 Nginx 反向代理 + 端口隔离,稳稳跑起多个完全不同的站点。全程分享技术思路,配置可复用。

为何要这么做

事情是这样的——我手头有一台 2核4G 的服务器,结果域名越搞越多:AI 服务、聊天工具、论坛、博客……眼看着站点列表越来越长,总不能每个都单独买一台吧?

于是就有了这个执念:能不能把多个站点全塞进这一台机器里,而且还要跑得稳?答案是可以,关键在架构设计。

核心思路:Nginx 反向代理 + 端口隔离

一台服务器上运行多个 Web 服务,最朴素也最可靠的方案就是:每个服务监听不同的本地端口,由 Nginx 作为统一入口,根据请求的域名转发到对应的服务端口。

这样做有几个好处:

  • 服务之间完全隔离,一个挂了不影响其他
  • 各自独立部署、独立升级,互不干扰
  • Nginx 层面统一管理 SSL、限流、日志
  • 资源按需分配,非核心服务可以按需启停

架构示意图如下(以假设的 6 个服务为例):

服务类型推荐技术栈端口范围备注
个人博客/内容站Node.js / PHP8081~8089可静态化加速
AI 工具/API 服务Node.js / Python8090~8099可能需要 WebSocket
即时通讯/IMNode.js + WebSocket8100~8109需配置 Upgrade 头
论坛/社区PHP (Discuz/WordPress)8110~8119数据库可复用
流量/监控面板自建/Python8120~8129可定时任务按需启动
公司官网/落地页静态/PHP8130~8139静态资源 Nginx 直出

Nginx 反向代理配置模板

每个站点的 Nginx 配置大同小异,核心就是 server_name 和 proxy_pass。下面是一个通用模板:

server {
    listen 443 ssl http2;
    server_name your-domain.com;  # 替换为你的域名

    ssl_certificate     /etc/nginx/ssl/your-domain/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/your-domain/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8081;  # 替换为你的服务端口
        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;
    }

    # 如果服务需要 WebSocket(如 IM、AI 流式输出)
    location /ws {
        proxy_pass http://127.0.0.1:8081;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 86400;
    }
}

每个站复制一份,改 server_name 和 proxy_pass 端口即可。需要 WebSocket 的服务单独配一个 location。

部署中的三个典型坑

理想很丰满,现实很骨感。部署过程中踩了三个大坑,也是多站点部署最容易遇到的问题。

坑①:WebSocket 连接失败

IM、AI 流式输出等服务依赖 WebSocket 维持长连接。如果 Nginx 没配 Upgrade 头,握手请求会被当成普通 HTTP 处理,导致 400 错误。

# 核心修复:在 location 中显式声明 Upgrade
location /ws {
    proxy_pass http://127.0.0.1:服务端口;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 86400;  # 24h 超时
}

要点:每个需要 WebSocket 的服务都要单独配 location,且 proxy_read_timeout 必须设长(至少 86400 秒),否则 Nginx 会自动掐断连接。

坑②:SSL 证书太多难管理

站点一多,证书管理就成了噩梦。每个域名单独申请、手动续期,迟早会漏。

解决方案:用泛域名证书(Let's Encrypt 免费),一张证书覆盖所有子域名。如果有不同根域的域名,单独再申请一张就好。

# 使用 acme.sh 一键申请泛域名证书
curl https://get.acme.sh | sh
acme.sh --issue -d example.com -d '*.example.com' \
  --dns dns_cf  # Cloudflare DNS API 验证

# 安装到 Nginx
acme.sh --install-cert -d example.com \
  --key-file /etc/nginx/ssl/example.com/privkey.pem \
  --fullchain-file /etc/nginx/ssl/example.com/fullchain.pem \
  --reloadcmd "nginx -s reload"

acme.sh 会自动续期(60 天自动续),一次配置终身无忧。不同 DNS 服务商(阿里云、腾讯云、Cloudflare 等)都有对应的 API 插件。

坑③:内存不够用

多个服务同时运行,内存消耗不容小觑。Node.js 服务尤其占内存,PHP 也不省心。

我的解决三板斧:

  1. 加 Swap:分配 2~4GB Swap 空间,物理内存不够时系统自动换出,防止 OOM 杀进程
  2. 限制单进程内存:Node.js 启动时加 --max-old-space-size=512,PHP-FPM 调低 pm.max_children
  3. 非核心服务按需启动:低频率服务(如日志分析、监控面板)做成定时任务或手动启停,不常驻
# 创建 Swap 文件
fallocate -l 4G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab

# PM2 限制 Node 内存(ecosystem.config.js)
module.exports = {
  apps: [{
    name: 'my-app',
    script: 'app.js',
    node_args: '--max-old-space-size=512',
  }]
}

# PHP-FPM 调优(www.conf)
pm.max_children = 5
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

优化之后,多服务稳定运行,内存控制在合理范围,再也没炸过。

多站点部署的几个建议

  • 端口避开常见端口(3000、8080、9090),减少被扫描猜中的概率
  • 非必需的服务用 Docker 运行,方便隔离和迁移,出问题直接删容器重建
  • MySQL / Redis / Nginx 等中间件全局共用一份即可,没必要每个服务单独装
  • 日志一定要做轮转(logrotate),多个服务的日志很容易写满磁盘
  • 部署前简单压测一下(ab / wrk),找找瓶颈在哪,心中有数
  • 敏感信息(端口、域名、路径)不要在公开文章里贴原始配置,脱敏处理

总结

折腾的乐趣不在于结果多牛,而在于过程——遇到问题、查资料、试错、最终搞定。一台 2核4G 的服务器跑多个站点,不是什么了不起的架构,但对个人站长来说,这就是把每一份资源都用到极致。

本文分享的是思路和方法论,配置模板拿过去改改就能用。如果你也有一台小服务器和一堆域名,不妨试试这个方案。

有任何问题欢迎评论交流。