Docker Compose Hardening: Complete Guide for Secure Homelabs
Technical deep dive on security best practices for Docker Compose in homelab environments. Configurations, privilege restrictions, and isolation to protect containers.
Docker Compose is an essential tool for managing container stacks in homelab environments, but security is often overlooked. In this guide, we dive deep into hardening techniques to protect your self-hosted services.
Why Harden Docker Compose?
Docker containers, if not configured properly, can pose a security risk to the entire homelab. Elevated privileges, dangerous mount points, and open network configurations are common vulnerabilities.
Fundamental Best Practices
1. User Namespace Remapping
User namespace remapping is one of the most effective techniques to prevent privilege escalation:
services:
app:
image: nginx:alpine
user: "1000:1000"
security_opt:
- "no-new-privileges:true"
2. Capability Limitation
Removing unnecessary capabilities drastically reduces the attack surface:
services:
database:
image: postgres:15
cap_drop:
- ALL
cap_add:
- CHOWN
- DAC_OVERRIDE
- SETGID
- SETUID
3. Read-Only Filesystem
Configure containers with read-only filesystems whenever possible:
services:
web:
image: nginx:alpine
read_only: true
tmpfs:
- /tmp
- /run
- /var/cache/nginx
Secure Network Configuration
Network Isolation
Use dedicated Docker networks for each stack:
networks:
app-network:
driver: bridge
internal: true
ipam:
config:
- subnet: 172.28.0.0/16
services:
app:
networks:
- app-network
Port Limitation
Expose only strictly necessary ports:
services:
webapp:
ports:
- "8080:80" # Solo HTTP
# - "8443:443" # Solo se serve HTTPS
Volume and Mount Point Management
Named Volumes vs Bind Mounts
Prefer named volumes over bind mounts for greater security:
volumes:
app-data:
driver: local
services:
app:
volumes:
- app-data:/app/data
# Evitare: - /host/path:/container/path
Access Restrictions
services:
database:
volumes:
- db-data:/var/lib/postgresql/data
environment:
- PGDATA=/var/lib/postgresql/data/pgdata
Resource Limits and Security Opt
Resource Limitation
services:
app:
deploy:
resources:
limits:
cpus: "2"
memory: 512M
reservations:
cpus: "0.5"
memory: 256M
Advanced Security Options
services:
critical-app:
security_opt:
- "apparmor:docker-default"
- "seccomp=unconfined"
pids_limit: 100
Complete Hardening Checklist
- [ ] User namespace remapping configured
- [ ] Unnecessary capabilities removed
- [ ] Read-only filesystem where possible
- [ ] Isolated and internal networks
- [ ] Only necessary ports exposed
- [ ] Named volumes instead of bind mounts
- [ ] Appropriate resource limits
- [ ] Security opt configured
- [ ] No-new-privileges enabled
- [ ] PIDs limit set
Complete Hardened docker-compose.yml Example
version: "3.8"
networks:
app-net:
driver: bridge
internal: true
ipam:
config:
- subnet: 172.22.0.0/16
volumes:
app-data:
driver: local
db-data:
driver: local
services:
web:
image: nginx:alpine
user: "101:101"
read_only: true
tmpfs:
- /tmp
- /run
- /var/cache/nginx
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
security_opt:
- "no-new-privileges:true"
networks:
- app-net
ports:
- "8080:80"
deploy:
resources:
limits:
memory: 256M
cpus: "1"
app:
image: node:18-alpine
user: "1000:1000"
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
security_opt:
- "no-new-privileges:true"
networks:
- app-net
volumes:
- app-data:/app/data
environment:
- NODE_ENV=production
- PORT=3000
database:
image: postgres:15-alpine
user: "999:999"
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
security_opt:
- "no-new-privileges:true"
networks:
- app-net
volumes:
- db-data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=appdb
- POSTGRES_USER=appuser
- POSTGRES_PASSWORD_FILE=/run/s...rd
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
Conclusions
Docker Compose hardening is not a one-time process but a continuous practice. Every new service added to the stack should be evaluated against these guidelines. Container security is an investment that protects not only individual services but the entire homelab infrastructure.
Remember: perfect security doesn't exist, but reducing the attack surface is the first step toward a more resilient homelab.
Sources: OWASP Docker Security Cheat Sheet, Docker Official Documentation, Reddit r/homelab discussions