ALB 日志里的 host 为什么不是负载均衡公网 IP
ALB 日志里的 host 为什么不是负载均衡公网 IP
线上排查 Web 扫描日志时,经常会看到一个容易误判的现象:请求明明是从负载均衡公网 IP 进来的,但 ALB 或 Nginx 日志里的 host 却是另一个陌生 IP。
结论先说清楚:日志里的 host 记录的是 HTTP 请求头里的 Host,不是客户端真正连接的公网入口 IP。 客户端可以连接 203.0.113.10:80,同时在 HTTP 层写 Host: 192.0.2.157:8826。如果 ALB 没有针对 Host 做拒绝规则,这个请求会走默认转发规则,后端 Nginx 也会把这个 Host 原样记下来。
本文用一个脱敏例子说明这个过程。
环境
| 项目 | 示例 |
|---|---|
| 云产品 | 阿里云 ALB 七层负载均衡 |
| 日志 | ALB 访问日志投递到 SLS,后端 Nginx access log 也投递到 SLS |
| 协议 | HTTP/1.1 |
| 公网入口 | 203.0.113.10:80,示例地址 |
| 客户端 IP | 198.51.100.23,示例地址 |
| 客户端自定义 Host | 192.0.2.157:8826,示例地址 |
| 后端 Nginx | 10.0.1.11:80,示例地址 |
文中的 IP 使用 RFC 5737 文档地址段和私网地址做脱敏示例,不对应真实生产资源。
请求链路

动态看一遍就是这样:

