海外服务器如何搭建多站点环境?Nginx虚拟主机与域名配置教程

一台海外服务器上跑好几个网站,是很常见的需求:一个博客、一个企业站、一个小商城,如果每个站都单独买一台服务器,成本高得离谱。好在 Nginx 支持"虚拟主机"(virtual host),可以让一台服务器用同一个 IP、同一组端口,根据访问的域名把请求分发给不同的网站目录,彼此互不干扰。这也是绝大多数站长在一台服务器上放多个站的标准做法。

这篇文章手把手教你搭建多站点环境:先讲清楚 Nginx 虚拟主机的原理,再给出目录结构与权限隔离方案,然后给出完整的 server 配置示例(含多域名绑定、通配符 SSL)、防火墙放行步骤,最后是验证与常见坑。命令同时给出 RHEL/CentOS/Rocky 系(yum/dnf)和 Debian/Ubuntu 系(apt)两套。涉及防火墙和端口操作的命令都附风险提示与回滚方式,请在测试环境验证后再上生产。

地域与合规提醒:服务器在海外,但面向中国大陆提供互联网信息服务的经营性业务通常须依法办理相关备案,具体以主管部门要求为准;同时要遵守业务落地国家/地区的法律。

一、Nginx 虚拟主机的原理

1. 什么是虚拟主机

Nginx 处理一个请求时,会根据请求头里的 Host(也就是浏览器地址栏里的域名)去匹配不同 server 块的 server_name,匹配到哪个就把请求交给哪个 server 处理。于是同一台服务器、同一个 80/443 端口,可以服务任意多个域名,每个域名对应不同的网站根目录、不同的配置。这就是基于域名的虚拟主机。

2. 三种常见虚拟主机类型

  • 基于域名:用 server_name 区分,最常用。
  • 基于端口:用不同端口区分,如 8080、8081,使用不便。
  • 基于 IP:用不同 IP 区分,需要多个 IP。

本文讲最实用的"基于域名"。

3. 前置条件

  • 一台海外服务器(以常见 Linux 发行版为例)。
  • 安装好 Nginx。
  • 域名已注册,并已把 A 记录解析到服务器 IP(在域名服务商处配置)。
  • 已开通服务器防火墙/安全组的 80、443 端口。
# 安装 Nginx
# RHEL/CentOS/Rocky(8+ 用 dnf,7 用 yum)
sudo dnf install -y nginx    # 或 sudo yum install -y nginx

# Debian/Ubuntu
sudo apt update && sudo apt install -y nginx

二、目录结构与权限隔离

多站点最关键的一点是"隔离":一个站出问题别拖垮别的站,一个站的程序别随便读写别的站的文件。

1. 推荐的目录结构

/www/
├── site-a/
│   ├── public/          # 网站根目录(只暴露这一层)
│   ├── logs/            # 该站日志
│   └── tmp/             # 临时文件
├── site-b/
│   ├── public/
│   ├── logs/
│   └── tmp/
└── site-c/
    └── ...

把每个站放在独立的顶层目录,网站根目录只暴露 public 层,配置文件、日志、临时文件分开,权限清晰。

2. 按站点建立独立系统用户

强烈建议每个站点用独立的系统用户运行,避免站点之间越权访问。

# 为每个站点建立独立的系统用户(无登录权限)
sudo useradd -r -s /sbin/nologin www-site-a
sudo useradd -r -s /sbin/nologin www-site-b

# 创建目录并归属到对应用户
sudo mkdir -p /www/site-a/public /www/site-a/logs /www/site-a/tmp
sudo chown -R www-site-a:www-site-a /www/site-a

sudo mkdir -p /www/site-b/public /www/site-b/logs /www/site-b/tmp
sudo chown -R www-site-b:www-site-b /www/site-b

权限建议:目录 755,文件 644,敏感文件(如配置文件)不要给 others 读权限。

sudo find /www/site-a -type d -exec chmod 755 {} \;
sudo find /www/site-a -type f -exec chmod 644 {} \;

3. 注意 PHP-FPM 隔离

如果站点用 PHP,建议每个站点跑独立的 PHP-FPM 池(pool),分别指定各自的运行用户和 socket,这样 PHP 进程之间也隔离。若共用一个池,就以最低权限用户运行,风险较大。

三、完整的 Nginx 配置示例

1. 主配置里引入站点配置

很多发行版的 Nginx 默认会 include 站点目录:

