一文吃透 Nginx 虚拟主机:原理 + 双站点实战 + SELinux 排错

Nginx 虚拟主机配置实战(案例一)

同一台服务器、同一个 IP、同一个 80 端口,如何同时运行多个网站?答案是 Nginx 的虚拟主机(Virtual Host / server block)。

一、案例需求

公司有一台 Nginx 服务器(IP:192.168.171.129,系统:CentOS 7),需要同时上线两个网站:

域名 网站根目录 首页效果
www.site1.com /data/nginx/site1 蓝色 "这是 Site1 首页"
www.site2.com /data/nginx/site2 红色 "这是 Site2 首页"

用户访问不同的域名,看到不同的页面,两个网站互不干扰。

二、核心原理

补充说明:在案例 1 中,Nginx 的角色是"内容提供方"------网站的 HTML 文件就存放在它自己的站点目录里(/data/nginx/site1site2),Nginx 收到请求后直接读取磁盘上的文件返回给用户,中间不经过任何其他程序。

  • 浏览器请求网站时,会在 HTTP 请求头里带上 Host: www.site1.com
  • Nginx 收到请求后,拿着这个 Host 去和每个 server 块里的 server_name 比对
  • 匹配到哪个 server 块,就按那个块的 root 去找文件并返回

所以"虚拟主机"的本质是:同一个 IP、同一个 80 端口,Nginx 靠域名(Host 头)区分请求该进哪个站点。

三、环境准备

1. 安装 Nginx

CentOS 7 上先添加 EPEL 扩展源,再安装 Nginx(非 root 用户请加 sudo):

bash 复制代码
yum install -y epel-release
yum install -y nginx

-y 表示安装过程中的提问全部自动回答 yes。看到 Complete! 即安装成功。

补充避坑:CentOS 7 官方源已停止维护,如果执行时提示 Could not resolve host: mirrorlist.centos.org,需要先把 yum 源换成阿里云存档源(centos-vault),再执行上面的安装命令。

2. 启动并设置开机自启

bash 复制代码
systemctl start nginx
systemctl enable nginx
systemctl status nginx

看到绿色的 active (running) 表示启动成功。

3. 本机验证

bash 复制代码
curl http://127.0.0.1

能返回 HTML 页面即正常。

