- Advanced
- Security
How it works
cap_drop: [ALL] removes them and cap_add gives back only those a program proves it needs; privileged: true grants all of them and much more, and is almost never right. Images that start as root to fix permissions and switch user (nginx, postgres) need CHOWN, SETUID and SETGID; an app that already runs as an unprivileged user needs none. no-new-privileges stops setuid binaries from raising privileges.
What breaks
Without a capability, the call fails with Operation not permitted: chown of a folder, gosu or setgid when switching user. Add back exactly that one, or choose an image built to run unprivileged; keeping the default set leaves a compromised process more ways to escalate.
In compose.yaml
services:
frontend:
image: nginx:1.27-alpine
cap_drop: [ALL]
cap_add: [CHOWN, SETUID, SETGID]
security_opt:
- "no-new-privileges:true"
See it break, then fix it
Write the Dockerfile or the compose file, type the docker commands, and watch a simulated server run them through reboots, upgrades and traffic. Free to start.