Running Docker containers with default settings is like leaving your front door unlocked. Here's a practical guide to hardening your containers and reducing your attack surface.
The Core PrinciplesThe Core Principles
Most Docker containers run as root by default and get far more capabilities than they actually need. This creates unnecessary risk if a container is compromised. The solution? Apply the principle of least privilege across every aspect of your container configuration.
Key Hardening TechniquesKey Hardening Techniques
Run as non-root user
user: "99:100" # nobody:users on UnraidDrop all capabilities by default
cap_drop:
- ALLOnly add back specific capabilities if absolutely required.
Enable security restrictions
security_opt:
- no-new-privileges:true
read_only: true # if possible
tty: false
stdin_open: falseHarden /tmp to prevent payload execution
tmpfs:
- /tmp:rw,noexec,nosuid,nodev,size=512mSet resource limits
pids_limit: 512
mem_limit: 3g
cpus: 3Mount volumes read-only when possible
volumes:
- /mnt/data/movies:/movies:roControl logging to prevent log bombs
logging:
driver: json-file
options:
max-size: "50m"
max-file: "5"Using TemplatesUsing Templates
Save time with compose anchors:
x-lockdown: &lockdown
read_only: true
security_opt:
- "no-new-privileges=true"
cap_drop:
- ALL
tmpfs:
- /tmp:rw,noexec,nosuid,nodev,size=512m
services:
myapp:
<<: *lockdownImportant NotesImportant Notes
Some containers won't work with all restrictions enabled. Use docker logs <container> to troubleshoot and selectively relax constraints as needed. For internet-facing containers, consider running them in a DMZ network or separate VM for additional isolation.
These configurations significantly reduce blast radius without eliminating all risk. Defense in depth is key.
*Credit: Based on excellent advice from the /r/selfhosted community https://www.reddit.com/r/selfhosted/comments/1pr74r4/comment/nv07sp4/ *