🚀 第02章 · 虚拟主机 server/server_name
本服务器 nginx 配置解析
虚拟主机 server/server_name¶
一台 Nginx 往往挂好几个域名,靠"一个 server 块代表一个站点"来区分。本章讲清 server 块的含义、server_name 的匹配规则,并用本机真实的四个站点配置做解析。学会它,你就能在没有独立服务器的情况下,用一台机器托管任意多个网站。
什么是虚拟主机¶
虚拟主机(Virtual Host)指:同一台物理服务器、同一个 IP(一个 443 端口),却能根据访问的域名把请求交给不同的站点处理。Nginx 的实现方式就是每个站点写一个 server {} 块。
本机四个站点,共用一个 443 端口,靠 server_name 区分:
| 域名 | 外部访问(443) | 后端转发到 |
|---|---|---|
bangdream.xyz |
Nginx 终止 TLS | 127.0.0.1:3000 |
lovelive.top |
Nginx 终止 TLS | 127.0.0.1:3010 |
dsh.bangdream.xyz |
Nginx 终止 TLS | 127.0.0.1:3081 |
gitlab.bangdream.xyz |
Nginx 终止 TLS | 127.0.0.1:8090 |
理解 浏览器发来的是明文 HTTP/HTTPS 请求,Nginx 拿到后读
Host请求头(HTTP/1.1 必须携带),再拿这个值和各个server_name比对,决定交给哪个server块。
server_name 怎么匹配¶
server_name 后面可以跟多个域名和通配符,匹配优先级从高到低:
server {
server_name bangdream.xyz www.bangdream.xyz; # 精确名(最优先)
server_name *.bangdream.xyz; # 通配符(前/后)
server_name ~^www\.\d+\.example\.com$; # 正则(优先级最低)
}
本机用的都是精确匹配,简单直接。匹配规则汇总:
| 写法 | 匹配类型 | 优先级 |
|---|---|---|
a.example.com |
完全精确 | 1 最高,逐字匹配 |
*.example.com |
前缀或后缀通配 | 2,从左到右前缀优先 |
www.* |
前缀通配 | |
~^www\..*$ |
正则 | 3 最低,按书写顺序 |
易错 如果写了多个
server,且某个请求的Host谁都匹配不上,就会落到default_server(没有则第一个出现的server)上。本机bangdream.xyz的 80 端口块标注了default_server,处理所有"不认识的" HTTP 请求并返回 404。
本机一个 server 块拆解¶
以 lovelive.top.conf 为例:
# Love Live! - lovelive.top
server {
server_name lovelive.top www.lovelive.top;
access_log /var/log/nginx/lovelive.access.log;
error_log /var/log/nginx/lovelive.error.log;
# 阻止敏感路径被代理访问
location ~ ^/(node_modules|scripts)/ { return 403; }
location = /package.json { return 403; }
location = /package-lock.json { return 403; }
location / {
proxy_pass http://127.0.0.1:3010;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
listen [::]:443 ssl;
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/lovelive.top/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/lovelive.top/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
拆成几层看:
server_name—— 这个server为哪些域名服务;两个域名写一起,www和非www都能到。access_log/error_log—— 每个站点有独立的日志文件,方便按站点排查。location / { ... }—— 根路径交给后端3010,即落到后端的 Node 服务。listen 443 ssl;—— 监听 443 端口并开启 TLS。ssl_certificate—— 指向 certbot 签发的证书文件路径。
listen 与端口¶
listen 决定"监听哪个 socket"。常见形态:
| 写法 | 含义 |
|---|---|
listen 443 ssl; |
仅 IPV4 的 443 端口,启用 TLS |
listen [::]:443 ssl; |
仅 IPv6 的 443 端口 |
listen 443 ssl; + listen [::]:443 ssl; |
IPv4 + IPv6 都监听 |
listen 80; |
HTTP 80 端口 |
listen 80 default_server; |
80 端口的兜底虚拟主机 |
本机四个 HTTPS 站点都同时写了 IPv4 和 IPv6,所以双栈都能访问。[::] 是 IPv6 的"任意地址"写法,对应 IPv4 的 0.0.0.0。
80 → 443 跳转块¶
certbot 会在每个 domain 配置里生成一个 80 端口的 server 块:只要 Host 是这个域名,就 301 跳到 HTTPS。
server {
if ($host = lovelive.top) {
return 301 https://$host$request_uri;
}
if ($host = www.lovelive.top) {
return 301 https://$host$request_uri;
}
listen 80;
listen [::]:80;
server_name lovelive.top www.lovelive.top;
return 404;
}
易错 这里的
if ($host = ...) { return 301 }是几乎唯一"安全使用if"的模式——只做return。Nginx 的if在其他场景(比如在if里用proxy_pass)行为诡异,属于文档里明令避免的坑。只把它当条件跳转用,别在里面做转发。
从零新建一个虚拟主机¶
接到"帮我挂一个 mydemo.com"的需求,完整流程:
# 1. 写配置到 available
sudo nano /etc/nginx/sites-available/mydemo.conf
# 2. 启用(软链接到 enabled)
sudo ln -s /etc/nginx/sites-available/mydemo.conf /etc/nginx/sites-enabled/mydemo.conf
# 3. 先测试语法
sudo nginx -t
# 4. 优雅重载
sudo systemctl reload nginx
mydemo.conf 最小内容(纯静态网站):
server {
listen 80;
server_name mydemo.com www.mydemo.com;
root /var/www/mydemo;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
易错 配置写好后必须
nginx -t通过再 reload,否则语法错误会导致整份配置被拒、reload 失败、仍跑旧配置,而且可能syntax error和test failed一起出现让人摸不着头脑。这一步也验证了:改错一处,全部站点重启失败——所以永远先测后载。
小结¶
server 块 = 一个虚拟主机;Nginx 用 Host 头匹配 server_name 把请求分发给对应站点;listen 定端口、server_name 定域名;sites-available 写配置、sites-enabled 软链启用;改完 nginx -t + reload。现在你已经能发起一次完整的多站点托管了。下一章讲 location / 里那个 proxy_pass 到底做了什么——反向代理。