补充:CentOS 上 Nginx 主配置文件是 /etc/nginx/nginx.conf,其中默认有一行 include /etc/nginx/conf.d/*.conf;,所以虚拟主机配置只需放在 /etc/nginx/conf.d/ 下新建 .conf 文件,Nginx 启动时会自动加载,不需要改动主配置文件。

四、实战步骤

1. 创建两个网站的目录和首页

bash 复制代码
mkdir -p /data/nginx/site1 /data/nginx/site2

echo '<h1 style="color:blue">这是 Site1 首页</h1>' > /data/nginx/site1/index.html
echo '<h1 style="color:red">这是 Site2 首页</h1>' > /data/nginx/site2/index.html

检查是否创建成功:

bash 复制代码
ls -l /data/nginx/site1 /data/nginx/site2
cat /data/nginx/site1/index.html
cat /data/nginx/site2/index.html

2. 编写两个虚拟主机配置

新建 /etc/nginx/conf.d/site1.conf:

nginx 复制代码
server {
    listen       80;
    server_name  www.site1.com;

    root   /data/nginx/site1;
    index  index.html;

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

新建 /etc/nginx/conf.d/site2.conf:

nginx 复制代码
server {
    listen       80;
    server_name  www.site2.com;

    root   /data/nginx/site2;
    index  index.html;

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

参数说明:

参数 作用
listen 80 监听 80 端口(HTTP 默认端口)
server_name 本站点的域名,虚拟主机靠它区分站点
root 网站根目录,Nginx 到这里找网页
index 访问目录时默认打开的文件
location / 对所有请求路径生效的匹配规则
try_files $uri $uri/ =404 依次尝试找文件、找目录,都找不到就返回 404

3. 检查配置语法

bash 复制代码
nginx -t

看到 syntax is oktest is successful 说明配置正确。

4. 让本地能解析这两个域名(测试用)

把域名加进虚拟机的 /etc/hosts:

bash 复制代码
echo "192.168.171.129 www.site1.com www.site2.com" >> /etc/hosts
tail -3 /etc/hosts

/etc/hosts 是本地域名表,优先级高于 DNS。我们没有真实域名,所以手动告诉系统"www.site1.com 就是这台机器",这种方法只影响当前机器,适合测试。

5. 加载新配置

bash 复制代码
systemctl reload nginx

nginx -t 只是检查语法,不会让配置生效 ;真正应用配置要用 systemctl reload。reload 是平滑重载,不中断正在处理的请求,生产环境改配置都用它。

6. 验证虚拟主机

bash 复制代码
curl http://www.site1.com
curl http://www.site2.com

两个域名走同一个 IP、同一个 80 端口,却返回不同页面 ------ 虚拟主机配置成功。

五、踩坑记录:403 Forbidden(SELinux)

现象

配置完成后 curl 访问两个域名,均返回 403 Forbidden

排查思路

bash 复制代码
tail -n 10 /var/log/nginx/error.log
getenforce
ls -lZ /data/nginx/site1

错误日志关键信息:

text 复制代码
"/data/nginx/site1/index.html" is forbidden (13: Permission denied)

原因

文件权限看起来完全正常,但 CentOS 7 默认开启 SELinux。Nginx 只能读取带有 httpd_sys_content_t 安全上下文标记的文件,而新建在 /data 下的网站目录标记不对,所以被拒绝访问。

修复方案

bash 复制代码
chcon -Rt httpd_sys_content_t /data/nginx
systemctl reload nginx

chcon -Rt 的含义:递归(-R)地把 /data/nginx 下所有文件的安全上下文类型(-t)改成 httpd_sys_content_t,告诉 SELinux"这些是网站内容,Nginx 可以读"。

这也是为什么系统自带的 /usr/share/nginx/html 不用处理就能访问------它出厂时就带着正确的 SELinux 标签。

六、进阶验证

1. 访问没登记的域名,会落到默认站点

bash 复制代码
curl http://192.168.171.129
curl -H "Host: www.unknown.com" http://192.168.171.129

预期看到 Nginx 欢迎页。原理:

  • curl -H "Host: ..." 是手动伪造请求头,模拟"我访问的是这个域名"
  • 当 Host 与任何 server_name 都不匹配时,Nginx 把请求交给默认站点------CentOS 的 Nginx 自带 default.conf,listen 80 default_server
  • 如果不存在默认站点,Nginx 会悄悄用加载顺序中第一个 server 块兜底,导致"访问别的域名却看到 site1"的诡异问题

生产环境规范做法:显式保留一个 default_server(通常返回 404 或跳转官网),不要让请求随机落到某个站点。

2. Nginx 匹配的不是网址,而是 Host 头

bash 复制代码
curl -H "Host: www.site2.com" http://192.168.171.129

访问地址明明是 IP,但因为 Host 头是 www.site2.com,返回的是 Site2 的红色页面。这再次验证:Nginx 不关心地址栏输入了什么,它只看请求头里的 Host 和 server_name 是否匹配。

七、小结

  • 虚拟主机 = 一台服务器通过 server_name 区分多个网站
  • 配置套路固定:建目录 → 写 conf.d/*.confnginx -tsystemctl reload → hosts 解析 → curl 验证
  • 遇到 403 先查 /var/log/nginx/error.log,再考虑 SELinux
  • default_server 建议显式配置,避免请求"乱入"
  • hosts 只用于本地测试,正式上线需要配置真实 DNS 解析
  • 本案例里 Nginx 是"静态内容提供方":自己存文件、自己返回页面;下一篇"反向代理实战"里,Nginx 会换一个角色,变成"转交员"------只负责把请求转发给后端程序,再把后端的结果带回给用户
相关推荐
mengge.cloud1 小时前
0909华为云网络类服务实践小白实验教程
linux·运维·服务器·网络·华为云·php
智恒百亿1 小时前
CSDN 文章|八卡 RTX5090 服务器深度实测:256GB 显存池,能否流畅跑通 70B 大模型微调?
运维·服务器
阿明61 小时前
基础编辑工具使用【Linux】
linux·运维·服务器
Tinyundg1 小时前
关于Termux的基本使用——安卓手机爆改Linux服务器?
linux·运维·服务器·智能手机·个人开发
AugustSkys2 小时前
PostgreSQL 完全指南:特性对比 + 安装部署 + 配置管理 + psql 实战 + pgAdmin 图形化
运维·postgresql·开源数据库·pgadmin
weixin_446260852 小时前
PromptMatic:通过多阶段提示优化提升大模型的指令遵循能力
运维·服务器
pt10432 小时前
从恐惧到自动化的百年突围
运维·自动化
HackTwoHub2 小时前
AI自动化信息收集赋能渗透测试!集成多款主流扫描工具,多维智能评分,精准锁定高危资产
运维·人工智能·安全·web安全·网络安全·自动化·系统安全
j7~2 小时前
【Linux】三十五.网络基础(三)《从零实现一个C++ HTTP服务器:完整项目实战》----万字详解
运维·网络协议·http·网络层·服务层·协议层·http的实现