CentOS Docker 使用 DOCKER-USER + iptables 限制容器端口访问方案
1. 适用场景
本文适用于以下场景:
- CentOS 服务器使用 Docker 部署服务
- Docker 容器通过
-p或ports暴露端口 - 需要限制容器暴露端口只允许指定服务器或指定 IP 访问
- 不希望关闭 Docker 自动管理 iptables
- 不希望影响 Docker NAT、端口映射、容器访问公网
- 需要服务器重启后规则仍然生效
推荐方案:
iptables-services
+
Docker 默认 iptables 管理
+
DOCKER-USER 链做访问控制2. 为什么使用 DOCKER-USER
Docker 启动容器并映射端口时,会自动写入 iptables 规则,例如:
nat表filter表DOCKER链DOCKER-USER链
其中:
DOCKER 链:Docker 自动维护,不建议手工修改
DOCKER-USER 链:Docker 预留给用户自定义访问控制Docker 的转发流量大致会经过:
FORWARD
↓
DOCKER-USER
↓
DOCKER
↓
容器因此,在 DOCKER-USER 链中写规则,可以在 Docker 自动放行容器端口之前,先做访问控制。
3. 重要原则
3.1 不建议关闭 Docker iptables
不要在 /etc/docker/daemon.json 中配置:
{
"iptables": false
}否则可能导致:
- Docker NAT 失效
- 容器端口映射异常
- 容器访问外网异常
- Docker bridge 网络异常
- Docker Compose 网络异常
推荐保持 Docker 默认配置:
{
"iptables": true
}或者不配置该项。
3.2 不要直接修改 DOCKER 链
不建议直接修改:
DOCKER因为该链由 Docker 自动维护,Docker 重启、容器启动或停止时都可能改写。
应使用:
DOCKER-USER3.3 不要只写 INPUT 链
Docker 暴露端口的访问流量很多情况下走的是:
FORWARD而不是:
INPUT所以只写 INPUT 链经常无法限制 Docker 映射端口。
3.4 DOCKER-USER 不只影响入站
DOCKER-USER 作用于 FORWARD 链,因此它不仅影响外部访问容器,也会影响容器访问公网。
容器访问公网路径大致是:
容器
↓
docker0 / br-xxxx
↓
FORWARD
↓
DOCKER-USER
↓
外网所以规则里必须先放行 Docker bridge 的出站流量,否则会出现:
宿主机可以访问公网 IP 和端口
但容器里面访问不通4. 推荐启动顺序
推荐顺序:
1. 启动 iptables 服务
2. 启动 Docker 服务
3. Docker 自动创建 DOCKER / DOCKER-USER 链
4. 写入 DOCKER-USER 访问控制规则
5. 保存 iptables 规则原因:
DOCKER-USER 链通常由 Docker 创建
Docker 未启动前,该链可能不存在5. 安装和初始化
5.1 安装 iptables-services
CentOS 7:
yum install -y iptables-servicesCentOS 8:
dnf install -y iptables-services5.2 停止 firewalld
如果决定使用 iptables-services 管理规则,建议关闭 firewalld:
systemctl stop firewalld
systemctl disable firewalld查看状态:
systemctl status firewalld5.3 启动 iptables
systemctl enable iptables
systemctl start iptables查看状态:
systemctl status iptables5.4 启动 Docker
systemctl enable docker
systemctl start docker查看状态:
systemctl status docker5.5 确认 DOCKER-USER 存在
iptables -L -n应能看到类似内容:
Chain DOCKER
Chain DOCKER-USER也可以单独查看:
iptables -L DOCKER-USER -n --line-numbers6. 示例需求
假设服务器上有 Docker 容器暴露端口:
8080要求:
允许 1.1.1.1 访问 8080
允许 2.2.2.2 访问 8080
拒绝其他 IP 访问 8080
允许容器正常访问公网7. 推荐规则模板
7.1 清理旧的 DOCKER-USER 自定义规则
如果之前 DOCKER-USER 规则较乱,可以先清空该链:
iptables -F DOCKER-USER如果提示链不存在,说明 Docker 可能未启动,先执行:
systemctl restart docker然后再次检查:
iptables -L DOCKER-USER -n --line-numbers7.2 添加规则:放行容器出站
默认 Docker bridge:
iptables -I DOCKER-USER 1 -i docker0 -j ACCEPTDocker Compose 或自定义 bridge 网络通常是 br-xxxx,建议放行:
iptables -I DOCKER-USER 2 -i br+ -j ACCEPT这两条用于保证容器可以正常访问外网,例如:
- DNS
- HTTP / HTTPS
- yum / apt
- curl
- API 调用
- 连接外部数据库或服务
7.3 添加规则:放行已建立连接
iptables -I DOCKER-USER 3 \
-m state --state RELATED,ESTABLISHED \
-j ACCEPT作用:
允许已经建立的连接继续返回数据7.4 添加规则:放行白名单 IP
允许 1.1.1.1 访问容器暴露的 8080:
iptables -I DOCKER-USER 4 \
-s 1.1.1.1 \
-p tcp --dport 8080 \
-j ACCEPT允许 2.2.2.2 访问容器暴露的 8080:
iptables -I DOCKER-USER 5 \
-s 2.2.2.2 \
-p tcp --dport 8080 \
-j ACCEPT7.5 添加规则:拒绝其他 IP
iptables -A DOCKER-USER \
-p tcp --dport 8080 \
-j DROP7.6 添加默认 RETURN
建议在链末尾保留:
iptables -A DOCKER-USER -j RETURN说明:
未被本链拦截的流量返回给 Docker 后续链处理如果 DOCKER-USER 链中原本已有 RETURN,无需重复添加。
8. 完整命令示例
以下命令可按需修改白名单 IP 和端口后使用。
# 清空 DOCKER-USER 旧规则
iptables -F DOCKER-USER
# 放行 Docker 默认 bridge 出站
iptables -A DOCKER-USER -i docker0 -j ACCEPT
# 放行 Docker Compose / 自定义 bridge 出站
iptables -A DOCKER-USER -i br+ -j ACCEPT
# 放行已建立连接
iptables -A DOCKER-USER \
-m state --state RELATED,ESTABLISHED \
-j ACCEPT
# 放行白名单 IP 访问 8080
iptables -A DOCKER-USER \
-s 1.1.1.1 \
-p tcp --dport 8080 \
-j ACCEPT
iptables -A DOCKER-USER \
-s 2.2.2.2 \
-p tcp --dport 8080 \
-j ACCEPT
# 拒绝其他 IP 访问 8080
iptables -A DOCKER-USER \
-p tcp --dport 8080 \
-j DROP
# 其他流量交还 Docker 后续规则处理
iptables -A DOCKER-USER -j RETURN9. 多端口示例
如果要限制多个端口,例如:
80,443,8080只允许 1.1.1.1 和 2.2.2.2 访问:
iptables -F DOCKER-USER
iptables -A DOCKER-USER -i docker0 -j ACCEPT
iptables -A DOCKER-USER -i br+ -j ACCEPT
iptables -A DOCKER-USER \
-m state --state RELATED,ESTABLISHED \
-j ACCEPT
iptables -A DOCKER-USER \
-s 1.1.1.1 \
-p tcp \
-m multiport --dports 80,443,8080 \
-j ACCEPT
iptables -A DOCKER-USER \
-s 2.2.2.2 \
-p tcp \
-m multiport --dports 80,443,8080 \
-j ACCEPT
iptables -A DOCKER-USER \
-p tcp \
-m multiport --dports 80,443,8080 \
-j DROP
iptables -A DOCKER-USER -j RETURN10. 查看规则
查看规则顺序:
iptables -L DOCKER-USER -n --line-numbers查看规则命中计数:
iptables -L DOCKER-USER -n -v --line-numbers预期类似:
Chain DOCKER-USER
num target prot opt source destination
1 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 in docker0
2 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 in br+
3 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
4 ACCEPT tcp -- 1.1.1.1 0.0.0.0/0 tcp dpt:8080
5 ACCEPT tcp -- 2.2.2.2 0.0.0.0/0 tcp dpt:8080
6 DROP tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080
7 RETURN all -- 0.0.0.0/0 0.0.0.0/011. 保存规则
规则验证无误后保存。
CentOS 7 常用:
service iptables save或者:
iptables-save > /etc/sysconfig/iptables确认文件已写入:
cat /etc/sysconfig/iptables12. 服务器重启后是否失效
只要已经保存到:
/etc/sysconfig/iptables并且启用了 iptables 服务:
systemctl enable iptables服务器重启后会自动加载规则。
推荐重启后的顺序:
1. iptables 服务启动
2. 加载 /etc/sysconfig/iptables
3. Docker 服务启动
4. Docker 自动恢复 DOCKER / DOCKER-USER 相关链
5. DOCKER-USER 中的白名单规则继续生效如果重启后发现 DOCKER-USER 链异常,可执行:
systemctl restart docker然后检查:
iptables -L DOCKER-USER -n --line-numbers13. 清理混乱规则并重新配置
13.1 最安全方式:只清理 DOCKER-USER
推荐:
iptables -F DOCKER-USER然后重新按本文第 8 节添加规则。
这种方式不会影响 Docker 自动生成的 NAT 规则。
13.2 清理 filter 表
如果整个 filter 表规则混乱,可以先备份:
iptables-save > /root/iptables-backup-$(date +%F-%H%M%S).rules再清理 filter 表:
iptables -F
iptables -X然后重启 Docker:
systemctl restart docker再重新写入 DOCKER-USER 规则。
13.3 不建议清理 nat 表
不要轻易执行:
iptables -t nat -F
iptables -t nat -X因为 Docker 的端口映射和 MASQUERADE 依赖 nat 表。
如果已经误清理 nat 表,需要重启 Docker:
systemctl restart docker必要时重启相关容器。
14. 验证方法
14.1 验证白名单访问
在白名单服务器执行:
curl http://服务器IP:8080应可以访问。
14.2 验证非白名单访问
在非白名单服务器执行:
curl http://服务器IP:8080应无法访问或连接超时。
14.3 验证容器访问公网
进入容器:
docker exec -it 容器名 sh测试 IP 连通性:
ping 8.8.8.8测试域名解析和 HTTPS:
curl https://www.baidu.com如果宿主机能访问外网,但容器不能访问,优先检查:
iptables -L DOCKER-USER -n -v --line-numbers确认是否有以下放行规则:
-i docker0 -j ACCEPT
-i br+ -j ACCEPT15. 常见问题
15.1 宿主机能访问公网,容器不能访问公网
原因通常是 DOCKER-USER 拦截了容器出站流量。
解决:
iptables -I DOCKER-USER 1 -i docker0 -j ACCEPT
iptables -I DOCKER-USER 2 -i br+ -j ACCEPT15.2 白名单规则不生效
检查规则顺序:
iptables -L DOCKER-USER -n --line-numbers白名单 ACCEPT 必须在 DROP 前面。
15.3 Docker 端口映射失效
检查 nat 表:
iptables -t nat -L -n检查 Docker 服务:
systemctl status docker如有必要:
systemctl restart docker15.4 Docker Compose 网络访问异常
Docker Compose 通常使用 br-xxxx 网桥。
确认是否有:
iptables -A DOCKER-USER -i br+ -j ACCEPT15.5 不知道容器使用哪个网桥
查看网络接口:
ip addr常见接口:
docker0
br-xxxxxxxxxxxx也可以查看 Docker 网络:
docker network ls
docker network inspect 网络名16. 生产环境建议
16.1 最推荐
Docker 保持默认 iptables 管理
iptables-services 做持久化
DOCKER-USER 做访问控制
不要手工修改 DOCKER 链
不要关闭 Docker iptables16.2 更安全的架构
如果条件允许,不建议容器端口直接暴露公网。
更推荐:
公网
↓
Nginx / HAProxy / SLB
↓
Docker 内网服务Docker 端口可以只监听本地:
docker run -p 127.0.0.1:8080:80 nginx然后由 Nginx 做:
- IP 白名单
- TLS
- 访问日志
- 限流
- WAF
17. 最终可执行模板
请将以下内容中的 IP 和端口替换为实际值。
# 1. 确认 Docker 已启动
systemctl start docker
# 2. 清空 DOCKER-USER 旧规则
iptables -F DOCKER-USER
# 3. 放行容器出站
iptables -A DOCKER-USER -i docker0 -j ACCEPT
iptables -A DOCKER-USER -i br+ -j ACCEPT
# 4. 放行已建立连接
iptables -A DOCKER-USER \
-m state --state RELATED,ESTABLISHED \
-j ACCEPT
# 5. 放行白名单访问容器端口
iptables -A DOCKER-USER \
-s 1.1.1.1 \
-p tcp --dport 8080 \
-j ACCEPT
iptables -A DOCKER-USER \
-s 2.2.2.2 \
-p tcp --dport 8080 \
-j ACCEPT
# 6. 拒绝其他来源访问该端口
iptables -A DOCKER-USER \
-p tcp --dport 8080 \
-j DROP
# 7. 其他流量交还 Docker 处理
iptables -A DOCKER-USER -j RETURN
# 8. 查看规则
iptables -L DOCKER-USER -n -v --line-numbers
# 9. 保存规则
service iptables save18. 回滚方法
如果规则配置后出现异常,可恢复备份:
iptables-restore < /root/iptables-backup.rules或者临时清空 DOCKER-USER:
iptables -F DOCKER-USER
iptables -A DOCKER-USER -j RETURN然后重启 Docker:
systemctl restart docker19. 注意事项
- 修改前一定要备份 iptables。
- 远程操作时,谨慎执行
DROP规则,避免误封 SSH。 - Docker 主机不要随意清理 nat 表。
- Kubernetes 节点不要直接套用本文清理规则,kube-proxy、Calico、Flannel 等也依赖 iptables。
- 白名单规则必须写在 DROP 规则前面。
- 容器出站放行规则必须写在 DROP 规则前面。