链路可以拆成五步:
- 客户端 TCP 连接的是 ALB 公网入口
203.0.113.10:80。 - 客户端在 HTTP 请求里带了
Host: 192.0.2.157:8826。 - ALB 收到请求,访问日志记录
host=192.0.2.157、http_host=192.0.2.157:8826。 - 如果没有更精确的 Host 路由命中,请求走默认规则转发到后端。
- 后端 Nginx 继续把请求头里的 Host 记到 access log。
所以不要把 host 当成“入口 IP”。入口要看 ALB 自己的字段,比如 app_lb_id、vip_addr、slb_vport,以及云资产里这个 vip_addr 对应的公网 EIP。
模拟一次这种请求
用 curl 就可以复现。关键点是:URL 里写实际访问的入口 IP,Header 里写另一个 Host。
curl -i \
-H 'Host: 192.0.2.157:8826' \
-H 'User-Agent: host-header-probe/1.0' \
http://203.0.113.10/__host_header_probe
这个请求的含义不是“访问 192.0.2.157”,而是:
TCP 连接: 203.0.113.10:80
HTTP Host: 192.0.2.157:8826
URI: /__host_header_probe
如果后端没有这个路径,一般会返回 404。这不影响验证,因为我们要看的不是业务响应,而是 ALB 和 Nginx 日志怎样记录字段。
ALB 日志里会看到什么
ALB 七层访问日志里常见字段类似这样:
app_lb_id: alb-xxxxxxxx
alb_rule_id: rule-default-lsn-xxxxxxxx
client_ip: 198.51.100.23
client_port: 57198
host: 192.0.2.157
http_host: 192.0.2.157:8826
request_method: GET
request_uri: /__host_header_probe
scheme: http
slb_vport: 80
vip_addr: 10.0.0.10
upstream_addr: 10.0.1.11:80
status: 404
http_user_agent: host-header-probe/1.0
几个字段要分开看:
| 字段 | 含义 |
|---|---|
client_ip |
连接到 ALB 的客户端 IP |
host / http_host |
HTTP 请求头里的 Host,由客户端传入 |
app_lb_id |
命中的 ALB 实例 |
alb_rule_id |
命中的 ALB 转发规则,rule-default-* 表示默认规则 |
slb_vport |
ALB 监听端口 |
vip_addr |
ALB 的内网 VIP |
upstream_addr |
ALB 转发到的后端地址 |
真正判断“从哪个负载均衡入口进来”,不要看 host,要看:
app_lb_id + vip_addr + slb_vport
再结合云资产里 ALB 的 ZoneMappings / LoadBalancerAddresses,把 vip_addr 映射回公网 EIP。
为什么会走默认规则
示例里的 alb_rule_id 是:
rule-default-lsn-xxxxxxxx
这说明没有命中更具体的 Host / Path 转发规则,ALB 用监听器默认动作把请求转发到了默认后端。
这类请求常见于扫描器:
GET /.env HTTP/1.1
Host: 192.0.2.157:8826
User-Agent: go-scanner/0.1
扫描器不一定知道真实域名。它可能随机拿一个 IP 当 Host,也可能从历史资产库里取一个值,然后探测 /.env、/.git/config、/.aws/credentials 之类敏感路径。
只要公网入口接受这个请求,并且默认规则能转发到后端,后端日志就会出现这个“看起来不是自己资产”的 Host。
Nginx 日志为什么也会记录这个 Host
Nginx 看到的是 ALB 转发过来的 HTTP 请求。请求头里的 Host 没变,所以 Nginx access log 里如果记录 $host 或 $http_host,就会继续看到:
host: 192.0.2.157
http_host: 192.0.2.157:8826
同时,Nginx 侧通常还能看到这些字段:
remote_addr: 10.0.0.126
server_addr: 10.0.1.11
http_x_forwarded_for: 198.51.100.23
upstream_addr: 127.0.0.1:8080
这里的含义是:
| 字段 | 含义 |
|---|---|
remote_addr |
Nginx 看到的上一跳,一般是 ALB 本地转发地址 |
server_addr |
处理请求的 Nginx 机器地址 |
http_x_forwarded_for |
ALB 传给后端的真实客户端 IP |
upstream_addr |
Nginx 再转发到的业务进程 |
所以 Nginx 日志可以反推链路,但如果要精确到 ALB 公网入口,最好查 ALB 原始访问日志。
SLS 查询方法
先取一条样例日志,确认字段名:
aliyun sls get-logs-v2 \
--project=<project> \
--logstore=<logstore> \
--endpoint=<region>.log.aliyuncs.com \
--from <start_ts> \
--to <end_ts> \
--query '*' \
--line 1 \
--format-output json
确认字段后,再按 Host 和 URI 查:
aliyun sls get-logs-v2 \
--project=<project> \
--logstore=<logstore> \
--endpoint=<region>.log.aliyuncs.com \
--from <start_ts> \
--to <end_ts> \
--query 'http_host: 192.0.2.157 and request_uri: "/.env"' \
--line 20 \
--format-output json
如果想按真实客户端 IP 查,ALB 日志里优先看 client_ip:
aliyun sls get-logs-v2 \
--project=<project> \
--logstore=<logstore> \
--endpoint=<region>.log.aliyuncs.com \
--from <start_ts> \
--to <end_ts> \
--query 'client_ip: 198.51.100.23 and request_uri: "/.env"' \
--line 20 \
--format-output json
注意:ALB 日志里的 http_x_forwarded_for 可能是 -,因为客户端直连 ALB 时本来没有带这个头。到 Nginx 后,ALB 可能会把 client_ip 写入 X-Forwarded-For,所以 Nginx 日志里又能看到 http_x_forwarded_for=198.51.100.23。
排查时怎么判断入口
建议按这个顺序看:
- 从 Nginx 日志拿到
remote_addr、server_addr、http_x_forwarded_for、host、request_uri。 - 用同一时间窗口查 ALB SLS。
- 在 ALB 日志里找到同一条
request_uri、host/http_host、client_ip。 - 看
app_lb_id确认负载均衡实例。 - 看
vip_addr和slb_vport确认入口监听。 - 用 ALB 资产里的
ZoneMappings / LoadBalancerAddresses把vip_addr映射到公网 EIP。 - 看
upstream_addr确认后端机器。
一个完整链路最终会长这样:
198.51.100.23
-> 203.0.113.10:80
-> ALB vip 10.0.0.10
-> 10.0.1.11:80 Nginx
-> 127.0.0.1:8080
而日志里的 Host 可能仍然是:
192.0.2.157:8826
这两个并不冲突。
如何减少这类噪音
如果业务不需要接受任意 Host,可以考虑做几件事:
- 在 ALB 上增加明确的 Host 转发规则,只让真实域名进入业务后端。
- 默认规则转发到一个固定的 404 后端,不进入主业务服务。
- 在 Nginx 默认
server里拒绝未知 Host。 - WAF / 安全事件系统里把“访问入口”和“HTTP Host”拆成两个字段,避免把 Host 误当成域名资产。
- 对
/.env、/.git/config等敏感路径做单独统计,避免一次扫描就误判成真实业务异常。
Nginx 默认拒绝未知 Host 的思路大概是:
server {
listen 80 default_server;
server_name _;
return 444;
}
实际生产环境要先确认健康检查、默认域名、回源链路和 CDN 行为,不要直接复制上线。
快速参考
字段速查:
| 要判断的问题 | 优先看哪个字段 |
|---|---|
| 客户端从哪里来 | ALB client_ip,Nginx http_x_forwarded_for |
| 客户端写了什么 Host | ALB host/http_host,Nginx $host/$http_host |
| 命中哪个 ALB | app_lb_id |
| 命中哪个入口监听 | vip_addr + slb_vport |
| 是否走默认规则 | alb_rule_id 是否是 rule-default-* |
| 转发到哪个后端 | ALB upstream_addr,Nginx server_addr |
模拟命令:
curl -i \
-H 'Host: 192.0.2.157:8826' \
-H 'User-Agent: host-header-probe/1.0' \
http://203.0.113.10/__host_header_probe
核心结论:
URL 里的 IP = 实际 TCP 连接入口
Host 头 = HTTP 层客户端声明的目标主机
ALB/Nginx 日志里的 host = Host 头,不等于入口 IP
看到陌生 IP 出现在 host 字段里,先不要判断为“域名展示错了”或“资产漏同步”。先查 ALB 原始日志里的 app_lb_id、vip_addr、client_ip、upstream_addr,再还原真实入口链路。

浙公网安备 33010602011771号