背景
一台机器上往往不止一个站:静态博客占一个端口,别的应用占 80。
「绑定域名」在 Nginx 里并不是改 hosts 就完事,核心是 server 块 + server_name + Host 头匹配,再配上是否做 default_server、是否反向代理。
本文依据 Nginx 官方文档整理,配置一律用示例域名,不涉及真实环境信息。
1. 请求如何选中一个 server
官方 How nginx processes a request 的顺序可以概括为:
- 连接先落在某个 listen 端口 的默认 server 上下文
- 解析请求行
- 解析
Host头 - 用
Host值在该端口的 server 里找server_name - 找不到 → 落到该端口的 default server
要点:
default_server 是 listen 端口的属性,不是 server_name 的属性。
server {
listen 80 default_server;
server_name _;
# 兜底应用(示例:旧系统)
}
server {
listen 80;
server_name blog.example.org;
# 博客
}
Host: blog.example.org → 第二个块;
Host: 1.2.3.4 或乱填域名 → 第一个块(default)。
2. server_name 怎么写
官方 Server names 支持:
| 写法 | 含义 | 例子 |
|---|---|---|
| 精确名 | 完全匹配 | blog.example.org |
| 前缀通配 | 仅允许 *. 开头 | *.example.org |
| 后缀通配 | 仅允许 .* 结尾 | mail.* |
| 正则 | ~ 开头 | ~^(?<sub>.+)\.example\.org$ |
.example.org | 裸域 + 任意子域 | 匹配 example.org 与 www.example.org |
_ | 非法域名当哨兵 | 常用于 catch-all |
匹配优先级(命中即停):
- 精确名
- 最长的
*.…通配 - 最长的
…*通配 - 配置文件中第一个匹配的正则
实践建议: 能写精确名就写精确名;正则最慢,名字多时别滥用。
完整示例:
server {
listen 80;
server_name blog.example.org www.blog.example.org;
root /var/www/blog;
index index.html;
}
3. 绑定域名的最小可用步骤
按依赖顺序,缺一不可:
DNS A/AAAA 记录 → 服务器公网 IP
↓
云安全组放行 80(及需要的 443/自定义端口)
↓
Nginx server { listen ...; server_name 你的域名; }
↓
nginx -t && systemctl reload nginx
↓
curl -H "Host: 你的域名" http://127.0.0.1/ # 本机先验
↓
浏览器访问 http://你的域名/
DNS 没生效、安全组没放行、server_name 拼错,都会表现成「绑了域名却打不开」。
4. 静态站:直接绑域名
server {
listen 80;
server_name blog.example.org;
root /home/deploy/projects/my-blog/current;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
root指向构建产物目录(例如静态站的dist)try_files:找不到文件再回退目录索引,避免错误 404 行为混乱- 改配置后务必
nginx -t,再 reload
5. 反向代理绑域名(同机多服务很常见)
当 80 已被占用,或需要「域名走 A、IP/另一域名走 B」时:
# 按 Host 分流:域名 → 本机另一端口的博客
server {
listen 80;
server_name blog.example.org;
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
}
# 其它流量 → 默认应用
server {
listen 80 default_server;
server_name _;
# 原有应用或静态页
}
为什么必须传 Host
官方 Reverse Proxy 说明:默认会改写 Host(变成 $proxy_host)。
若后端也靠虚拟主机选站,不传 proxy_set_header Host $host 会串站。
proxy_set_header Host $host;
6. 同端口多站点:加载顺序坑
配置放在 conf.d/*.conf 时,文件名会影响加载顺序;
未显式写 default_server 时,该 listen 上第一个 server 块成为默认站。
常见事故:
- 新加的
agents.example.conf字母序排在default.conf前面 - 默认站被抢走
- 用 IP 访问时进了新站,原应用「突然打不开」
规避:
# 原主站显式钉死
listen 80 default_server;
# 新域名站不要写 default_server
listen 80;
server_name blog.example.org;
改完用两种 Host 各测一次:
curl -sI -H 'Host: blog.example.org' http://127.0.0.1/ | head
curl -sI -H 'Host: 192.0.2.10' http://127.0.0.1/ | head
(192.0.2.10 为文档示例地址,按你的机器替换。)
7. 常见故障排查表
| 现象 | 优先检查 |
|---|---|
| 域名打不开,IP 正常 | DNS 是否指向正确、server_name 是否完全一致(含不带 www) |
| 打开是另一个站 | Host 匹配到了 default 或另一个 server;查 server_name 与 conf 加载顺序 |
| 403 | root 路径权限、目录是否可读、是否有 index 文件 |
| 404 但文件存在 | root/alias 是否多写了一层路径 |
| 反代后后端认错站 | 是否缺少 proxy_set_header Host $host |
| reload 无效 | 是否改了错误环境的配置;是否只 nginx -t 未 reload |
| 端口起不来 | 是否被其它进程占用、是否误监听已占用端口 |
快速自检命令:
nginx -t
systemctl is-active nginx
ss -lptn | grep nginx
curl -v -H 'Host: blog.example.org' http://127.0.0.1/
8. 什么时候用精确名、通配、正则
| 场景 | 推荐 |
|---|---|
| 一域名一站 | 精确名 |
| 一批子域同一套静态 | *.example.org |
| 仅裸域 + www | 写两个精确名,或 .example.org |
| 动态按子域选目录 | 正则 + 命名捕获(谨慎,注意性能) |
官方优化说明:精确名进 hash,正则线性扫描;域名很多时优先精确/通配。
9. 和「多层 Nginx」的关系
很多环境是:
浏览器
→ 边缘/容器 Nginx(:80/:443,按域名分流)
→ 系统 Nginx 或应用端口(:8080 等)
绑域名时要分清 哪一层 在做 server_name:
- 边缘层负责「域名 → 哪条上游」
- 内层可继续
server_name或只当静态/反代
两层都写 server_name 时,边缘必须已经把正确 Host 传下去(proxy_set_header Host $host)。
10. 结论
Nginx 绑定域名可以收成四句:
- DNS + 安全组 先通,再谈配置
server_name对齐 Host,写不清就进 defaultdefault_server显式声明,避免加载顺序抢默认站- 反代必传
Host $host,否则后端再绑域名会串站
配置改完固定动作:nginx -t → reload → 带 Host 的 curl 验证 → 浏览器复测。
参考
- Nginx. Server names. https://nginx.org/en/docs/http/server_names.html
- Nginx. How nginx processes a request. https://nginx.org/en/docs/http/request_processing.html
- Nginx/F5. NGINX Reverse Proxy. https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/