From 0ff950c62cd2507f1a947aa26a56135de6839a0d Mon Sep 17 00:00:00 2001 From: Alexandr Yepishev Date: Fri, 19 Jun 2026 16:33:30 +0100 Subject: [PATCH] Set deterministic 14933:14933 user in prod Docker images --- .changeset/tiny-buckets-notice.md | 5 +++++ core/chainlink.Dockerfile | 7 ++++++- core/config/docs/core.toml | 5 +++++ docs/CONFIG.md | 8 ++++++++ plugins/chainlink.Dockerfile | 6 +++++- 5 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 .changeset/tiny-buckets-notice.md diff --git a/.changeset/tiny-buckets-notice.md b/.changeset/tiny-buckets-notice.md new file mode 100644 index 00000000000..a1421f9ded0 --- /dev/null +++ b/.changeset/tiny-buckets-notice.md @@ -0,0 +1,5 @@ +--- +"chainlink": minor +--- + +#nops: Hard-set UID and GID when CHAINLINK_USER is non-root, and document container RootDir and safe volume mount conventions for operators. diff --git a/core/chainlink.Dockerfile b/core/chainlink.Dockerfile index 9b18c1c4ede..1cc14f0f038 100644 --- a/core/chainlink.Dockerfile +++ b/core/chainlink.Dockerfile @@ -113,7 +113,12 @@ RUN curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc \ && apt-get update && apt-get install -y postgresql-client-17 \ && rm -rf /var/lib/apt/lists/* -RUN if [ ${CHAINLINK_USER} != root ]; then useradd --uid 14933 --create-home ${CHAINLINK_USER}; fi +# Prod images (CHAINLINK_USER=chainlink) run as UID:GID 14933:14933 for deterministic +# ownership on bind mounts in Docker/Compose deployments without K8s securityContext overrides. +RUN if [ ${CHAINLINK_USER} != root ]; then \ + groupadd --gid 14933 ${CHAINLINK_USER} && \ + useradd --uid 14933 --gid 14933 --create-home ${CHAINLINK_USER}; \ + fi USER ${CHAINLINK_USER} # Expose image metadata to the running node. diff --git a/core/config/docs/core.toml b/core/config/docs/core.toml index f37e63fd41a..bcebd95304d 100644 --- a/core/config/docs/core.toml +++ b/core/config/docs/core.toml @@ -6,6 +6,11 @@ InsecureFastScrypt = false # Default # Deprecated: no effect. Always enabled. InsecurePPROFHeap = true # Default # RootDir is the Chainlink node's root directory. This is the default directory for logging, database backups, cookies, and other misc Chainlink node files. Chainlink nodes will always ensure this directory has 700 permissions because it might contain sensitive data. +# +# Container deployments: official prod Docker images run as UID:GID 14933:14933 (user `chainlink`). Bind mounts must be owned 14933:14933, or use named volumes with an appropriate fsGroup in Kubernetes. A non-deterministic GID mismatch is a common cause of read/write errors on bind mounts in Docker/Compose. +# RootDir in containers: both '/home/chainlink' and '~/.chainlink' (which resolves to '/home/chainlink/.chainlink') are valid. Choose one and align any persistence mounts to that path. '/home/chainlink' is often preferred because '.chainlink' is hidden by default. +# Volume mounts: ensure you do not bind-mount over '/home/chainlink' — it replaces the entire home directory, hides image-created paths such as '.cache', and causes permission failures. +# Mount config and secrets at separate paths (e.g. '/run/secrets/config.toml', '/configs/...') and pass them via CLI flags ('-c', '-s', '-a', '-p'). Subdirectory mounts under home (e.g. '/home/chainlink/workflows') are acceptable when permissions match 14933:14933. RootDir = '~/.chainlink' # Default # ShutdownGracePeriod is the maximum time allowed to shut down gracefully. If exceeded, the node will terminate immediately to avoid being SIGKILLed. ShutdownGracePeriod = '5s' # Default diff --git a/docs/CONFIG.md b/docs/CONFIG.md index d283f2faf4a..db2207dee18 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -48,6 +48,14 @@ RootDir = '~/.chainlink' # Default ``` RootDir is the Chainlink node's root directory. This is the default directory for logging, database backups, cookies, and other misc Chainlink node files. Chainlink nodes will always ensure this directory has 700 permissions because it might contain sensitive data. +Official prod Docker images run as UID:GID 14933:14933 (user `chainlink`). A non-deterministic GID mismatch is a common cause of read/write errors on bind mounts in Docker/Compose. + +RootDir '/home/chainlink' and '~/.chainlink' (which resolves to +'/home/chainlink/.chainlink') are valid. Choose one and align any persistence mounts to that path. '/home/chainlink' is often preferred because '.chainlink' is hidden by default. + +Do not bind-mount over '/home/chainlink' — it replaces the entire home directory and causes permission failures. Mount config and secrets at separate paths (e.g. '/run/secrets/config.toml', '/configs/...') and pass them via CLI flags +('-c', '-s', '-a', '-p'). + ### ShutdownGracePeriod ```toml ShutdownGracePeriod = '5s' # Default diff --git a/plugins/chainlink.Dockerfile b/plugins/chainlink.Dockerfile index 855e6c99e06..676f5b52a8c 100644 --- a/plugins/chainlink.Dockerfile +++ b/plugins/chainlink.Dockerfile @@ -113,7 +113,11 @@ RUN curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc \ && apt-get update && apt-get install -y postgresql-client-17 \ && rm -rf /var/lib/apt/lists/* -RUN if [ ${CHAINLINK_USER} != root ]; then useradd --uid 14933 --create-home ${CHAINLINK_USER}; fi +# Prod images (CHAINLINK_USER=chainlink) run as UID:GID 14933:14933 for deterministic ownership. +RUN if [ ${CHAINLINK_USER} != root ]; then \ + groupadd --gid 14933 ${CHAINLINK_USER} && \ + useradd --uid 14933 --gid 14933 --create-home ${CHAINLINK_USER}; \ + fi USER ${CHAINLINK_USER} # Expose image metadata to the running node.