Skip to content
HostStack Docs

What Your Container Runs As

Your container runs as root, with a read-only root filesystem, and with most Linux capabilities dropped. That last one is the surprising part: your container runs as root, but root is not root for file permissions here.

Reproduce it locally

If your image works on your machine but fails on HostStack, run it with these flags first. This is the sandbox, in one command:

docker run --rm -it \
  --read-only --tmpfs /tmp --tmpfs /var/tmp \
  --cap-drop ALL \
  --cap-add CHOWN --cap-add SETGID --cap-add SETUID --cap-add NET_BIND_SERVICE \
  --security-opt no-new-privileges \
  -e PORT=3000 -p 3000:3000 \
  your-image

Anything that fails under that command will fail on HostStack, and anything that passes will run. Debugging it locally is far faster than debugging it a deploy at a time.

The capability set

All capabilities are dropped, then four are added back — enough for the standard entrypoint patterns (a chown of the app dir, a gosu/su-exec privilege drop, binding :80/:443):

granted:  CHOWN  SETGID  SETUID  NET_BIND_SERVICE
dropped:  everything else — notably DAC_OVERRIDE and FOWNER

DAC_OVERRIDE is what normally lets root ignore file permission bits, and FOWNER is what lets root chmod a file it doesn't own. Without them, root can only write where it owns the directory and can only chmod files it owns. id -u still prints 0, which is why this is so easy to misread.

Errors this produces

None of these messages mention capabilities. All of them are the missing DAC_OVERRIDE/FOWNER:

  • A chown succeeds and the chmod on the very next line fails with Operation not permitted — under set -e your entrypoint dies one line after doing the work correctly.
  • file_put_contents(): Failed to open stream: Permission denied on a file the same script just wrote.
  • cp -a into a directory the script itself created, denied.
  • tail on the process's own log file, denied.
  • Writes anywhere outside /tmp, /var/tmp, and your mounted volumes failing with Read-only file system.

The fix is almost always the same: create files as the user that will read them rather than fixing up permissions afterwards, and write only to /tmp or a persistent volume.

Where you can write

  • /tmp and /var/tmp — tmpfs, writable, noexec, and wiped on every restart. Free; no provisioning needed.
  • Any persistent volume you attach — writable and durable across restarts and deploys.
  • Nothing else. The rest of the filesystem is read-only, including your application directory.

Other limits

no-new-privileges     setuid binaries cannot escalate
seccomp               a restricted syscall profile is applied
pids limit            capped per container
nofile / nproc        ulimits are capped per container
network               your service reaches the internet and its own
                      project's services; inbound arrives via the edge only

Binding the port

Bind the port in $PORT, on 0.0.0.0 — not 127.0.0.1. A container listening only on loopback is unreachable from the edge and will fail its readiness probe with the container never answered. See Health Checks.

Essential cookies only — for login sessions. No tracking. Details