# MinIO 9000/9001 端口局域网无法访问问题排查报告
> **日期**:2026-07-12
> **服务器 IP**:10.68.223.254
> **涉及服务**:MinIO(Docker 容器,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` 被覆盖为只剩 ``,所有端口和规则丢失
4. **22 端口被锁,SSH 无法连接**(用户通过 RustDesk 远程桌面仍可操作)
### 2.6 恢复防火墙配置
1. 从 `/etc/firewalld/zones/public.xml.old` 恢复了完整的端口列表和服务
2. 在恢复的 public.xml 中添加了 ``
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 rules:11.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 规则作为兜底(但当前测试表明不需要)