1. 背景:为什么要封 8848 / 4243?
在内网环境里,我们经常会遇到这种情况:
-
Nacos(8848) 只想给本机 Java 服务用,不希望其他机器(B/C/D...)也能访问
-
Docker Remote API(4243) 如果被开放,风险非常高(相当于别人可以远程控制你的 Docker)
所以目标非常明确:
✅ 4243:彻底封死
✅ 8848:只允许本机访问(localhost),其他机器一律拒绝
✅ 重启机器后规则仍然生效(不靠手工敲命令)
2. 先确认:8848 是宿主机服务还是 Docker 暴露出来的?
先看 8848 到底是谁在监听:
netstat -ntlp | grep 8848
你可能会看到类似输出:
tcp6 0 0 :::8848 :::* LISTEN 2710/docker-proxy
这代表:
-
8848 是 Docker 容器映射出来的端口
-
docker-proxy在宿主机监听 8848
3. 为什么你封了 INPUT 还是能访问?
很多人第一反应是封 INPUT:
iptables -I INPUT -p tcp --dport 8848 -j DROP
但是在 Docker 场景下,有时候会出现:
规则加了,但其他机器还是能访问 8848
原因是:
-
Docker 会创建自己的链路(FORWARD / DOCKER / DOCKER-USER)
-
端口映射的流量可能会走转发链路,不一定完全依赖 INPUT
所以更稳的做法是:
✅ INPUT 负责控制宿主机端口访问
✅ DOCKER-USER 负责控制容器转发访问(防 Docker 绕过)
4. 最推荐方案:写 systemd 服务,开机自动生效
这里我用 systemd oneshot 服务 来实现:
-
开机自动插入 iptables 规则
-
不依赖
iptables-save -
内网机器也能稳定落地
5. 一键写入配置(可直接复制执行)
⚠️ 下面这一段你可以直接复制执行,它会创建规则服务文件:
cat > /etc/systemd/system/iptables-local.service <<'EOF'
[Unit]
Description=Local iptables rules (Nacos localhost only)
After=network.target docker.service
Requires=docker.service
[Service]
Type=oneshot
# ===============================
# 1. dockerd API:彻底封死
# ===============================
ExecStart=/usr/sbin/iptables -I INPUT -p tcp --dport 4243 -j DROP
ExecStart=/usr/sbin/ip6tables -I INPUT -p tcp --dport 4243 -j DROP
# ===============================
# 2. nacos 8848:只允许本机
# ===============================
# IPv4
ExecStart=/usr/sbin/iptables -I INPUT 1 -i lo -p tcp --dport 8848 -j ACCEPT
ExecStart=/usr/sbin/iptables -I INPUT 2 -p tcp --dport 8848 -j DROP
# IPv6
ExecStart=/usr/sbin/ip6tables -I INPUT 1 -i lo -p tcp --dport 8848 -j ACCEPT
ExecStart=/usr/sbin/ip6tables -I INPUT 2 -p tcp --dport 8848 -j DROP
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
6. 让服务生效(立即执行 + 开机自启)
执行下面命令:
systemctl daemon-reload
systemctl enable iptables-local.service --now
systemctl status iptables-local.service
如果你看到类似:
Active: active (exited)
说明规则已经插入成功。
7. 验证规则是否真的生效
7.1 检查 4243 是否被封死
iptables -nvL INPUT --line-numbers | grep 4243
如果出现 DROP 就说明 OK。
7.2 检查 8848 是否只允许本机访问
iptables -nvL INPUT --line-numbers | grep 8848
你应该能看到类似两条规则(顺序很关键):
-
lo 放行
-
其他全部 DROP
7.3 实际测试(最重要)
在 A 机器本机 执行:
curl -I http://127.0.0.1:8848
应该可以正常返回。
然后在 B/C/D 机器 执行:
curl -I http://A机器IP:8848
应该连接失败或超时(被 DROP)。
8. 注意事项:为什么要加 IPv6 规则?
你之前看到的监听是:
tcp6 :::8848
这意味着服务同时可能支持 IPv6 访问。
如果你只封 IPv4,不封 IPv6,有些环境下仍可能绕过。
所以这里我把 ip6tables 也一起加上了,避免漏网。
9. 常见问题(排坑)
Q1:服务启动失败,提示 No chain/target/match by that name
比如你之前遇到的:
ip6tables: No chain/target/match by that name.
原因通常是:
-
你去操作了
DOCKER-USER但 IPv6 的链不存在 -
或者 Docker 没启导致链还没创建
解决办法:
-
规则写 INPUT(宿主机)一般不会有这个问题
-
如果要写 DOCKER-USER,建议加
Requires=docker.service并确保 Docker 已启动
Q2:我封了 INPUT,但其他机器还是能访问 8848?
这种情况大概率是:
-
你封的是 INPUT,但端口映射流量走了 FORWARD / DOCKER 链路
-
或者你规则顺序不对(DROP 在 ACCEPT 前面)
正确思路是:
-
INPUT 控制宿主机
-
DOCKER-USER 控制容器转发(更强硬)
10. 总结
这套方案解决了两个核心问题:
-
4243(Docker Remote API):彻底封死,避免被远程控制
-
8848(Nacos):只允许本机访问,其他机器全部拒绝
并且:
✅ 不依赖外网
✅ 不依赖 iptables-save
✅ systemd 管理,重启机器仍然生效
✅ 顺序可控,规则稳定落地
