Docker entrypoint gosu bind mount
Skill kjuhwa/skills-hub/skills/docker/docker-entrypoint-gosu-bind-mount
Write a Docker ENTRYPOINT that `mkdir -p`s required subdirs on first run, `chown`s them, then drops from root to a non-root user with `gosu` — so bind mounts "just work" and named volumes keep their inherited perms.From its SKILL.md
npx -y skills add kjuhwa/skills-hub --skill docker-entrypoint-gosu-bind-mountAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
5.3 KB, ~1.3k tokens by cl100k_base, as published. Nobody here has run it
Docker ENTRYPOINT: mkdir -p Subdirs + gosu Drop to Non-Root
When to use
- You ship a Docker image that expects a persistent data directory (e.g.
/.archon/) and users mount it via either named volume or bind mount.- Named volumes inherit the image-layer's perms/ownership on first use — fine.
- Bind mounts do not — they start with whatever perms the host directory has. Subdirs that the image baked in are gone, and your container's non-root user typically can't write them.
- A naive fix "run container as root" is a security regression. Tools like Claude Code explicitly refuse to run as root with
--dangerously-skip-permissions. - You want one image that boots correctly under both mount styles, for root and non-root container invocations.
Steps
-
Install
gosuin the image (Debian-based:apt-get install -y gosu). It's a minimal setuid-like helper that drops privileges cleanly — unlikesu/sudo, it doesn't fork a subshell or interfere with signals. -
Write
docker-entrypoint.shthat (in order):set -efor strict error handling.mkdir -pevery subdirectory your app needs inside the mount point. This is the whole point — named volumes copy these from the image, bind mounts don't.- Detect whether we're root:
if [ "$(id -u)" = "0" ]. If yes:chown -Rh <user>:<user> /mount(with a clear error message on failure: "volume may be read-only or mounted with incompatible options";exit 1).- Set
RUNNER="gosu appuser".
- Otherwise (already non-root via
--useror K8ssecurityContext):- Set
RUNNER="".
- Set
-
Do any auth / setup steps as the target user via
$RUNNER:$RUNNER git config --global …— configure git as appuser if you need per-user settings.$RUNNER bun run setup-auth— run one-shot auth setup.
-
exec $RUNNER <main-command>— theexecreplaces the shell so the main process becomes PID 1 and receives SIGTERM directly, enabling graceful shutdown. Withoutexec, the shell swallows signals. -
Handle CRLF on Windows hosts.
COPY docker-entrypoint.sh /usr/local/bin/followed byRUN sed -i 's/\r$//' /usr/local/bin/docker-entrypoint.sh && chmod +x. This prevents/bin/bash^M: bad interpretererrors when the repo is cloned on Windows withoutcore.autocrlf=input. -
Pre-configure
safe.directoryfor git operations if the mount will contain git repos owned by a different UID than the container user. Example:RUN gosu appuser git config --global --add safe.directory '/.archon/workspaces' \ && gosu appuser git config --global --add safe.directory '/.archon/workspaces/*' \ && gosu appuser git config --global --add safe.directory '/.archon/worktrees' \ && gosu appuser git config --global --add safe.directory '/.archon/worktrees/*'This prevents "fatal: detected dubious ownership" errors when bind mounts have non-appuser UIDs.
-
Use a credential helper for tokens, not
~/.gitconfig. Archon embeds a bash function soGH_TOKENstays in env, never in a file:$RUNNER git config --global credential."https://github.com".helper \ '!f() { echo "username=x-access-token"; echo "password=${GH_TOKEN}"; }; f'
Counter / Caveats
- Don't
chownevery file on the volume —-Ron a large mount (many GB) adds seconds to boot.-Rhfollows no symlinks, which is usually what you want. If boot time matters, chown only the known subdirs youmkdired. gosuis notsuand notsudo. It doesn't run PAM, doesn't spawn a login shell, doesn't alter env vars. That's the feature, not a bug.- If you want the container to run fully read-only (
docker run --read-only), the entrypoint'smkdir -pneeds a writable subdirectory (tmpfs mount on/mount/tmp), or you need to pre-create everything in the image and skip the chown step. - When running in Kubernetes with
securityContext.fsGroup, the cluster may already fix ownership on bind-equivalent mounts, making your chown redundant but not harmful. Keep the check for portability. - Don't call
chown -Rwhen the mount might be read-only (ConfigMap / secrets volume). Guard withif ! chown … 2>/dev/nulland exit with a clear message.
Evidence
docker-entrypoint.sh(32 lines): full script withset -e,mkdir -p, root-detect +chown -Rh,RUNNER=""fallback, credential-helper-as-bash-function for GH_TOKEN,exec $RUNNER.Dockerfile:gosuin system install at line 67-77.- Non-root user creation + data-dir perms at lines 119-126.
safe.directorypre-configuration at lines 175-179.- CRLF strip at lines 182-185.
- Commit SHA: d89bc767d291f52687beea91c9fcf155459be0d9.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.