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/site1、site2),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 ok 和 test 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/*.conf→nginx -t→systemctl reload→ hosts 解析 → curl 验证 - 遇到 403 先查
/var/log/nginx/error.log,再考虑 SELinux default_server建议显式配置,避免请求"乱入"- hosts 只用于本地测试,正式上线需要配置真实 DNS 解析
- 本案例里 Nginx 是"静态内容提供方":自己存文件、自己返回页面;下一篇"反向代理实战"里,Nginx 会换一个角色,变成"转交员"------只负责把请求转发给后端程序,再把后端的结果带回给用户