解决方案:以MySQL为例
方案 1:修改 Docker 容器的端口绑定(最简单)
将 MySQL 容器只绑定到本地地址,而不是 0.0.0.0:
# 1. 停止并删除当前 MySQL 容器(先备份数据!)
docker stop mysql
docker rm mysql
# 2. 重新运行 MySQL 容器,只绑定到 127.0.0.1
docker run -d \
--name mysql \
-p 127.0.0.1:3306:3306 \ # 关键:只绑定到本地回环地址
-e MYSQL_ROOT_PASSWORD=您的密码 \
mysql:latest
# 或者如果使用 Docker Compose,在 ports 部分修改:
# ports:
# - "127.0.0.1:3306:3306"
这样外部就无法通过 IP 访问 MySQL,但本地应用仍可连接。
方案 2:限制 Docker 容器的网络访问
创建自定义 Docker 网络并限制访问:
# 1. 创建一个自定义网络
docker network create --subnet=172.20.0.0/16 internal_network
# 2. 停止并重新运行容器,使用此网络
docker stop mysql
docker rm mysql
docker run -d \
--name mysql \
--network internal_network \
-p 127.0.0.1:3306:3306 \
-e MYSQL_ROOT_PASSWORD=您的密码 \
mysql:latest
方案 3:在 UFW 中阻止 Docker 的 3306 端口
# 1. 查看当前的 UFW 规则编号
sudo ufw status numbered
# 2. 在 DOCKER-USER 链中添加规则(这是 Docker 推荐的方法)
sudo iptables -I DOCKER-USER 1 -p tcp --dport 3306 -j DROP
# 3. 保存规则(如果需要持久化)
# 对于 Debian 12,使用 netfilter-persistent
sudo apt install iptables-persistent -y
sudo netfilter-persistent save
# 或者保存到特定文件
sudo sh -c "iptables-save > /etc/iptables/rules.v4"
方案 4:配置 Docker 不操作 iptables
警告:这会影响所有 Docker 容器的网络功能!
# 1. 创建或编辑 Docker 配置文件
sudo nano /etc/docker/daemon.json
# 2. 添加以下内容
{
"iptables": false
}
# 3. 重启 Docker
sudo systemctl restart docker
# 4. 重新创建 MySQL 容器
docker stop mysql
docker rm mysql
docker run -d --name mysql -p 127.0.0.1:3306:3306 -e MYSQL_ROOT_PASSWORD=您的密码 mysql:latest
方案 5:使用 docker-ufw-wrapper(推荐)
这是一个专门解决 Docker 与 UFW 冲突的工具:
# 安装
wget https://raw.githubusercontent.com/chaifeng/ufw-docker/master/ufw-docker
sudo mv ufw-docker /usr/local/bin/
sudo chmod +x /usr/local/bin/ufw-docker
# 安装到系统
sudo ufw-docker install
# 修复 UFW 规则
sudo ufw-docker fix
# 然后重新创建容器
方案 6:通过 CloudCone 控制面板限制
登录 CloudCone 控制面板,在防火墙/安全组中拒绝 3306 端口。
推荐的解决步骤:
-
首先尝试方案 1(修改端口绑定):
# 备份 MySQL 数据 docker exec mysql sh -c 'exec mysqldump --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' > backup.sql # 停止并删除容器 docker stop mysql && docker rm mysql # 重新运行,只绑定到 127.0.0.1 docker run -d \ --name mysql \ -p 127.0.0.1:3306:3306 \ -e MYSQL_ROOT_PASSWORD=您的密码 \ -v mysql_data:/var/lib/mysql \ mysql:latest -
验证是否生效:
# 查看容器端口绑定 docker ps --format "table {{.Names}}\t{{.Ports}}" # 应该显示:127.0.0.1:3306->3306/tcp # 检查是否仍能从外部访问 nc -zv 您的服务器IP 3306 # 应该显示 Connection refused # 本地应该可以连接 mysql -h 127.0.0.1 -u root -p -
如果还需要其他解决方案:
- 如果多个容器需要此配置,使用方案 5(docker-ufw-wrapper)
- 如果只需要简单解决,方案 1 足够了
长期维护建议:
-
使用 Docker Compose 管理容器,配置更清晰:
version: '3.8' services: mysql: image: mysql:latest container_name: mysql ports: - "127.0.0.1:3306:3306" # 关键:只绑定本地 environment: MYSQL_ROOT_PASSWORD: 您的密码 volumes: - mysql_data:/var/lib/mysql volumes: mysql_data: -
定期检查暴露的端口:
# 查看所有暴露的端口 docker ps --format "table {{.Names}}\t{{.Ports}}" # 查看 iptables 中 Docker 相关的规则 sudo iptables -L DOCKER-USER -n -v -
使用网络策略限制:
# 创建仅内部访问的网络 docker network create --internal internal-only
评论区