Compose Secrets Deep Dive: Providers, Persistence, and the Last Mile

Compose makes secret delivery look settled. Declare a top-level secret, grant a service access to it, and the value appears under /run/secrets/. The interface is simple; the storage and delivery path behind it are not. Outside Swarm, a file-backed Compose secret is a bind mount. A secret sourced from the host environment follows a different path and, with current Compose versions, ends up in the container’s writable layer. Both appear under /run/secrets, but they leave different traces on the host and behave differently when someone runs docker commit. The path alone says nothing about whether the value lives in a tmpfs. ...

September 1, 2026 · 12 min · 2375 words · Guillaume Lours

Docker Compose Tip #73: expose vs ports — what actually gets published

Two directives that look similar but do completely different things. Confusing expose with ports is a classic way to either break inter-service communication or accidentally publish a database to the public internet. What each one does ports publishes a container port to the host. The outside world (and anything on the host) can reach it. services: web: image: nginx ports: - "8080:80" # host:container expose declares that a container listens on a port. It does not publish anything to the host. The directive is documentation of intent for tooling and humans. ...

June 8, 2026 · 3 min · 508 words · Guillaume Lours

Docker Compose Tip #43: Read-only root filesystems

Making a container’s root filesystem read-only is one of the simplest and most effective hardening measures. If an attacker gets in, they can’t modify binaries or drop malicious files. Basic usage services: app: image: myapp read_only: true That’s it. The container’s filesystem is now immutable. But most applications need to write somewhere — logs, temp files, caches. That’s where tmpfs comes in. Read-only with tmpfs for writable directories Combine read_only with tmpfs to allow writes only where needed: ...

March 23, 2026 · 2 min · 336 words · Guillaume Lours

Docker Compose Tip #31: Network isolation between services

Secure your application architecture by isolating services in separate networks. Not every service needs to talk to every other service! Default behavior: All connected By default, all services share the same network: # All services can communicate services: web: image: nginx api: image: myapi database: image: postgres Problem: web can directly access database - potential security risk! Network isolation pattern Create separate networks for different tiers: ...

February 23, 2026 · 3 min · 516 words · Guillaume Lours

Docker Compose Tip #29: Container capabilities and security options

Secure containers with principle of least privilege! Control exactly what your containers can do. Understanding capabilities Linux capabilities break down root privileges into distinct units: services: # Drop all capabilities, then add only what's needed secure-app: image: myapp cap_drop: - ALL cap_add: - NET_BIND_SERVICE # Bind to ports < 1024 - CHOWN # Change file ownership # Default Docker capabilities (for reference) default-app: image: myapp # Implicitly has: CHOWN, DAC_OVERRIDE, FSETID, FOWNER, # MKNOD, NET_RAW, SETGID, SETUID, SETFCAP, SETPCAP, # NET_BIND_SERVICE, SYS_CHROOT, KILL, AUDIT_WRITE Common capability patterns Web server (needs port 80/443): ...

February 12, 2026 · 3 min · 524 words · Guillaume Lours