Skip to main content
SecurityAdvanced

Securing Docker Containers: A Production Checklist

A comprehensive production checklist for Docker container security — non-root users, image scanning, seccomp profiles, secrets management, and more.

N
Neeraj Jha
·Updated September 11, 2026·5 min read
Securing Docker Containers: A Production Checklist

Running containers in production without security hardening is like leaving your front door open. This checklist covers the essential practices for securing Docker containers from image build to runtime.

1. Run as Non-Root

By default, containers run as root. This is dangerous — a container escape as root means root on the host.

dockerfile
FROM node:20-alpine

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

WORKDIR /app
COPY --chown=appuser:appgroup . .
RUN npm ci --only=production

USER appuser
CMD ["node", "server.js"]

Verify with docker exec <container> whoami — it should not return root.

2. Use Minimal Base Images

ImageSizeAttack Surface
ubuntu:22.04~77MBLarge — includes many packages
node:20~340MBVery large — full Debian
node:20-alpine~50MBMinimal — musl libc, few packages
node:20-alpine + multi-stage~30MBSmallest — only production deps
gcr.io/distroless/nodejs20~40MBNo shell, no package manager

Fewer packages means fewer CVEs. Distroless images are ideal for production since they contain no shell, making exploitation significantly harder.

3. Read-Only Filesystem

Prevent malicious writes inside the container:

yaml
services:
  api:
    image: myorg/api:1.4.2
    read_only: true
    tmpfs:
      - /tmp
      - /var/run

Use tmpfs mounts for directories that need temporary write access.

4. Drop All Linux Capabilities

By default, Docker grants a set of Linux capabilities. Drop them all and add back only what you need:

yaml
services:
  api:
    image: myorg/api:1.4.2
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE

Common capabilities and their use:

CapabilityPurpose
NET_BIND_SERVICEBind to ports below 1024
CHOWNChange file ownership
SETUID / SETGIDChange process UID/GID
SYS_PTRACEDebug processes (avoid in prod)

5. Seccomp Profiles

Seccomp filters restrict which system calls a container can make. Docker's default profile blocks ~44 dangerous syscalls. You can make it stricter:

json
{
  "defaultAction": "SCMP_ACT_ERRNO",
  "architectures": ["SCMP_ARCH_X86_64"],
  "syscalls": [
    {
      "names": ["read", "write", "open", "close", "stat", "fstat", "mmap", "mprotect", "munmap", "brk", "exit_group"],
      "action": "SCMP_ACT_ALLOW"
    }
  ]
}

Apply it:

bash
docker run --security-opt seccomp=custom-profile.json myimage

6. Image Scanning

Scan images for known vulnerabilities before deploying:

bash
# Trivy (open-source, fast)
trivy image myorg/api:1.4.2

# Docker Scout (built into Docker Desktop)
docker scout cves myorg/api:1.4.2

# Grype (Anchore)
grype myorg/api:1.4.2

Integrate scanning into your CI pipeline so vulnerable images never reach production.

7. Secrets Management

Never bake secrets into images. Instead:

bash
# Bad — secret visible in image layers
ENV DATABASE_PASSWORD=mysecret

# Good — mount as Docker secret
docker secret create db_password ./secret.txt
yaml
services:
  api:
    image: myorg/api:1.4.2
    secrets:
      - db_password

secrets:
  db_password:
    file: ./secrets/db_password.txt

Access the secret at /run/secrets/db_password inside the container.

8. Network Segmentation

Limit container-to-container communication:

yaml
networks:
  frontend:
  backend:
    internal: true  # No external access

services:
  nginx:
    networks: [frontend, backend]
  api:
    networks: [backend]
  db:
    networks: [backend]

The internal: true flag prevents containers on that network from reaching the internet.

9. Resource Limits

Prevent denial-of-service by limiting resources:

yaml
services:
  api:
    deploy:
      resources:
        limits:
          cpus: "1.0"
          memory: 512M
          pids: 100

The pids limit prevents fork bombs.

10. Audit and Monitoring

  • Enable Docker daemon audit logging
  • Monitor container activity with Falco (runtime security)
  • Set up alerts for privilege escalation attempts
  • Regularly rotate and update images

Quick Reference Checklist

  • Non-root user in Dockerfile
  • Minimal / distroless base image
  • Read-only filesystem where possible
  • All capabilities dropped, only needed ones added
  • Seccomp profile applied
  • Images scanned in CI
  • Secrets mounted, never baked
  • Networks segmented
  • Resource limits enforced
  • Runtime monitoring enabled

Security is not a one-time task. Build these practices into your pipeline and review them regularly.

Tagged with

Enjoyed this article?

Get more DevOps insights delivered to your inbox.

Get new posts by email

Subscribe to get an email when a new blog post is published. Skip anytime.

No spam, unsubscribe anytime.

N

Written by

Neeraj Jha

Platform administrator and lead writer.

View all posts

Discussion

0 comments

Sign in to join the conversation.

Be the first to comment

Start a conversation about this post

Share: