SyntaxStudy
Sign Up
Docker Production Hardening Checklist
Docker Beginner 1 min read

Production Hardening Checklist

Running Docker in production requires deliberate hardening beyond the defaults. The most impactful changes are: use specific image tags (never latest), run containers as non-root users, set memory and CPU limits, mount filesystems as read-only where possible, drop unnecessary Linux capabilities, scan images for CVEs before deployment, and keep base images updated. Enable Docker's --live-restore daemon option so running containers survive Docker daemon restarts, which is essential during Docker upgrades. Set the logging driver to json-file with max-size and max-file limits to prevent containers from filling the disk with logs. Use a secrets manager (Docker secrets, Vault, AWS SSM) instead of environment variables for sensitive values. For the host OS, keep Docker Engine updated, restrict access to the Docker socket (access to the socket is equivalent to root on the host), and consider using rootless Docker mode which runs the daemon as a non-root user. Enable audit logging for Docker daemon actions and forward container logs to a centralised logging platform for retention and analysis.
Example
# /etc/docker/daemon.json - production Docker daemon config
# {
#   "live-restore": true,
#   "log-driver": "json-file",
#   "log-opts": { "max-size": "10m", "max-file": "5" },
#   "userland-proxy": false,
#   "no-new-privileges": true
# }

# Hardened docker run command
docker run -d \
  --name api \
  --restart unless-stopped \
  --memory 512m \
  --memory-swap 512m \
  --cpus 1 \
  --read-only \
  --tmpfs /tmp:size=64m \
  --cap-drop ALL \
  --cap-add NET_BIND_SERVICE \
  --security-opt no-new-privileges:true \
  --user 1001:1001 \
  --health-cmd "wget -qO- http://localhost:3000/health || exit 1" \
  --health-interval 30s \
  --health-retries 3 \
  -p 127.0.0.1:3000:3000 \
  -e NODE_ENV=production \
  myapp:2.1.0

# Verify security posture
docker inspect api --format '{{.HostConfig.ReadonlyRootfs}}'
docker inspect api --format '{{.HostConfig.CapDrop}}'
docker inspect api --format '{{.Config.User}}'