In modern cloud-native development, Docker containers are the default standard for deploying web applications.
However, generic Dockerfiles often yield images containing OS vulnerabilities, unnecessary tooling, or root process privileges. In this guide, we cover the essential best practices to harden your Docker container images for production.
1. Enforce Multi-stage Builds
Leaving build tools, compiler caches, or developer dependencies (like npm or git) inside your final runtime image increases the container size and broadens the attack surface.
Multi-stage builds let you compile the binary in a dedicated environment, then copy only the static artifact to a minimal runtime layer.
# Stage 1: Build Environment
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp main.go
# Stage 2: Final Secure Layer
FROM alpine:3.19
WORKDIR /app
COPY --from=builder /app/myapp .
EXPOSE 8080
CMD ["./myapp"]
2. Avoid Running Containers as Root
By default, Docker container processes execute as root (superuser). If an attacker exploits a code vulnerability, they may gain full access to the underlying host kernel and filesystem.
Mitigate this by declaring a non-root system user inside the Dockerfile.
# Create a dedicated system user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
CMD ["./myapp"]
3. Choose Secure Base Images
Instead of basing your setup on a full OS distribution (like Ubuntu), choose lightweight, minimal baselines.
- Alpine Linux (
-alpine): A minimal OS (approx. 5MB) with a tiny packages footprint, reducing security vulnerabilities. - Distroless Images (Google): Contains only your compiled application and its runtime dependencies—completely excluding package managers, shells, and terminal tools.
4. Integrate Vulnerability Scanning (Trivy)
Automate security audits by scanning your built images during your CI/CD pipelines (e.g., GitHub Actions).
Using Trivy lets you scan your images for known CVEs before deployment.
# Auditing your local Docker image with Trivy
trivy image myapp:latest
5. Summary
The absolute rule of container security is minimization. By shipping only what is necessary and executing with minimal privileges, you insulate your production workloads against external exploits.
