跳转至正文内容

独立技术知识论坛 主机玩家与运维交流社区 • 与德国 netcup GmbH 无官方隶属关系。

NETCUP GUIDE
知识论坛 · 实时优惠码池
运维教程 难度:初级入门 耗时:20 分钟 // 阅读约 18 分钟 • 核验于

如何在 Netcup VPS 与 Root Server 上安装 Docker Engine 并修复 UFW 防火墙绕过问题

得益于 Netcup 全系 VPS 与 Root Server 均采用完整的 QEMU/KVM 硬件虚拟化架构(而非共享宿主机内核的 LXC/OpenVZ 容器),Docker Engine 在 Netcup 服务器上拥有 100% 原生内核性能,完全不存在 cgroupv2 权限受限或 overlay2 挂载报错的问题。然而,如果在终端里随手执行 apt install docker.io,不仅会装上版本严重滞后的发行版旧包,还会面临两大生产级隐患:一是容器标准输出 JSON 日志无限膨胀直至写满 SSD/NVMe 磁盘;二是 Docker 默认注入的 iptables 转发规则会绕过 UFW 防火墙,将您的内网数据库端口直接暴露在公网扫描器之下!本教程将带您配置 Docker 官方加密 APT 源、硬化 /etc/docker/daemon.json 守护进程参数,并构建三层容器网络边界防御体系。

楼主 (OP) // 实测发起人 Marcus Vance 首席云基础设施架构师(欧洲 KVM 与网络工程)
版主复核 // 共同维护 Elena Rostova 高级 Linux 系统与安全审计工程师
帖子状态 // 最后修订 社区核查规范 →
版主按语 // 实测环境与社区透明说明 本教程基于官方 Docker CE(docker-ce v27+)生产软件包、ext4/XFS 文件系统下的 overlay2 存储驱动以及 Netcup SCP 宿主机边缘防火墙实测验证。

环境要求 // 前置条件清单

检查清单
  • ✓ 一台运行 Ubuntu 24.04 LTS 或 Debian 12 的 Netcup VPS(如 VPS 500 G12.5 或 VPS 1000 G12.5)或 Root Server(如 RS 1000 G12.5)
  • ✓ 已配置好具备 sudo 权限的非 root 管理员 SSH 登录账户

核心技术结论 (Key Takeaways)

核心摘要
  • 01 切勿安装 Ubuntu/Debian 仓库自带的陈旧 docker.io 包或受限于 AppArmor 沙盒路径的 Snap 版 Docker;务必添加 Docker 官方 GPG 签名仓库以安装最新的 docker-ce、containerd.io 与 docker-compose-plugin。
  • 02 在 /etc/docker/daemon.json 中强制配置 max-size: "10m"、max-file: "3" 日志轮转策略以及 live-restore: true 热恢复机制,既能防止容器 stdout 日志写满磁盘,又能保证升级 Docker 守护进程时业务容器零中断运行。
  • 03 关键安全准则:使用 -p 5432:5432 发布容器端口时,Docker 会在 UFW 的 INPUT 过滤链生效之前直接在内核 PREROUTING/DOCKER 链中放行流量!所有内部服务端口必须显式绑定至本地回环地址(如 127.0.0.1:5432:5432),并配合 Netcup SCP 宿主机防火墙实现双重封堵。
📑 本文目录导航(共 3 节) ▼
§ 01

第一步:清理冲突旧包并注册 Docker 官方 GPG 加密 APT 软件源

在正式安装上游 Docker Engine 之前,第一步是卸载操作系统发行版自带的任何旧版容器运行时组件(如 docker.io、podman-docker、docker-compose v1 Python 脚本以及独立的旧版 containerd),并确认系统中未安装通过 snap 分发的 Docker 软件包。Ubuntu 安装向导中有时会引导用户勾选 Snap 版 Docker,但 Snap 的严格目录沙盒与 AppArmor 策略会导致容器无法挂载 /opt 或自定义数据盘路径,且 Snap 后台强制自动更新会在毫无预警的情况下重启整机容器集群。

