Docker 的 Permission denied 很容易误导人。
同样是权限错误,可能发生在两个完全不同的位置:
- 你在宿主机执行
docker ps,提示连不上 Docker daemon socket。 - 容器已经启动,但访问挂载目录时提示
Permission denied。
前者是宿主机用户没有权限访问 Docker socket,后者是容器内进程和宿主机目录的 UID/GID 不匹配。这两类问题不能用同一套命令解决。很多人一看到权限错误就 chmod 777,短期可能不报错,长期会把安全和数据所有权搞乱。
这篇按 VPS 上最常见的 Docker 权限问题排查:先解决 /var/run/docker.sock,再看 docker 用户组和会话刷新,最后处理 bind mount、容器用户、rootless Docker 和 CI/CD 里的 socket 挂载。
如果你执行:
docker ps
看到:
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
这是宿主机用户访问 Docker daemon 的权限问题。
如果你执行容器日志或应用操作时看到:
Permission denied: '/data/cache'
open /app/storage/logs/app.log: permission denied
这通常是容器内用户写宿主机挂载目录失败。
先分清这两层,再动手。
权限问题之前,先确认 Docker 本身不是挂了:
systemctl status docker
如果服务没启动:
sudo systemctl enable --now docker
再看 socket 文件:
ls -l /var/run/docker.sock
常见输出:
srw-rw---- 1 root docker 0 May 25 10:00 /var/run/docker.sock
这里的关键是:socket 属于 root:docker,权限通常是 660。也就是说,root 和 docker 组成员可以访问它。
如果 Docker 服务本身异常,先不要急着改权限。可以看:
journalctl -u docker --since "30 minutes ago"
如果你还不熟悉系统日志,可以先看:VPS 日志怎么看:journalctl、systemctl、Nginx、应用日志。
查看当前用户所属组:
id
如果里面没有 docker,添加当前用户:
sudo usermod -aG docker $USER
如果你是给另一个用户加权限:
sudo usermod -aG docker deploy
注意 -aG 不能少。-G docker 会把用户从其他附加组里移除,可能造成新的权限问题。
加完组以后,不要马上判断失败。当前 SSH 会话里的组信息不会自动刷新。
很多人执行完:
sudo usermod -aG docker $USER
立刻运行:
docker ps
还是报 permission denied,于是以为命令没用。实际上你需要重新登录,或者临时刷新组:
newgrp docker
然后再试:
docker ps
更稳的方式是退出 SSH 重新登录:
exit
重新连接后再执行:
id
docker ps
如果 id 里已经有 docker,但还是没权限,继续看 socket 权限是否被改坏。
有些教程会让你执行:
sudo chmod 777 /var/run/docker.sock
不要这么做。
能访问 Docker socket,基本等价于拿到宿主机 root 权限。因为用户可以启动一个挂载宿主机根目录的容器,然后修改宿主机文件。
例如:
docker run --rm -it -v /:/host debian:12 chroot /host bash
所以,加入 docker 组本身就是一个高权限操作。它比普通“能跑容器”更敏感。生产环境里,不要随便把业务用户、Web 用户、CI 用户都加到 docker 组。
如果 socket 权限被你改乱了,可以先重启 Docker 让它恢复默认:
sudo systemctl restart docker
ls -l /var/run/docker.sock
如果仍然异常,再检查 systemd socket 或发行版包配置,不要靠 777 硬压过去。
如果:
sudo docker ps
可以运行,而:
docker ps
不行,说明 Docker daemon 正常,问题在当前用户权限。
这时不要把所有 Docker 命令都长期写成 sudo docker ...。对于个人 VPS,这样也能用,但会带来两个副作用:
- 生成的文件可能归 root 所有。
- 后续 Compose、CI、部署脚本的权限会更混乱。
更推荐:明确哪个用户负责部署,把它加入 docker 组,然后用这个用户运行 Docker。
如果你安装的是 rootless Docker,socket 不一定在:
/var/run/docker.sock
而可能在:
/run/user/1000/docker.sock
检查环境变量:
echo $DOCKER_HOST
Rootless Docker 常见设置:
export DOCKER_HOST=unix:///run/user/1000/docker.sock
如果你在 systemd service、cron 或 CI 脚本里调用 Docker,交互式 shell 里的 DOCKER_HOST 不一定存在。脚本里要明确设置,或者使用正确用户的环境。
这类问题也常和定时任务混在一起。如果是 cron 里能手动执行 Docker、自动执行失败,可以参考:VPS 定时任务不执行怎么办。
另一类常见问题是容器启动成功,但应用写文件失败。
例如 Compose 里:
services:
app:
image: my-app
volumes:
- ./data:/app/data
容器里应用写 /app/data 报错。这时先看宿主机目录权限:
ls -ld ./data
stat ./data
再看容器进程实际用哪个用户运行:
docker exec -it app id
ps aux
如果容器内用户是 UID 1000,而宿主机目录属于 root 且没有写权限,就会失败。
你可以把目录所有权改给对应 UID/GID:
sudo chown -R 1000:1000 ./data
或者在 Compose 里明确运行用户:
services:
app:
image: my-app
user: "1000:1000"
volumes:
- ./data:/app/data
不要一上来:
chmod -R 777 ./data
这会让任何本机用户都能写,安全边界太粗。
数据库、对象存储模拟目录、Web 上传目录最容易被权限问题搞坏。
例如 MySQL 容器的数据目录必须由容器内的 mysql 用户可写。你把一个 root-owned 目录挂进去,容器可能直接启动失败,或者初始化一半后留下错误文件。
排查顺序:
docker logs mysql
ls -ld ./mysql-data
docker exec -it mysql id mysql
如果是 Web 应用,例如 Laravel、WordPress、Nextcloud,通常要确认:
storage/uploads/cache目录可写。- Nginx/PHP-FPM/应用容器的 UID/GID 是否一致。
- 宿主机备份脚本是否把文件恢复成 root 所有。
如果你遇到的是 Web 502/504,而日志里又有权限报错,可以对照:VPS 出现 502 / 504 Bad Gateway 怎么办。
很多 CI/CD 教程会写:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
这样容器里的 CI runner 就可以控制宿主机 Docker。但风险也很高:如果 CI 任务被恶意代码控制,攻击者就能控制宿主机 Docker,进一步拿到宿主机权限。
更稳的做法取决于场景:
- 小型个人 VPS:可以临时使用,但只给可信项目。
- 多人团队:把 CI runner 隔离到单独机器。
- 高安全要求:使用 rootless Docker、远程构建器,或专门的构建环境。
不要把 Docker socket 暴露给公开 Web 应用容器。
遇到 Docker permission denied,按这个顺序查:
systemctl status docker确认 Docker daemon 正常。ls -l /var/run/docker.sock看 socket 属主和权限。id看当前用户是否在docker组。sudo usermod -aG docker $USER添加用户组。- 退出 SSH 重登,或执行
newgrp docker。 - 不要
chmod 777 /var/run/docker.sock。 - 如果是 rootless Docker,检查
DOCKER_HOST和/run/user/UID/docker.sock。 - 如果是 bind mount 写入失败,查宿主机目录 owner、容器内 UID/GID。
- 用
chown UID:GID或 Composeuser:对齐权限。 - CI/CD 场景谨慎挂载
/var/run/docker.sock。
Docker 的 Permission denied 要先分层:是宿主机用户访问 Docker socket 被拒,还是容器内进程写挂载目录被拒。
前者通常用 docker 用户组和重新登录解决;后者要对齐宿主机目录和容器用户的 UID/GID。真正不该做的是一把梭 chmod 777,尤其是 /var/run/docker.sock。Docker socket 权限本质上接近 root 权限,给谁访问,就等于信任谁能控制这台 VPS。
