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

9.2 KiB
Raw Permalink Blame History

MinIO 9000/9001 端口局域网无法访问问题排查报告

日期2026-07-12 服务器 IP10.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 中删除了以下两行:

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 -Iinsert)将规则插入到 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_URLMINIO_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 规则作为兜底(但当前测试表明不需要)