卸载冲突旧包后,我们将创建符合 Debian/Ubuntu 现代安全规范的 /etc/apt/keyrings 目录(权限 0755,取代早已废弃的全局 apt-key add 命令),下载并注册 Docker 官方 GPG 公钥证书(docker.asc),并通过 signed-by=/etc/apt/keyrings/docker.asc 参数将信任范围严格限定在 Docker 官方软件源内。

为了确保脚本在 Ubuntu 24.04 LTS(代号 noble)与 Debian 12(代号 bookworm)上均能零差错执行,下方代码块直接读取 /etc/os-release 中的 $ID 与 $VERSION_CODENAME 环境变量动态生成 /etc/apt/sources.list.d/docker.list,并一次性安装 docker-ce、docker-ce-cli、containerd.io、docker-buildx-plugin 以及原生 Go 语言编写的 docker-compose-plugin(即 docker compose v2 命令)。

从底层虚拟化架构来看,Netcup 全系 VPS 与 Root Server 均基于 QEMU/KVM 全虚拟化技术,为客户机提供独立的 Linux 6.8+ 内核空间、完整的 cgroupv2(Control Groups v2)资源隔离层级以及原生 overlay2 联合文件系统支持。这意味着您可以利用 deploy.resources.limits 对单个容器施加精准的 CPU 份额与内存硬上限(避免某个内存泄漏的 Java 或 Node.js 容器拖垮整台服务器),同时利用 BuildKit 多阶段并发构建缓存将 CI/CD 镜像打包速度提升 3 倍以上:

配置 Docker 官方 APT 软件源并安装 Docker Engine 与 Compose v2 全套工具链
bash
# 1. 清理系统内置的旧版冲突容器软件包
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
  sudo apt-get remove -y $pkg 2>/dev/null || true
done

# 2. 安装前置依赖并导入 Docker 官方 GPG 签名公钥
sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
. /etc/os-release
sudo curl -fsSL "https://download.docker.com/linux/${ID}/gpg" -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# 3. 写入官方 Docker APT 软件源配置
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/${ID} ${VERSION_CODENAME} stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 4. 安装 Docker Engine、CLI、containerd、Buildx 与 Compose v2 插件
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
docker --version && docker compose version

命令与参数详解: 通过 /etc/os-release 自动识别当前 Netcup 服务器运行的是 ubuntu 还是 debian,配置由官方 GPG 密钥签名的稳定版软件源,并安装包含 Buildx 与 Compose v2 在内的完整现代容器引擎。

预期终端输出
Docker version 27.3.1, build ce12230
Docker Compose version v2.29.7
§ 02

第二步:硬化 /etc/docker/daemon.json 守护进程配置(日志轮转、热恢复与 IPAM 地址池)

默认安装状态下,Docker 的 json-file 日志驱动会将容器内应用向标准输出(stdout)和标准错误(stderr)打印的每一行访问日志永久追加保存在 /var/lib/docker/containers/<container-id>/ 目录下,且没有任何体积上限!在承载生产业务的 Netcup VPS 1000 G12.5 或 RS 1000 G12.5 上,一个高并发的 Nginx、Traefik 或 Node.js 容器在运行数月后,其未轮转的 JSON 日志文件往往会悄无声息地吞噬 40 GB 以上的宝贵 NVMe 空间,最终引发全盘 ENOSPC (No space left on device) 故障并导致 PostgreSQL 或 MySQL 数据库停机。

通过在 /etc/docker/daemon.json 中显式配置 "max-size": "10m"、"max-file": "3" 与 "compress": "true",Docker 守护进程会在单个容器日志达到 10 MB 时自动触发轮转与 gzip 压缩,并仅保留最新的 3 个历史分片(单容器日志封顶 30 MB)。同时,显式指定 "storage-driver": "overlay2" 可确保容器镜像层直接利用 Linux 内核原生的目录级写时复制(Copy-on-Write)机制,充分释放 Netcup 本地 RAID10 NVMe 存储阵列的随机读写性能。

生产环境还应当开启两项关键内核级特性:一是设置 "live-restore": true,将容器生命周期管理与上层 dockerd 守护进程解耦——当 unattended-upgrades 自动升级 docker-ce 软件包并重启 dockerd 时,所有正在运行的业务容器由底层 containerd-shim 保持继续运行而不会发生中断;二是设置 "userland-proxy": false,关闭默认情况下每个端口映射都会派生一个消耗额外 RAM 与 CPU 上下文切换的 docker-proxy 用户态转发进程,完全交由 Linux 内核的高性能 netfilter 原生 Hairpin NAT 处理流量转发。

