虚拟主机 (Virtual Host)
一句话
一台服务器、一个 IP、一个端口,靠名字分辨出很多个网站。其中每一个网站的配置,就叫一个 vhost(虚拟主机)。
1. 它解决什么问题
IP 和端口是有限的,机器只有一台。2000 年代之前基本是一个网站一个 IP;现在一台机器要跑几十个站。
分辨靠两个"名字":
- HTTP(80 端口):看请求头里的
Host - HTTPS(443 端口):看 TLS 握手里的 SNI(Server Name Indication,服务端名称指示)—— 加密开始之前就得知道你要找哪个站,才可能给对证书
所以 vhost 的本质是:同一扇门上挂很多块牌子,看牌子决定领你去哪间屋。
2. 长什么样
nginx:一个 server {} 块 = 一个 vhost。
server {
listen 443 ssl;
server_name example.com; # 认领这个名字
ssl_certificate /path/fullchain.pem;
ssl_certificate_key /path/privkey.pem;
location / { proxy_pass http://127.0.0.1:3000; }
}宝塔面板:一个域名一个文件,文件名随便,起作用的是里面的 server_name。
/www/server/panel/vhost/nginx/example.com.confApache 里写作 <VirtualHost>,概念完全一样 —— "虚拟主机"这个词就是从 Apache 来的。
3. 匹配顺序(nginx)
server_name 的优先级:
精确名字 > 前缀通配(*.example.com) > 后缀通配(example.*) > 正则 > 默认站点匹配不上不报错。 请求会落到"默认站点"—— 同一个端口上第一个出现的,或者标了 default_server 的那个。这是最容易骗人的地方。
4. 默认站点是最大的坑
没匹配上时,默认站点会安安静静地返回它自己的页面。
宝塔的默认页是「域名未绑定」。这张页面长得特别像"转发没生效",于是人会跑去前端查转发,查半天查不出问题。
配套症状:
| 现象 | 值 |
|---|---|
| 根路径 | 默认站点的占位页 |
| API 路径 | 146 字节的 nginx 404 |
| 证书 | 正常(证书是前面那层发的,跟这里无关) |
判据:证书对、请求也到了、但内容是占位页 → 先数后端认领了哪些名字,别查转发。
补齐 vhost 后,同一个 API 路径会从 404 变成 401 + JSON。401 才是"找对人了,只是没带钥匙"。
5. 证书和 vhost 是两件事
- SNI 决定 443 上出哪张证书
server_name/Host决定请求交给哪个server {}
两者独立出错。所以证书对 ≠ 找对了 vhost:
- 证书错 → 浏览器报不安全,或客户端直接握手失败
- vhost 错 → 握手正常,内容是默认站点
前面有转发层时,证书往往是前面那层发的,内容才是后端这台决定的。分开看这两件事,能省很多时间。
6. 怎么查、怎么验
# 这台机器认领了哪些名字
nginx -T | grep server_name
ls /www/server/panel/vhost/nginx/*.conf
# 指定 Host 打本机,绕开 DNS 和所有转发层
curl -s -o /dev/null -w "%{http_code}\n" -H "Host: example.com" http://127.0.0.1/
# 443 上某个 SNI 出哪张证书
echo | openssl s_client -connect 127.0.0.1:443 -servername example.com 2>/dev/null | openssl x509 -noout -subject第 2 条(-H "Host:" 打 127.0.0.1)是最省事的一步:它只测"这台机器的 vhost 对不对",把 DNS、转发层、证书全部排除在外。
7. 容易踩的地方
- 前面有转发层时,域名是两关:① 转发层把这个域名转过来 ② 后端有同名 vhost。缺第二关就是第 4 节那个样子。加域名要记得两边都做。
- 改完必须 reload。宝塔的机器用
nginx -s reload,别用systemctl reload nginx—— 后者可能返回 0 但不生效。 - 80 段写
return 301 https://...是常规做法,但在"前置层终结 TLS 后转发到后端 80 端口"的架构里,它会变成无限跳转。这种场景下 80 段要直接proxy_pass。 server_name写错不报错,只是静默落默认站。写完拿第 6 节的curl -H打一下。
8. 相关
- 本机通、公网 403——容器前的域名转发层 (Loopback OK but Public 403 — Domain Forwarding Layer) —— 第 5.1 节就是本文第 7 节第一条的实例。
- 宝塔 nginx 的 systemctl reload 静默不生效 (BT Panel nginx systemctl reload Is a Silent No-Op) —— 改完 vhost 之后怎么让它真的生效。
- Htpasswd 基础鉴权 —— vhost 里常挂的鉴权。
- 跨子域会话共享 (Cross-Subdomain Session Sharing) —— 多域名同源问题时,vhost 是下手的地方。
本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/Web