Container Security

Docker Security Best Practices

Secure your containers from development to production. Common mistakes and how to fix them.

Security Best Practices

Use Minimal Base Images

Start with minimal images like Alpine or distroless. Less software = smaller attack surface.

Implementation: Use alpine variants or Google's distroless images. Avoid full OS images like ubuntu unless necessary.

Don't Run as Root

Containers running as root can escape to host. Always use a non-root user.

Implementation: Add USER directive in Dockerfile. Use --user flag when running containers.

Scan Images for Vulnerabilities

Base images and dependencies may have known CVEs. Scan before deploying.

Implementation: Use docker scout, trivy, or snyk in CI/CD. Block deployments with critical CVEs.

Never Store Secrets in Images

Secrets in Dockerfiles or images persist in layers and can be extracted.

Implementation: Use Docker secrets, environment variables at runtime, or secret managers.

Use Multi-Stage Builds

Keep build tools out of production images. Reduces size and attack surface.

Implementation: Build in one stage, copy only artifacts to final minimal image.

Common Dockerfile Mistakes

Hardcoding secrets in Dockerfile
ENV API_KEY=sk-xxx

Fix: Pass secrets at runtime: docker run -e API_KEY=$API_KEY

Using latest tag
FROM node:latest

Fix: Pin specific versions: FROM node:20.11-alpine

Running as root
No USER directive

Fix: Add: RUN adduser -D appuser && USER appuser

Exposing unnecessary ports
EXPOSE 22 (SSH in container)

Fix: Only expose ports your app needs. Never SSH into containers.

Copying entire directory
COPY . .

Fix: Use .dockerignore. Copy only what's needed.

Secure Dockerfile Template

# Use specific version, minimal base
FROM node:20.11-alpine AS builder

WORKDIR /app

# Copy package files first (cache dependencies)
COPY package*.json ./
RUN npm ci --only=production

# Copy source code
COPY src/ ./src/

# Build
RUN npm run build

# Production stage - minimal image
FROM node:20.11-alpine

# Create non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

WORKDIR /app

# Copy only production artifacts
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules

# Set ownership and switch to non-root
RUN chown -R appuser:appgroup /app
USER appuser

# Don't run as PID 1
CMD ["node", "dist/index.js"]

This template demonstrates: minimal base images, multi-stage builds, non-root user, and proper layer ordering.

Secure Your Containerized Apps

VAS scans your deployed applications for security issues— including exposed secrets that might have leaked from Docker images.

Free Security Scan

Frequently Asked Questions

Is Docker secure by default?

No. Docker provides isolation but defaults aren't hardened. Containers run as root by default, images may have vulnerabilities, and secrets can leak into layers. You need to actively implement security practices—use non-root users, scan images, and properly manage secrets.

Can containers escape to the host?

Yes, especially if running as root or with privileged mode. Container escapes are real vulnerabilities. Mitigate by: never using --privileged, running as non-root, keeping Docker updated, and using security tools like AppArmor or seccomp profiles.

How do I handle secrets in Docker?

Never put secrets in Dockerfiles or images. Options: Docker secrets (Swarm), Kubernetes secrets, environment variables at runtime (not build time), or secret managers like Vault, AWS Secrets Manager. For development, use .env files that aren't copied into images.

Should I use Alpine or Distroless?

Alpine is good for most use cases—small but has a shell for debugging. Distroless is more secure (no shell, minimal binaries) but harder to debug. Start with Alpine, consider distroless for high-security production workloads where you don't need shell access.

How often should I rebuild images?

At minimum, weekly to pick up security patches in base images. Better: trigger rebuilds when base images update. Use tools like Dependabot or Renovate to track base image updates. Critical CVEs should trigger immediate rebuilds.

Last updated: January 16, 2026