最后,通过 "default-address-pools" 显式规划容器网桥的 IPAM(IP 地址管理)子网分配策略至关重要。默认情况下,每当您执行一次 docker compose up 创建一个新项目网络时,Docker 都会豪横地切分走一整段 /16 大网段(172.17.0.0/16、172.18.0.0/16……),不仅迅速耗尽私有路由空间,还极易与企业内部的 WireGuard、Tailscale 或 OpenVPN 隧道网段发生路由冲突。将地址池基准设为 172.20.0.0/14 并将子网掩码粒度设为 "size": 24,即可支持多达 1,024 个互不冲突的独立 Compose 网络:

写入生产级 /etc/docker/daemon.json 配置文件并平滑重启 Docker 服务
bash
cat << 'EOF' | sudo tee /etc/docker/daemon.json
{
  "storage-driver": "overlay2",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3",
    "compress": "true"
  },
  "live-restore": true,
  "userland-proxy": false,
  "default-address-pools": [
    {
      "base": "172.20.0.0/14",
      "size": 24
    }
  ]
}
EOF

sudo systemctl daemon-reload
sudo systemctl restart docker
sudo docker info | grep -E "Storage Driver|Logging Driver|Live Restore"

命令与参数详解: 将单容器日志体积封顶在 30 MB(3 × 10m),禁用高内存占用的 docker-proxy 用户态代理以启用纯内核 NAT 转发,激活守护进程升级期间的容器热恢复(live-restore),并规划清晰的 /24 容器子网地址池。

预期终端输出
 Storage Driver: overlay2
 Logging Driver: json-file
 Live Restore Enabled: true
§ 03

第三步:解决 Docker 绕过 UFW 防火墙的高危网络暴露问题

这是自建 Linux 容器服务器上最常见的高危安全隐患:当您在 Ubuntu 上开启了 ufw 防火墙(设置默认拒绝入站 ufw default deny incoming,仅放行 22/80/443),随后在 compose.yaml 中使用 ports: - "5432:5432" 或 - "6379:6379" 启动 PostgreSQL 或 Redis 容器时,Docker 会直接修改 Linux 内核 nat 表的 PREROUTING 链与 filter 表的 FORWARD 链。而在 Linux netfilter 数据包处理流程中,PREROUTING 目的地址转换(DNAT)发生在路由决策之前,被重写目标 IP 的数据包随后直接进入 FORWARD 转发链,从而完全绕过了 UFW 所接管的本机 INPUT 过滤链!

结果就是:尽管您在宿主机终端运行 sudo ufw status 看到防火墙处于激活状态且并未放行 5432 或 6379 端口,但全世界的自动化扫描器却能直接连上您容器的数据库端口。更危险的是,如果您为了阻止这种行为而在 /etc/docker/daemon.json 中草率地设置 "iptables": false,则会直接切断所有 Docker 容器的源地址转换(SNAT / MASQUERADE),导致容器内部无法访问外部互联网或拉取 API 数据。

正确的根治方案是从套接字绑定层入手:只要某个容器端口仅供宿主机本机的 Nginx/Caddy 反向代理或本机其他容器调用,在 docker run -p 或 compose.yaml 的 ports: 数组中就必须显式指定本地回环地址前缀 127.0.0.1:(例如 "127.0.0.1:5432:5432" 或 "127.0.0.1:8080:8080")。这样内核 DNAT 规则会严格限制仅匹配目标地址为 127.0.0.1 的本地数据包,任何来自外部 eth0 公网网卡的探测流量都会被直接丢弃。

