在 docker-compose.yml 中避免 root 运行需显式指定非 root 用户(如 user: "1001:1001")、清空默认能力后仅添加必要项(cap_drop: ["ALL"] + cap_add: ["NET_BIND_SERVICE"])、启用 read_only: true 并对必需路径挂载 tmpfs 限制,最后通过 id、CapEff 和权限测试验证生效。

在 docker-compose.yml 中避免 root 运行,核心是**显式指定非 root 用户 + 精准控制能力 + 补强运行时约束**,不能只靠 user 字段就以为万事大吉。
明确指定 UID:GID 格式的用户
用数字 ID 而非用户名,避免容器内无对应用户导致降权失败或行为异常:
-
推荐写法:
user: "1001:1001"(UID 和 GID 都设为 1001) - 确保镜像中已创建该用户(Dockerfile 里用
useradd -u 1001 -g 1001 appuser) - 应用文件、配置目录、缓存路径等必须对该 UID:GID 可读可写(如
/var/www、/tmp、/var/cache/nginx)
配合 cap_drop 和 cap_add 实现最小能力集
默认能力太多,先清空再加必需项,否则 cap_add 反而扩大攻击面:
在 Linux 上通过 Docker 运行 OpenClaw,并使用 Tailscale 实现远程访问。⚠️ 涉及 sudo、Docker、Tailscale和凭证挂载——请先查阅安全章节...
- 必须写
cap_drop: ["ALL"],清掉所有默认能力 - 只加真正需要的,例如绑定 80/443 端口:
cap_add: ["NET_BIND_SERVICE"] - 绝对不加
SYS_ADMIN、NET_ADMIN、SYS_MODULE等高危能力
叠加只读根文件系统与临时挂载限制
即使用户和能力都设对了,攻击者仍可能写入恶意二进制或篡改配置:
- 启用
read_only: true,让整个根文件系统不可写 - 对必须可写的路径单独挂载
tmpfs,并限制大小和执行权限:tmpfs: - /tmp:size=20M,noexec,nosuid - 日志目录、缓存目录等也建议用
tmpfs或命名卷替代直接写入镜像层
验证是否真正生效
部署后进入容器快速检查三项:
- 执行
id:确认uid不是 0,gid也不为 0 - 执行
cat /proc/1/status | grep CapEff:十六进制值应仅含NET_BIND_SERVICE对应位(0x0000000000000010) - 尝试
ping 8.8.8.8或chown nobody /tmp/test:应提示“Operation not permitted”

