# /etc/nginx/nginx.conf 中通常有类似内容
http {
    include       /etc/nginx/conf.d/*.conf;
    # Debian/Ubuntu 常见:include /etc/nginx/sites-enabled/*;
}

把每个站点的配置放到 conf.d/(Debian/Ubuntu 也可用 sites-available + sites-enabled 软链接)。

2. 站点 A 的 HTTP 配置

# /etc/nginx/conf.d/site-a.conf
server {
    listen 80;
    server_name www.site-a.com site-a.com;   # 主域名 + 带 www
    root /www/site-a/public;
    index index.html index.php;

    access_log /www/site-a/logs/access.log;
    error_log  /www/site-a/logs/error.log;

    location / {
        try_files $uri $uri/ =404;
    }
}

3. 站点 B 的配置(同服务器不同域名)

# /etc/nginx/conf.d/site-b.conf
server {
    listen 80;
    server_name www.site-b.com site-b.com;
    root /www/site-b/public;
    index index.html index.php;

    access_log /www/site-b/logs/access.log;
    error_log  /www/site-b/logs/error.log;

    location / {
        try_files $uri $uri/ =404;
    }
}

注意 server_name 必须各站唯一,否则会匹配到默认 server(第一个或标了 default_server 的)。

4. 通配符 SSL 的 HTTPS 配置

如果同一站有多个子域名,可以用通配符证书。通配符证书只覆盖一级子域名(如 *.site-a.com 覆盖 www.site-a.com、api.site-a.com,但不覆盖 a.b.site-a.com)。

server {
    listen 443 ssl;
    http2 on;
    server_name site-a.com *.site-a.com;

    ssl_certificate     /etc/nginx/ssl/site-a.com.crt;      # 证书(含链)
    ssl_certificate_key /etc/nginx/ssl/site-a.com.key;      # 私钥
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;
    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 10m;

    root /www/site-a/public;
    index index.html index.php;

    access_log /www/site-a/logs/access.log;
    error_log  /www/site-a/logs/error.log;
}

# 把 80 端口请求跳转到 https(可选,但推荐)
server {
    listen 80;
    server_name site-a.com *.site-a.com;
    return 301 https://$host$request_uri;
}

私钥文件权限要收紧:

sudo chmod 600 /etc/nginx/ssl/site-a.com.key

5. 检查配置并重载

# 语法检查,必须通过再重载
sudo nginx -t

# 平滑重载(不中断连接)
sudo systemctl reload nginx

# 开机自启
sudo systemctl enable nginx

风险提示:nginx -t 通过后再 reload;如果 reload 失败但旧进程还在,服务通常不受影响,可回滚到上一版配置再 reload。

四、防火墙与安全组放行

1. 云厂商安全组

如果服务器来自云厂商,要先在控制台的安全组里放行 80、443 端口(入方向)。这一步在云平台操作,不涉及服务器命令。

2. 系统防火墙

# firewalld(RHEL/CentOS/Rocky)
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-all       # 核对

# ufw(Debian/Ubuntu)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw status verbose

风险提示:

  • 修改防火墙前,确保 SSH 端口(默认 22)已放行,否则可能把自己锁在服务器外面。
  • 云服务器还要确认安全组没有误拦 SSH。
  • 回滚方式:firewalld 用 --remove-service,ufw 用 ufw delete allow 80/tcp。
  • 建议先在测试环境验证,保留一个已登录的 SSH 会话再改防火墙。

五、验证多站点是否生效

1. 本机 hosts 测试(推荐先本地验证)

在本地电脑的 hosts 文件里临时把域名指向服务器 IP,再访问,可绕过 DNS 缓存快速验证:

# Linux/macOS: /etc/hosts    Windows: C:\Windows\System32\drivers\etc\hosts
# 添加一行(示例):
# 1.2.3.4  www.site-a.com site-a.com

2. curl 带 Host 头验证

# 直接指定域名访问,看是否命中对应站点
curl -I http://www.site-a.com/
curl -I http://www.site-b.com/

# 用 --resolve 强制解析到指定 IP(不依赖本地 DNS)
curl -I --resolve www.site-a.com:80:1.2.3.4 http://www.site-a.com/

能返回各自的页面、日志分别写入各自目录,就说明多站点配置成功。

3. 检查默认站点

如果访问一个未配置的域名,会命中默认 server。可以显式配置一个"兜底"server,返回 444 或一个提示页,避免陌生域名被解析到你的服务器:

server {
    listen 80 default_server;
    server_name _;
    return 444;   # 直接断开连接
}

六、多站点日常运维要点

搭好只是第一步,多站点环境长期跑下来,有几个运维细节必须处理,否则迟早出事。

1. 新增站点的标准流程

建议固定成一个流程,避免临时乱改:

  1. 建独立系统用户和目录(useradd + mkdir + chown)。
  2. 放站点的 Nginx 配置到 conf.d/,server_name 写全(含带 www)。
  3. 配好该站的日志路径和 SSL 证书。
  4. nginx -t 检查语法。
  5. systemctl reload nginx 平滑生效。
  6. 用 curl --resolve 或本地 hosts 验证命中正确站点。
  7. 在监控里加入该站,纳入统一监控。

2. 日志管理与轮转

多站点日志分散在各站 logs 目录,要防止日志把磁盘写满。用 logrotate 定期轮转:

# /etc/logrotate.d/nginx-sites(示例)
/www/site-*/logs/*.log {
    daily
    rotate 14
    missingok
    notifempty
    compress
    delaycompress
    copytruncate
}

copytruncate 适合不便让 Nginx 重新打开日志文件的场景;若在 Nginx 里配置了向 logrotate 发送 USR1 信号,也可以不截断而直接重开。

3. 备份策略

多站点意味着配置和数据都要分别备份:

  • 备份各站点目录、数据库,以及 /etc/nginx/conf.d/ 的配置文件。
  • 备份要能覆盖"单个站点"和"整机"两种粒度。
  • 定期验证备份可恢复,别只备份不演练。
# 打包某站点数据(示例)
tar -czf /backup/site-a-$(date +%F).tar.gz /www/site-a

4. 监控与资源争抢

多站点共享同一台服务器,最容易互相影响:

  • 监控整机 CPU、内存、磁盘 IO、带宽,以及各站点的请求量和错误率。
  • 某个站被攻击或流量暴增,可能拖垮同机其他站,要能快速定位到"是哪个站"。
  • 建议对每个站单独统计访问日志,便于溯源。

5. 伪静态与路径重写

很多 CMS 需要伪静态(如把 index.php?p=1 重写为 /p/1)。写重写规则时要注意规则只作用于本 server 块,别把规则写在全局把其他站也影响了。

# 以常见 CMS 伪静态为例(示意)
location / {
    try_files $uri $uri/ /index.php?$args;
}

具体规则以你所用程序的官方文档为准。

常见问题

Q1:一台服务器能放多少个站?
理论上没有硬限制,取决于 CPU、内存、磁盘 IO 和带宽。静态站可以放很多;动态站(PHP/数据库)要看资源。经验上小型站几十个是常见的,具体以监控到的资源使用为准。

Q2:多个站能不能共用一个 SSL 证书?
如果域名用同一张多域名证书(SAN 证书)或同一通配符证书,可以。否则要各自配置证书。server_name 里列出的域名要和证书覆盖范围匹配。

Q3:为什么访问域名却打开了别的站?
多半是 server_name 没匹配上,落到了默认 server。检查域名拼写、是否带 www、以及是否有 default_server。也可用 curl -I 带正确 Host 验证。

Q4:改了防火墙后 SSH 连不上了怎么办?
如果还开着 firewall-cmd/ufw 的其它会话,先把 SSH 端口加回来再 reload。若完全断开,只能通过云厂商的 VNC/串口控制台登录修复。所以改防火墙前务必确认 SSH 端口已放行。

Q5:日志都写在一起怎么办?
每个 server 块里单独指定 access_log 和 error_log 路径,指向各自站点的 logs 目录,权限归属对应站点用户,即可分开。

总结

  • Nginx 通过 server_name 实现基于域名的虚拟主机,一台服务器、一个 IP、同端口可服务多个站。
  • 隔离靠两件事:独立目录结构(只暴露 public)+ 独立运行用户(每站一个系统用户,PHP 用独立 FPM 池)。
  • SSL 可用通配符证书覆盖一级子域名,私钥权限设 600,80 端口跳转 443。
  • 每次改配置先 nginx -t 再 systemctl reload nginx;改防火墙前务必确认 SSH 端口已放行,并准备回滚方式。
  • 用本地 hosts 或 curl --resolve 验证多站点是否生效,配置默认 server 兜底防止陌生域名命中。
  • 日常运维要管好日志轮转、备份、监控和资源争抢,新增站点走固定流程,伪静态规则只作用于本 server 块。合规上注意备案要求与业务落地地法律。