在此基础上,结合 Netcup 独有的 SCP 宿主机边缘有状态防火墙(Hypervisor Stateful Firewall) 与 Docker 官方预留的 DOCKER-USER 过滤链,即可在 Netcup 服务器上构建起三层纵深容器网络边界防御体系,确保没有任何一个后端容器端口会意外暴露在公网之上:

  • ▪ 第一层防御 —— 在 compose.yaml 中强制绑定本地回环地址(Loopback Binding):对于任何由宿主机 Nginx/Caddy 反向代理或本机服务访问的容器端口,一律写成 127.0.0.1:8080:8080 或 127.0.0.1:6379:6379,从套接字源头阻止外部网卡访问。
  • ▪ 第二层防御 —— 启用 Netcup SCP 宿主机有状态防火墙(Hypervisor Stateful Firewall):登录 servercontrolpanel.de → Network → Firewall,仅允许入站 TCP 22、80、443 与 UDP 443,并将默认入站策略设为 DROP。由于 SCP 防火墙运行在宿主机虚拟交换机层(位于虚拟机外部),客户机内部 Docker 修改的任何 iptables 规则都绝对无法穿透 SCP 防火墙!
  • ▪ 第三层防御 —— 在 /etc/ufw/after.rules 中锁定 DOCKER-USER 链:利用 Docker 专门预留给管理员的最高优先级过滤链 DOCKER-USER,显式丢弃从公网网卡(eth0/ens3)直接发往私有容器子网的非预期新建连接。
Netcup 各主力机型 Docker 容器承载能力与防火墙纵深架构对照表
Netcup 服务器型号存储卷与网络接口ECC 内存与计算核心典型 Docker 容器并发承载规模推荐防火墙防护组合
VPS nano G11.5s60 GB SSD / 1 Gbit/s VirtIO2 GB ECC / 2 vCPU3–5 个轻量级 Alpine / Go / Caddy 容器127.0.0.1 回环绑定 + Netcup SCP 边缘防火墙
VPS 500 G12.5128 GB NVMe / 1 Gbit/s VirtIO4 GB ECC / 4 vCPU8–12 个容器(WordPress、Redis、Postgres、Nginx)127.0.0.1 绑定 + SCP 边缘防火墙 + UFW
VPS 1000 G12.5256 GB NVMe / 1 Gbit/s VirtIO8 GB ECC / 6 vCPU15–25 个容器(全栈 SaaS 业务 + Prometheus 监控)127.0.0.1 绑定 + SCP 防火墙 + DOCKER-USER 链锁定
RS 1000 G12.5512 GB NVMe / 2.5 Gbit/s VirtIO8 GB DDR5 ECC / 4 独享 EPYC 核心25+ 个高 I/O 容器、CI 构建节点与生产数据库127.0.0.1 绑定 + SCP 防火墙 + DOCKER-USER 链锁定
实测本地回环端口绑定并审计全机监听套接字状态
bash
# 始终将内部应用与数据库容器端口严格绑定在 127.0.0.1 本地回环地址上:
docker run -d --name test-redis --restart unless-stopped -p 127.0.0.1:6379:6379 redis:7-alpine

# 审计 Netcup 服务器上所有处于监听状态的 TCP/UDP 套接字:
# 确保只有 sshd (22) 与您的前端反向代理 (80/443) 监听在 0.0.0.0 或 [::] 上
sudo ss -tulnp

命令与参数详解: 启动一个测试用 Redis 7 容器并将其严格绑定至 127.0.0.1:6379,随后通过 ss -tulnp 套接字审计命令确认其并未监听在公网通配地址 0.0.0.0:6379 上。

预期终端输出
tcp   LISTEN 0      4096       127.0.0.1:6379      0.0.0.0:*    users:(("dockerd",pid=1120,fd=14))

安全与生产运维提示: 关于 docker UNIX 用户组的权限警告:将普通用户加入 docker 组(sudo usermod -aG docker deployadmin)在安全等价意义上等同于授予无密码 root 权限,因为任何能调用 /var/run/docker.sock 的用户都可以通过 -v /:/host 将宿主机根目录挂载进容器。请仅将受信任的核心管理员加入该组。

严禁在公网 VPS 上直接使用 -p 5432:5432 发布内部容器端口

直接书写 -p 5432:5432 会默认绑定到 0.0.0.0:5432 并通过 netfilter FORWARD 链转发流量,从而 100% 绕过 UFW 的 INPUT 规则。所有仅限本机反代或内部调用的端口,必须显式加上本地回环前缀 127.0.0.1:(例如 127.0.0.1:5432:5432)。

常见故障排查方案

排障手册

[故障现象] Docker 容器内部无法解析外部域名(报错 Temporary failure in name resolution)

