Files
llm-wiki/docs/minio-firewall-investigation-report.md
2026-07-12 21:26:08 +08:00

212 lines
9.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MinIO 9000/9001 端口局域网无法访问问题排查报告
> **日期**2026-07-12
> **服务器 IP**10.68.223.254
> **涉及服务**MinIODocker 容器,1Panel 管理)
> **状态**:未完全复现,已恢复原样
---
## 1. 问题描述
用户反馈:MinIO 容器的 9000(API)和 9001(控制台)端口已在防火墙开放,但局域网无法访问。从另一台机器扫描 10.68.223.254 的 1-10000 端口,只发现 22、5230、6060 端口开放,9000 和 9001 端口显示为关闭。
## 2. 排查过程
### 2.1 检查防火墙规则
```
public zone ports:
10086/tcp 22/tcp 9000/tcp 8100/tcp 18686/tcp 3306/tcp 8088/tcp 3307/tcp 5230/tcp 8080/tcp 5180/tcp 6060/tcp 5901/tcp
```
- 9000 端口在 public zone 的 ports 列表中 ✓
- 9001 端口**不在** ports 列表中,只有一条 rich rule 限制 `11.1.1.0/24` 网段可访问
**发现**9001 端口只对 11.1.1.0/24 网段开放,其他网段无法访问。但 9000 端口已全局开放,不应该有问题。
### 2.2 检查 MinIO 配置
发现 MinIO 容器有两个关键环境变量绑定到 127.0.0.1:
```
MINIO_SERVER_URL=http://127.0.0.1:9000
MINIO_BROWSER_REDIRECT_URL=http://127.0.0.1:9001
```
**推测**:这两个变量可能导致 MinIO 在处理请求时重定向到 127.0.0.1,使局域网客户端无法访问。
### 2.3 检查 Docker 端口映射
```
docker-proxy 在监听 0.0.0.0:9000 和 0.0.0.0:9001
nat 表有 DNAT 规则:tcp dpt:9000 to:172.20.0.3:9000
```
Docker 端口映射正常,docker-proxy 也在监听。
### 2.4 检查 iptables FORWARD 链
发现 FORWARD 链末尾有 firewalld 的 REJECT 规则:
```
23 REJECT 0 -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
```
**推测**:Docker 端口映射的流量走 FORWARD 链,被末尾的 REJECT 规则拦截。虽然 firewalld 在 public zone 开放了 9000 端口,但那是 INPUT 链的规则,对 FORWARD 链无效。
### 2.5 尝试修复(操作过程中出现意外)
在尝试通过 `firewall-cmd --direct --add-rule` 向 FORWARD 链添加放行规则时:
1. 多次执行 `--direct --add-rule` 失败,报错 `iptables-restore: line 2 failed`
2. 直接编辑 `/etc/firewalld/direct.xml` 文件,导致规则不一致
3. 执行 `firewall-cmd --reload` 后,`/etc/firewalld/zones/public.xml` 被覆盖为只剩 `<masquerade/>`,所有端口和规则丢失
4. **22 端口被锁,SSH 无法连接**(用户通过 RustDesk 远程桌面仍可操作)
### 2.6 恢复防火墙配置
1.`/etc/firewalld/zones/public.xml.old` 恢复了完整的端口列表和服务
2. 在恢复的 public.xml 中添加了 `<masquerade/>`
3. 清空了 direct.xml(删除了之前添加的 FORWARD 规则)
4. 重启 firewalld,所有端口恢复正常
### 2.7 修改 MinIO 配置
从 docker-compose.yml 中删除了以下两行:
```yaml
MINIO_BROWSER_REDIRECT_URL: http://127.0.0.1:9001
MINIO_SERVER_URL: http://127.0.0.1:9000
```
重启 MinIO 容器后,局域网可以访问 9000 和 9001 端口。
## 3. 复现尝试
用户反馈:之前 MinIO 配置从未改动过,一直可以正常访问。要求复现问题。
### 3.1 尝试一:firewall-cmd --reload
**假设**firewalld reload 会清空 Docker 的 iptables 规则,导致流量无法通过 FORWARD 链。
**操作**
1. 删除手动添加的 FORWARD_direct 规则
2. 执行 `firewall-cmd --reload`
**结果**:9000 端口仍然可以访问。Docker 的 nat 表 DNAT 规则和 filter 表 FORWARD/DOCKER 链规则在 reload 后**没有被清掉**。
### 3.2 尝试二:停 Docker → reload firewalld → 启 Docker
**假设**Docker 和 firewalld 的启动顺序会影响 iptables 规则的排列位置。
**操作**
1. `sudo systemctl stop docker`
2. `sudo firewall-cmd --reload`
3. `sudo systemctl start docker`
**结果**Docker 重启后,自动用 `iptables -I`insert)将规则插入到 FORWARD 链**最顶部**,在 firewalld 的 REJECT 规则之前。9000 端口仍然可以访问。
### 3.3 尝试三:还原 MinIO 配置,只 reload firewalld
**假设**:问题是 MinIO 的 `MINIO_SERVER_URL=http://127.0.0.1:9000` 导致的。
**操作**
1. 还原 docker-compose.yml 中的 `MINIO_SERVER_URL``MINIO_BROWSER_REDIRECT_URL`
2. 重启 MinIO 容器
3. 不动防火墙,直接测试
**结果**:9000 和 9001 端口都可以正常访问。**问题没有复现。**
## 4. 猜想与分析
### 猜想一:MinIO 配置导致
`MINIO_SERVER_URL=http://127.0.0.1:9000` 会导致 MinIO 控制台在登录后重定向到 `http://127.0.0.1:9001`,局域网客户端浏览器会尝试访问自己的 9001 端口,导致访问失败。
**问题**:这只能解释浏览器访问控制台失败,不能解释端口扫描工具显示 9000 端口关闭。而且还原配置后也能正常访问,无法复现。
### 猜想二:firewalld reload 清空了 Docker 规则
`firewall-cmd --reload` 会重建 iptables 规则,可能清空 Docker 插入的 FORWARD 和 nat 规则。
**问题**:实际测试发现 `firewall-cmd --reload` 并不会清空 Docker 的规则。Docker 的规则在 reload 后依然存在。
### 猜想三:Docker 启动时 iptables 操作失败
Docker 启动容器时需要操作 iptables 添加 DNAT 和 FORWARD 规则。如果当时 iptables 处于异常状态(比如 firewalld 正在重建规则),Docker 的 iptables 操作可能失败,导致规则没有正确添加。
**佐证**:排查过程中曾尝试 `docker restart minio`,报错:
```
Cannot restart container minio: driver failed programming external connectivity
iptables failed: iptables --wait -t nat -A DOCKER -p tcp --dport 9001 -j DNAT ...
iptables: No chain/target/match by that name.
```
这说明 nat 表的 DOCKER 链被删了,Docker 无法添加 DNAT 规则。
### 猜想四:操作导致的临时状态
排查过程中多次执行 `firewall-cmd --direct --add-rule`,每次都报错 `iptables-restore: line 2 failed`。这些失败的操作可能导致 iptables 处于不一致的状态,使 Docker 的规则部分丢失或位置异常。
**佐证**:用户最初反馈问题时,可能是在某次 firewalld 操作后出现的。而我开始排查时,由于又执行了多次 firewalld 操作,可能加剧了规则的不一致。
### 猜想五:Docker 和 firewalld 的启动顺序竞争
如果 firewalld 和 Docker 同时启动,可能出现竞争条件:
- Docker 先启动,添加了 iptables 规则
- firewalld 后启动,重建 iptables 规则,清掉了 Docker 的规则
- Docker 没有感知到规则被清掉,不会自动恢复
**问题**:这个猜想很难复现,因为需要精确控制两个服务的启动时序。
## 5. 未查明的原因
综合以上分析,**真正的原因未能确定**。可能的原因包括:
1. **Docker 和 firewalld 的启动顺序竞争**:某次系统重启后,firewalld 在 Docker 之后启动,清掉了 Docker 的 iptables 规则,而 Docker 没有自动恢复
2. **iptables 异常状态**:某次 firewalld 操作(如 reload 或 direct 规则添加失败)导致 iptables 处于不一致状态,Docker 的规则部分丢失
3. **MinIO 配置叠加效应**`MINIO_SERVER_URL=http://127.0.0.1:9000` 在某些情况下可能导致 MinIO 拒绝非本地请求,使端口扫描工具误判端口关闭
4. **临时网络问题**:可能是当时的临时网络或路由问题,后续自然恢复
## 6. 最终状态
### 防火墙
- public zone:所有端口已恢复(22、9000、9001、8080、5180、6060、5901 等)
- 服务:ssh、mdns、dhcpv6-client
- masquerade:已开启
- rich rules11.1.1.0/24 的 137-139、445、9001 规则已恢复
- direct.xml:已清空(不需要额外的 FORWARD 规则)
### MinIO
- 配置已**还原为原始状态**`MINIO_SERVER_URL=http://127.0.0.1:9000`
- 容器正常运行
- 9000 和 9001 端口可从局域网正常访问
### Docker
- iptables 规则正常
- nat 表 DOCKER 链有 DNAT 规则
- filter 表 FORWARD 链有 Docker 的 ACCEPT 规则在顶部
- filter 表 DOCKER 链有 9000/9001 的 ACCEPT 规则
## 7. 经验教训
1. **不要反复用 `firewall-cmd --direct` 写规则**:该命令在 firewalld 0.6.6 上容易失败,导致 iptables-restore 报错,可能破坏现有规则
2. **修改防火墙前先备份**`/etc/firewalld/zones/*.xml` 文件在 reload 时可能被覆盖,应先备份
3. **不要同时直接编辑 XML 文件和用命令操作**:这会导致 firewalld 内部状态和文件不一致
4. **Docker 和 firewalld 有潜在的 iptables 冲突**:虽然正常情况下不会出问题,但在异常操作或启动顺序竞争时可能出现问题
5. **排查问题前先确认当前状态**:不要在问题已经自然恢复后再尝试复现,因为临时状态可能已经消失
## 8. 后续建议
1. 如果问题再次出现,**先不要做任何 firewalld 操作**,立即检查:
- `iptables -t nat -L DOCKER -n`(检查 DNAT 规则是否存在)
- `iptables -L FORWARD -n --line-numbers`(检查 Docker 规则位置)
- `docker logs minio`(检查容器日志)
2. 如果 Docker 规则丢失,执行 `sudo systemctl restart docker` 即可恢复
3. 考虑将 firewalld 的启动顺序设置为在 Docker 之后,避免竞争条件
4. 考虑在 `/etc/firewalld/direct.xml` 中预先配置 Docker 相关的 FORWARD 规则作为兜底(但当前测试表明不需要)