Skip to content

docker stack deploy --with-registry-auth cannot read registry credentials because env -i strips HOME #4401

Closed

Description

@leogomide

To Reproduce

To Reproduce

Disclosure: the diagnosis, root-cause analysis, suggested fix, and the linked references in this report were produced by Claude Code (Anthropic's CLI coding assistant) — not by me. I observed the symptom on my own deploy, ran the AI to investigate, reviewed the output, and am forwarding it here because the analysis matches what I see and points at concrete files and PRs in this repo. Maintainers should re-verify the code references before acting; I have not independently audited every line cited.

  1. In the Dokploy UI, go to Registry and add a private registry with credentials. Dokploy runs docker login internally and writes the auth entry to /root/.docker/config.json on the host.

  2. Push at least one image to that registry from outside Dokploy (e.g., from a CI pipeline).

  3. In the Dokploy UI, create a new application with:

    • Source Type: any source that points to a repo containing a stack file.
    • Compose Type: Stack (Swarm), not Compose.
  4. Point the application to a stack file that references the private image, for example:

    services:
      web:
        image: registry.example.com/my-org/my-app:latest
        deploy:
          replicas: 1
  5. Click Deploy.

  6. After the deploy command finishes, on the host run:

    docker stack services <stack-name>
    docker stack ps <stack-name> --no-trunc

    to inspect the task state.

Current vs. Expected behavior

Current vs. Expected behavior

Expected: the manager pulls the image manifest from the registry using the credentials saved by Dokploy's docker login, records the digest in the service spec, propagates valid auth to workers via --with-registry-auth, and the service tasks reach running.

Actual: the deploy log prints

image registry.example.com/my-org/my-app:latest could not be accessed
on a registry to record its digest. Each node will access
registry.example.com/my-org/my-app:latest independently, possibly
leading to different nodes running different versions of the image.

Docker Compose Deployed: ✅

docker stack services shows 0/1 replicas, and docker stack ps --no-trunc reveals the tasks failing to pull (No such image / auth errors) even though:

  • The registry is reachable from the host.
  • The credentials in Dokploy → Registry are correct.
  • /root/.docker/config.json on the host contains a valid entry for the registry.
  • Switching the same application to Compose type (same image, same registry, same credentials) deploys and runs successfully.

Root cause

In packages/server/src/utils/builders/compose.ts, the deploy command is wrapped in:

env -i PATH="$PATH" ${exportEnvCommand} docker ${command.split(" ").join(" ")}

env -i strips all environment variables, including HOME. Only PATH and the project-scoped vars produced by exportEnvCommand survive — HOME is not re-exported.

With an empty HOME, the Docker CLI expands ~/.docker/config.json to /.docker/config.json instead of /root/.docker/config.json. That path does not exist, so the CLI silently falls back to anonymous access. The manager cannot resolve the image digest, and the auth payload that --with-registry-auth ships to workers is empty.

This bug is invisible in Compose mode because Dokploy writes DOCKER_CONFIG=/root/.docker into the project's .env file, which docker compose reads. docker stack deploy does not consume the project .env for its own auth resolution, so the same workaround does not apply.

The env -i was introduced by #3062. --with-registry-auth was later added to the stack deploy command by #3341, but the interaction with #3062 was not caught.

Provide environment information

## Provide environment information


Operating System:
  OS: <fill in — e.g., Ubuntu 24.04>
  Arch: <fill in — e.g., x86_64>
Dokploy version: <fill in — check the UI footer>
VPS Provider: <fill in>
What applications/services are you trying to deploy?
  A multi-service Node.js stack (Fastify API + Next.js web + cron worker + one-shot Prisma migration) pulled from a self-hosted Zot registry behind Traefik with TLS.

Which area(s) are affected? (Select all that apply)

Docker Compose, Docker

Are you deploying the applications where Dokploy is installed or on a remote server?

Same server where Dokploy is installed

Additional context

Additional context

Suggested fix

Preserve HOME (and optionally DOCKER_CONFIG) across the env -i boundary so the Docker CLI can locate ~/.docker/config.json:

- env -i PATH="$PATH" ${exportEnvCommand} docker ${command.split(" ").join(" ")}
+ env -i HOME="$HOME" DOCKER_CONFIG="${DOCKER_CONFIG:-$HOME/.docker}" PATH="$PATH" ${exportEnvCommand} docker ${command.split(" ").join(" ")}

This single-line change:

  • Restores correct expansion of ~/.docker/config.json for the Docker CLI.
  • Honors an explicit DOCKER_CONFIG override if set by the operator.
  • Has no side effects on Compose mode (the existing .env injection of DOCKER_CONFIG keeps working).

Workaround (for users hitting this today)

On the Swarm manager host:

mkdir -p /.docker
cp /root/.docker/config.json /.docker/config.json

Because HOME is empty inside env -i, ~ resolves to / and the CLI now finds /.docker/config.json. After this, redeploy from the Dokploy UI — docker stack deploy --with-registry-auth will pick up the credentials, record the digest, and propagate valid auth to workers. This is a single-node workaround; on a multi-node cluster the credentials would need to exist on every worker, or --with-registry-auth needs to function correctly (which is what the fix above restores).

Related issues and PRs

Code references

  • packages/server/src/utils/builders/compose.ts — the bash command that runs docker stack deploy (where env -i lives).
  • packages/server/src/services/registry.ts — where Dokploy's docker login runs and writes credentials to /root/.docker/config.json.

Will you send a PR to fix it?

No

Activity

  1. dosubot commented on May 13, 2026

    @dosubot

    Hi @leogomide! I'm Dosu and I’m helping the dokploy team.

    I can confirm this analysis is accurate. The env -i wrapper on line 57 of packages/server/src/utils/builders/compose.ts only preserves PATH and the export env command variables — HOME is not included [1]:

    env -i PATH="$PATH" ${exportEnvCommand} docker ${command.split(" ").join(" ")} 2>&1 || { echo "Error: ❌ Docker command failed"; exit 1; }

    And the stack deploy command on line 93 does include --with-registry-auth [2]:

    command = `stack deploy -c ${path} ${appName} --prune --with-registry-auth`;

    No existing PR has addressed preserving HOME in the env -i wrapper. The PRs that touched this area — #3062 [3], #3071 [4], and #3341 [5] — improved environment handling and added --with-registry-auth but didn't account for the interaction between env -i stripping HOME and Docker needing it to resolve ~/.docker/config.json.

    The suggested fix of adding HOME="$HOME" to the env -i line looks correct and minimal. Adding DOCKER_CONFIG as a fallback is a nice bonus for operators who override the config location, though HOME alone should be sufficient for the default setup.

    To reply, just mention @dosu.


    Docs are dead. Just use Dosu.

    Leave Feedback Ask Dosu about dokploy Share Dosu with your team

  2. added a commit that references this issue on May 30, 2026
    85211af
  3. added a commit that references this issue on May 30, 2026
    30b3e1f
  4. added a commit that references this issue on Jun 8, 2026
    b3c2e1e
  5. added a commit that references this issue on Aug 23, 2026
    22853b1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions