Run as Non-Root
FROM node:20-slim
RUN addgroup --system app && adduser --system --ingroup app app
USER app
WORKDIR /app
COPY --chown=app:app . .
CMD ["node", "server.js"]
Use Read-Only Filesystem
docker run --read-only --tmpfs /tmp myapp
Limit Resources
docker run -d \
--memory=512m \
--cpus=1 \
--pids-limit=100 \
myapp
Network Isolation
# Create isolated networks
docker network create --internal backend
# Containers on "internal" networks cannot reach the internet
# Only expose necessary ports
docker run -p 127.0.0.1:3000:3000 myapp # Localhost only
Scan for Vulnerabilities
# Docker Scout
docker scout cves myapp:latest
# Trivy
trivy image myapp:latest
Secrets Management
# Never put secrets in images or environment variables
# Use Docker secrets (Swarm) or mount files
docker run -v /etc/secrets/db-password:/run/secrets/db-password:ro myapp
Security Checklist
- Use official, minimal base images (alpine, slim variants)
- Pin image versions — never use
:latest in production - Scan images before deployment
- Drop all Linux capabilities and add only what you need
- Enable Docker Content Trust for image signing
- Log container activity to a central system
- Regularly update base images
Drop Capabilities
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE myapp