预算有限或者项目初期,经常会在一台服务器上部署多个网站。不少人购买一台云主机,同时搭建公司官网、测试环境、内部管理后台,不想额外购置服务器。部署主要分两种思路,依靠域名区分,或是依靠端口区分。域名区分就是用户访问不同网址,服务器读取域名,分发请求到对应网站目录。端口区分是同一个IP搭配不同端口,80端口放主站,8080用作后台,3000跑API接口。两种方案不冲突,实际部署过程中经常搭配使用。
先说多端口部署,实现方式最简单,每个服务监听独立端口,互不干扰。Nginx监听80和443承载主站,Node.js程序跑在3000端口提供接口,Python开发的管理后台占用5000,Java应用监听8080。服务器上运行多个进程,各自绑定端口,外部用户通过IP加端口访问。这种方式在开发测试阶段很省事,不用配置域名,无需等待DNS生效,服务启动就能直接访问。

直接暴露端口会带来不少麻烦。用户需要记住端口号,访问体验差。每个端口都需要单独配置SSL证书,维护繁琐。安全层面风险更高,开放端口越多,被扫描攻击的概率越大。生产环境更常用的方案,仅对外开放80和443端口,其余服务绑定127.0.0.1本地地址,依靠Nginx反向代理统一入口。用户访问example.com/api,Nginx转发请求到本机3000端口;访问example.com/admin,则转发至5000端口。外部只能看到80、443端口,内部端口无法从公网访问。
Nginx实现该功能依靠server块与location块。单个server块对应一个域名,listen 80代表监听HTTP端口,server_name填写域名。root指向网站文件目录,index设置默认首页。多个域名就配置多个server块,每个块内server_name不同,root指向独立目录。Nginx接收请求,读取请求头Host字段匹配对应server块,返回网站文件给访客,也就是虚拟主机。单台机器可以部署几十个网站,相互之间不会冲突。
想用端口承载后端服务,就在server块内部添加location配置。location /api/下填写proxy_pass http://127.0.0.1:3000/,所有/api开头请求转发本机3000端口。location /admin/转发至5000端口。用户只需要记住一个域名,路径用来区分后端服务。路径转发比直接IP加端口访问更美观,安全性更好。
PHP站点部署有特殊之处。Nginx本身不处理PHP代码,PHP相关请求转发到PHP-FPM进程。一台服务器部署多个PHP网站,可以为每个站点配置独立PHP-FPM池,每个池使用单独用户和socket文件。这样A站点程序无法读取B站点文件,做好权限隔离,单个网站被入侵不会牵连其余站点。Nginx的server块通过fastcgi_pass指向对应socket文件。
数据库层面,多个网站可以共用一套MySQL实例,每个站点单独创建数据库与数据库账号,账号仅拥有自身数据库权限。不要全部网站共用root账号连接数据库,会留下巨大安全隐患。如果站点数据敏感度差异大,可以部署两套MySQL实例,监听不同端口或者socket,进一步隔离。
Docker让多站点部署更整洁。每个网站打包成独立容器,容器内部自带web服务与运行环境。宿主机映射不同端口给各个容器,再单独部署Nginx容器做反向代理,统一对外入口。容器之间网络隔离,单个容器故障不会影响其他容器。升级时拉取新镜像重启容器,不会污染宿主机系统环境。缺点是资源消耗高于直接运行进程,但环境边界清晰。
端口管理有几个实操要点。修改Nginx配置后,执行nginx -t校验语法,确认无误再reload,不要直接restart。reload平滑加载配置,不会中断正在处理的请求。查询端口占用,使用ss -tlnp或者lsof -i:端口号,避免端口冲突。防火墙、安全组按需放行,只开放对外端口,内部端口禁止公网放行。Ubuntu系统使用ufw,CentOS系列使用firewall-cmd,云服务器还要在控制台安全组调整入站规则。
日志分开存储。每个网站的访问日志、错误日志单独生成文件,Nginx server块通过access_log、error_log指定文件路径。排查故障直接查看对应站点日志,不用在大体积混合日志文件内检索。日志文件配置logrotate,防止长期运行占满磁盘空间。
多网站多端口部署存在成本。端口数量多容易混淆,服务依赖关系变复杂,故障排查需要逐层定位。SSL证书续期、PHP版本升级、安全补丁,全部站点都需要维护。比较务实的方案,控制单台服务器网站数量,不要为节省成本一次性部署几十个站点,资源争抢和排障成本会超过托管节省的费用。不同站点流量、重要程度差别大,可以把核心站点单独部署,测试站、边缘站点放在另一台服务器,分散风险,降低维护压力。