Containers·9 min read·

A Docker Security Checklist for Production Hosts

A production-ready Docker checklist: hardened host, minimal pinned images, non-root read-only runtime, capability drops, limits, and clean network hygiene.

NB

Netbay Cloud Team

Netbay Engineering

On this page

Docker does not make a host insecure by default — it just leaves every default on, and the defaults were chosen for convenience, not for a public-facing server. The practical question is which knobs to turn before trusting a production box, and in what order, because a checklist you cannot apply is a wish. This guide is that checklist: host foundation, image policy, runtime hardening, resource limits, network hygiene, and operations — each item concrete enough to verify in a single command, and complete enough to stand up to a review.

Layers of a hardened Docker host HOST: patched, firewalled, locked daemon IMAGES: pinned, scanned, minimal, no latest RUNTIME: non-root, read-only, caps dropped, limits OPERATIONS: prune, update, rotate, back up Each layer assumes the one beneath it is already true

Layer One: The Host Foundation

A hardened Docker stack starts on a boring host. Use a current LTS distribution, enable automatic security updates, and keep SSH hardened with key-only login. The firewall should close everything except the ports you actually publish, and the Docker daemon belongs on the local socket only — never expose 2375 or 2376 to the network, because an unauthenticated daemon socket is root on the box. Verify with the obvious commands: the byte-cheap checks that prove the foundation holds.

bash
ufw status verbose
ss -tlnp | grep -E '2375|2376'   # nothing listening here
docker context ls
apt list --upgradable | head

The context line confirms you are talking to the local daemon and not some accidentally discovered remote socket. If 2375 or 2376 appears in ss output, close it before evaluating a single container — that socket is the whole farm's front door.

Layer Two: Image Policy

Image hygiene is a policy before it is a pipeline. Pin images to explicit versions and digests; never deploy latest, because two hosts that pull at different times run different software with the same name. Run a scanner on the registry or in CI so a vulnerable base is caught before it is deployed, and prefer slim images that genuinely lack the packages a scanner would flag.

dockerfile
FROM debian:bookworm-slim@sha256:9f1f1e1f5a9e9d9b3e4d3c2b1a0f0e0d0c0b0a09080706050403020100
# or at minimum: FROM postgres:16-alpine
LABEL org.opencontainers.image.revision="7c9f2a1"

The digest (shown shortened here; a real one is longer and opaque, which is the point) makes the image content provably identical everywhere. A pinned digest plus a scanned registry turns "which version is running" from a question into a quoted fact.

Layer Three: Runtime Hardening

Every container that faces untrusted traffic should run with the full hardening set: non-root user, read-only rootfs, all capabilities dropped, no-new-privileges, and a seccomp profile. These are the four paragraph-one settings this series keeps returning to because they are the difference between "compromised process" and "compromised host".

yaml
name: api
services:
  web:
    image: my-api:2.4
    read_only: true
    tmpfs:
      - /tmp:size=64m
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    user: "10001:10001"
    restart: unless-stopped

Prefer running without --privileged and without host-mode networking unless a genuine requirement forces them. Docker's default seccomp profile is active out of the box; knowing it is there, and never disabling it per-container without review, is the discipline that keeps the profile meaningful.

Layer Four: Resource Limits

A container that can exhaust host memory or saturate four CPUs is a fault-isolation hole. Give every service explicit ceilings — memory, CPU, and process count — so a leak inside one container degrades that container instead of the whole host.

yaml
name: api
services:
  worker:
    image: my-worker:1.1
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: "1.0"
    pids_limit: 256
    read_only: true
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true

pids_limit is the one that most teams skip, and it is the guard against fork bombs inside a container — a runaway that would otherwise grind the host scheduler to a standstill. Memory limits without swap discipline can still write pressure through the host; set swap limits on the host level and keep the container memory well-defined.

Layer Five: Network Hygiene

One custom bridge network per trust tier, published ports only, and host-mode reserved for the few containers with a real reason. A database attached to the same network as the public web tier is one exploit away from being directly reachable; a database on its own internal network requires an explicit act to expose. The checks are the same commands from the networking post in this series: docker network inspect shows membership, docker port shows exposure.

bash
docker network ls
docker network inspect appnet
docker port web
docker ps --filter "network=appnet"

Every printed row is either a name you intended or a finding. If the reverse proxy's network contains a database container, that is a config choice you should be forced to explain in a review.

Layer Six: Operations Discipline

Security checklists rot without operations: prune, update, rotate, back up.

bash
docker image prune -af
docker builder prune -af
docker container prune -f
docker system df
docker volume ls

Weekly pruning removes dangling images and build cache; regular base-image pulls and rebuilds close the update gap that scanners expose; secrets rotate on a schedule instead of on incident (the worst time to migrate is during an ongoing breach); and volumes get their own backup story separate from the host disk. None of these commands is glamorous, and all four are what keep a checklist that was true in June still true in August.

Takeaway

A production Docker host is the sum of its defaults being deliberately overridden: a patched and firewalled host, pinned and scanned images, non-root read-only containers with capabilities dropped, explicit resource ceilings, segmented networks, and a pruning and rotation rhythm. Every item above is verifiable in one command that a reviewer can run, and together they describe a host where a single compromised process has nowhere convenient to go. On a Netbay VPS with full root and Docker-ready SSD storage, the entire checklist is yours to apply from the first boot onward — start at netbayhosts.in.

Keep reading

Follow along on a real VPS

Deploy Linux in under 60 seconds

These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.

Deploy an instance