根本原因: Ubuntu 的 systemd-resolved 默认在宿主机本地回环地址 127.0.0.53 上运行 DNS Stub 监听,当容器进入独立的网络命名空间(Network Namespace)后,若未继承有效的上游公网 DNS,就会导致解析失败。

解决方案: 在 /etc/docker/daemon.json 中添加 "dns": ["46.38.225.230", "1.1.1.1", "2a03:4000:0:1::e1e6"](即 Netcup 机房内网低延迟递归 DNS 与 Cloudflare DNS),随后执行 sudo systemctl restart docker。

[故障现象] 修改 /etc/docker/daemon.json 后执行 systemctl restart docker 启动失败报错

根本原因: /etc/docker/daemon.json 文件中存在 JSON 格式语法错误(例如最后一个键值对末尾多写了逗号),或者与 docker.service 启动参数冲突。

解决方案: 运行 jq . /etc/docker/daemon.json 自动校验并高亮定位 JSON 语法错误,并通过 sudo journalctl -u docker.service -n 30 --no-pager 查看详细报错日志。

[故障现象] Docker 默认网桥(172.17.0.0/16)与企业内部 WireGuard 或 OpenVPN 隧道子网发生路由冲突

根本原因: 如果不显式指定 default-address-pools,Docker 会按顺序从 172.17.0.0/16 至 172.31.0.0/16 划分大网段,极易与内网 VPN 路由重叠。

解决方案: 按照本教程第二步在 /etc/docker/daemon.json 中配置 "default-address-pools",将子网精确控制在 172.20.0.0/14 的 /24 小段内,并运行 docker network prune 重建自定义网桥。

常见问题解答 (FAQ)

权威解答

入门级的 Netcup VPS nano G11.5s(2 GB ECC 内存)可以流畅运行 Docker 吗?

完全可以!因为 VPS nano G11.5s 同样基于完整的 KVM 硬件虚拟化,配备 2 GB ECC 内存与 60 GB SSD 存储,轻松支持同时运行 3 到 5 个基于 Alpine、Go 或 Nginx 的轻量级容器。如果需要同时运行 MariaDB/PostgreSQL 数据库与 Redis 缓存,建议选择 4 GB ECC 内存的 VPS 500 G12.5 或 8 GB ECC 内存的 VPS 1000 G12.5。

在 Netcup 服务器上使用 Docker overlay2 存储驱动,底层文件系统选 ext4 还是 XFS 更好?

Ubuntu 与 Debian 默认的 ext4 文件系统以及开启了 ftype=1 的 XFS 文件系统(AlmaLinux/Rocky Linux 默认)均是 Docker 官方认证的一级(Tier-1)overlay2 底层存储支持方案,性能表现一致且稳定可靠。

如何安全清理未使用的 Docker 历史镜像与 Buildx 编译缓存以释放磁盘空间?

可先执行 docker system df 查看各组件空间占用明细,随后定期执行 docker builder prune -af && docker image prune -af --filter "until=168h",即可安全回收超过 7 天未使用的悬空镜像与构建缓存,且绝不会误删正在使用的持久化数据卷(Named Volumes)。

为什么我已经执行了 sudo ufw deny 8080,外网依然能够直接访问我容器映射的 8080 端口?

因为 Docker 的端口映射规则直接注入在内核 netfilter 的 PREROUTING 与 FORWARD 链中,而 ufw deny 8080 仅作用于本机 INPUT 链。请务必在 compose.yaml 中改为 127.0.0.1:8080:8080,并同时开启 Netcup SCP 宿主机边缘防火墙。

在 Netcup RS 1000 G12.5 上运行多个高负载 Docker 容器时,如何限制单个容器的 CPU 与内存以防止 OOM?

在 compose.yaml 的对应服务下添加 mem_limit: 2g 与 cpus: 2.0(或使用 deploy.resources.limits)。由于 Netcup Ubuntu 24.04 默认启用了完整的 cgroupv2 控制器,当某个异常容器触及 2 GB 内存上限时,内核仅会回收或重启该容器内部的进程,而不会影响宿主机上的 PostgreSQL 数据库或其他正常运行的容器。

参考资料 // 官方技术文档与核验来源

延伸阅读 // 核心架构评测与买前必读

领取优惠码 →