发布版说明
- 已对真实域名、公网 IP、具体云厂商指代做脱敏处理。
- 原始学习笔记未改动,这一版用于公开发布。
专题:Nginx 多站点与反向代理
这篇是把前面几次实战里反复碰到的 Nginx,单独拎出来讲透。
目标不是背配置,而是搞明白:
- 一个请求到了服务器以后,Nginx 到底怎么决定交给谁
- 为什么同一台机器可以挂很多站点
- 什么场景该反代到容器,什么场景直接给静态文件
- 为什么明明容器活着,浏览器却还是打不开
一、先把整体图看明白
前面我们已经实际搭过这几种情况:
status.example.com->Uptime Kumafiles.example.com->FileBrowserblog.example.com->WordPress
它们表面上是三个网站,底层其实可以共用一台服务器、一个 Nginx:
浏览器
->
域名
->
公网 IP
->
Nginx 80/443
->
根据 Host 头匹配不同站点
->
转发给不同应用
关键点就一句:
不是靠端口区分站点,而是靠域名区分站点。
也就是请求里这个 Host:
status.example.comfiles.example.comblog.example.com
Nginx 看见不同的 Host,就把请求送进不同的 server 块。
二、server 块到底是什么
可以把一个 server 块理解成:
“某个域名对应的一份站点接待规则”
最基本长这样:
server {
listen 80;
server_name status.example.com;
location / {
proxy_pass http://127.0.0.1:3001;
}
}
这里面最关键的 3 个点:
2.1 listen
表示这个站点监听哪个端口。
常见是:
listen 80;表示 HTTPlisten 443 ssl;表示 HTTPS
注意:
同一台机器可以有很多 server 都写 listen 80;
这不冲突,因为它们不是靠端口继续区分,而是靠 server_name 区分。
2.2 server_name
表示这份配置是给哪个域名用的。
比如:
server_name status.example.com;
它的意思不是“DNS 在这里配置”,而是:
当请求到达 Nginx,并且
Host头等于这个域名时,这个站点配置来处理。
所以 DNS 和 Nginx 是两层事:
- DNS 负责把域名解析到服务器 IP
- Nginx 负责接到请求后按域名分流
2.3 location
表示:
路径怎么处理
最常见的就是:
location / {
proxy_pass http://127.0.0.1:3001;
}
意思是:
- 只要访问这个站点的任意路径
- 都转发给后端应用
以后你还会遇到:
location /api/location /static/location /.well-known/acme-challenge/
这就是“同一个站点里,不同路径不同处理规则”。
三、Nginx 怎么判断一个请求该进哪个站点
这一步必须彻底搞懂,不然后面会一直被默认页、串站、证书失败折磨。
3.1 请求到达 Nginx 时,先按端口分一层
比如:
- 请求到
80 - 或请求到
443
Nginx 先找所有监听这个端口的 server
3.2 再按 Host 头匹配 server_name
比如浏览器请求:
http://status.example.com/
它会带上:
Host: status.example.com
于是 Nginx 去找:
- 哪个
server同时监听了80 - 且
server_name匹配status.example.com
找到了,就交给它。
3.3 如果没匹配上,会掉进“默认站点”
这就是我们前面碰到的经典坑:
明明域名已经解析到服务器了,结果访问出来是:
- Ubuntu 默认 Nginx 欢迎页
- 或别的站点页面
原因通常不是应用挂了,而是:
这个请求没有被你想要的 server 块接住。
常见原因:
server_name写错了- 配置文件没启用
- 改完没 reload
- 默认站点还在抢请求
这也是为什么这个命令特别重要:
curl -I -H "Host: status.example.com" "http://127.0.0.1"
它测的是:
- 不走公网
- 不依赖 DNS
- 直接测试 Nginx 能不能按
Host匹配到正确站点
如果这一步都不对,就不要去怀疑容器和证书,先把 Nginx 匹配修好。
四、反向代理到底在干什么
反向代理不是一个玄学词,本质上就是:
浏览器访问的是 Nginx,但 Nginx 再代你去访问真正的应用。
以前面 Uptime Kuma 为例:
浏览器
-> http://status.example.com
-> Nginx
-> http://127.0.0.1:3001
-> Uptime Kuma
这时候浏览器根本不知道 3001 的存在。
它只知道自己在访问:
status.example.com
这样做的好处很大:
- 应用可以只绑定本机端口,不直接暴露公网
- HTTPS 统一由 Nginx 处理
- 多个应用可以共用 80/443
- 将来换后端端口,前端域名不变
这就是为什么我们前面一直坚持:
ports:
- "127.0.0.1:3001:3001"
而不是直接把应用暴露成公网 3001
五、静态站点和反代站点有什么区别
这两个概念很容易混。
5.1 静态站点
比如一个纯 HTML 页面:
server {
listen 80;
server_name demo.example.com;
root /var/www/demo;
index index.html;
}
这里 Nginx 自己就能把文件读出来返回给浏览器。
这叫:
Nginx 直接提供静态文件。
5.2 反代站点
比如 FileBrowser:
server {
listen 80;
server_name files.example.com;
location / {
proxy_pass http://127.0.0.1:8081;
}
}
这里真正返回页面的不是 Nginx,而是后面的应用。
Nginx 只是中转。
所以:
- 返回 404,不一定是 Nginx 的 404,也可能是后端应用自己的 404
- 返回 302,也可能是后端应用自己的跳转
这就是前面你碰到 curl -I http://127.0.0.1:8081 返回 404,但直接拉 / 却能看到 HTML 的原因:
你测到的是应用自己的响应,不是 Nginx 配错了。
六、为什么同一台机器能挂很多应用
因为站点入口统一由 Nginx 承担,而后端应用都只监听本机不同端口。
比如:
status.example.com -> 127.0.0.1:3001
files.example.com -> 127.0.0.1:8081
blog.example.com -> 127.0.0.1:8082
这时候对外看:
- 都是 80/443
对内看:
- 每个应用各守自己的本机端口
这就是部署多站点最常见的骨架。
七、你前面实战里真正踩到的几个关键坑
7.1 域名能解析,不代表站点一定对
比如:
dig +short "status.example.com"
返回了服务器 IP,只能证明:
- DNS 这一层通了
不能证明:
- Nginx 站点配置正确
- 容器活着
- HTTPS 正常
7.2 本机反代通,不代表公网一定通
前面最典型的问题就是:
- 本机
curl已经能访问 - 证书、本地 443、Nginx 也都正常
- 但外网访问 HTTPS 超时
最后发现不是 Nginx,而是:
云厂商安全组没放行 443
这件事非常重要,因为它说明网络是分层的:
- 应用层
- Nginx 层
- Linux 防火墙层
- 云厂商安全组层
任何一层拦住,外面都访问不到。
7.3 curl -I 和浏览器看到的不是一回事
比如:
curl -I "http://status.example.com"
你看到的是:
302 Found
Location: /dashboard
这其实是正常的。
因为很多应用首页本来就会跳转。
所以看到 302 不要第一反应就觉得坏了,继续测:
curl -I "http://status.example.com/dashboard"
如果这里是 200,那反而说明链路已经基本通了。
7.4 ACME 挑战路径被站点规则吞了
前面证书申请失败时,错误信息里最核心的一句是:
访问 /.well-known/acme-challenge/... 时,拿到的不是挑战文件,而是你站点自己的 HTML。
这说明:
- Certbot 把挑战文件写到了某个 webroot
- 但 Nginx 没有优先把这个路径映射到挑战目录
- 请求被其他
location /或静态页规则接走了
这也是为什么申请证书时,HTTP 站点不能只想着“首页能打开就行”。
还要保证:
/.well-known/acme-challenge/
这条路径返回的是 challenge 文件本身。
八、以后判断一个站点问题,按什么顺序查
这是现在最应该固定下来的排障顺序。
第 1 步:先查 DNS
dig +short "status.example.com"
看域名是不是已经指向你的服务器 IP。
第 2 步:查本机应用是不是活着
比如:
curl -I "http://127.0.0.1:3001"
curl -I "http://127.0.0.1:8081"
curl -I "http://127.0.0.1:8082"
如果这一步不通,先别看 Nginx。
第 3 步:查 Nginx 是否能按域名接住请求
curl -I -H "Host: status.example.com" "http://127.0.0.1"
如果这里不对,问题多半在:
server_name- 站点没启用
- 默认站点
- 没 reload
第 4 步:查 Nginx 配置有没有语法错
sudo nginx -t
sudo systemctl reload nginx
别改完配置不验证,那个最容易把自己绕晕。
第 5 步:查端口监听
sudo ss -lntp | grep -E ':80|:443|:3001|:8081|:8082'
看看到底是谁在监听:
- Nginx 是否监听了
80/443 - 应用是否监听了它自己的本机端口
第 6 步:查公网链路
如果本机都正常,但公网不通,就查:
ufw- 云厂商安全组
必要时可以这样测本机 HTTPS:
curl -vkI --resolve "status.example.com:443:127.0.0.1" "https://status.example.com"
这个命令的意义是:
- 强行把域名解析到本机
127.0.0.1 - 直接测试“本机上的 HTTPS 站点”本身有没有问题
如果这一步通,但公网还是超时,那就基本不是 Nginx 配置问题了。
九、一个最小可用的多站点脑图
现在可以把你的服务器理解成这样:
203.0.113.10
->
Nginx 80/443
->
按域名分流
->
status.example.com -> 127.0.0.1:3001 -> Uptime Kuma
files.example.com -> 127.0.0.1:8081 -> FileBrowser
blog.example.com -> 127.0.0.1:8082 -> WordPress
只要这个结构脑子里清楚了,以后你再上:
MinIONextcloudGiteaVaultwardenPlausible
本质都还是同一个套路。
变化只在:
- 后端应用监听哪个端口
- 它是否需要数据库
- 它的站点路径和头部是否有特殊要求
十、这一课学完后,你应该真正掌握的东西
不是会背某份配置,而是知道:
server块是在按域名接请求server_name不对,站点就接不住- 默认页出现,大概率不是应用挂了,而是站点匹配错了
proxy_pass是把请求转发给后端应用- 同一台机器挂多个站点,核心不是多开公网端口,而是域名分流
- 本机通、公网不通,要想到安全组和防火墙
- 证书申请失败,常常不是证书本身有问题,而是挑战路径没被正确接住
十一、下一步最适合继续学什么
下一课建议接:
HTTPS 与 Let’s Encrypt
因为现在你已经知道:
- Nginx 怎么按域名接请求
- 反代怎么把流量送给后端
下一步就该把这件事彻底吃透:
- 证书申请到底依赖什么条件
HTTP-01挑战到底在验证什么- 为什么“本机能开网页”不等于“证书一定能签下来”
- 证书签发、续期、443 放行之间到底是什么关系
这一课接上去,会非常顺。

















暂无评论内容