Dokploy / Dokploy/dokploy

Docker source: "Login Succeeded" then "pull access denied" — Registry URL never reaches the image name

Open
#5,469 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

needs-triage🔍
Dominant language
TypeScript
Stars
37.4k
Forks
3k
Avg merge
1d 3h
Merged PRs (30d)
73

Description

To Reproduce
  1. Have a working private registry (e.g. registry.example.com, image published at
    registry.example.com/team/app:latest).
  2. Add it under Registry management and hit test — it succeeds.
  3. Create an application with source type Docker and fill the Docker Provider form:
    • Docker Image: app:latest
    • Registry URL: https://registry.example.com/team/
    • Username / Password: valid registry credentials
  4. Deploy.
Current vs. Expected behavior

Current — the deployment fails with two lines that contradict each other:

Pulling app:latest
Login Succeeded
Error response from daemon: pull access denied for app, repository does not exist or may require 'docker login'
❌ Pulling image failed

The login goes to the right registry; the pull goes to Docker Hub. buildRemoteDocker
(packages/server/src/utils/providers/docker.ts) uses the two fields in two different
commands:

const { registryUrl, dockerImage, username, password } = application;
echo `Pulling ${dockerImage}`;
safeDockerLoginCommand(registryUrl || "", username, password)   // registryUrl used here
docker pull ${quote([dockerImage])}                              // and nowhere else

registryUrl is never prepended to the image, so app:latest is resolved by Docker to
docker.io/library/app:latest. The error message confirms it — it names app with no
host; had the daemon contacted the private registry it would read
pull access denied for registry.example.com/team/app.

Expected — one of:

  • the deployment fails with a message that says the image needs the registry host, or
  • the Registry URL is composed into the image (see Additional context — I don't think
    this one is safe).

Either way, not a "Login Succeeded" immediately followed by an auth failure against a
registry that was never contacted.

Provide environment information
Operating System:
RockyLinux (sudo mode)
Which area(s) are affected? (Select all that apply)

Application

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

Remote server

Additional context

Why this is easy to hit. The UI suggests the short form: the Docker Image placeholder
is node:16 and the Registry URL field sits right next to it, which reads as "these two
get joined". Nothing validates the pair, and the failure mode is a confident wrong answer
rather than a visible error.

The product uses both conventions. On the push side Dokploy does compose
(packages/server/src/utils/cluster/upload.ts, getRegistryTag):

return finalRegistry ? `${finalRegistry}/${targetPrefix}/${repositoryName}` : ...

Same two fields, opposite contract, no indication in the UI which one you're in.

This is not a regression. I walked git log -p --follow on providers/docker.ts back
to the initial commit: docker pull ${dockerImage} has been verbatim throughout. The only
changes to that line are log plumbing (a05b75fc6), the error branch (0d3c978aa) and
shell-quoting (cba0b253c, whose own test pins that a legitimate reference round-trips
unchanged). The now-deleted local path pullImage did the same thing with spawnAsync.
So it has never worked this way — it is a long-standing UX trap, not something that broke.

Second, quieter issue. getAuthConfig (packages/server/src/utils/builders/index.ts)
puts registryUrl straight into AuthConfig.serveraddress, which Swarm matches against
the registry host of the image on the target node. A pasted https://registry.example.com/team/
carries a scheme and a path where a host is expected, so the node-side pull can 401 even
after the build-server pull succeeds. Note the service is created against
application.serverId, not the build server — so these are two different machines.

On auto-composition. It looks like the obvious fix but I don't think it is safe: someone
with a private Registry URL who sets Docker Image to nginx:latest (a public Hub image)
works today and would break. Happy to implement it if maintainers prefer it, but the PR I'm
opening reports the mismatch instead of rewriting the image.

Will you send a PR to fix it?

Yes

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in packages/server/src/utils/providers/docker.ts at buildRemoteDocker and trace how registryUrl and dockerImage are passed to login and pull. Compare that flow with getRegistryTag in packages/server/src/utils/cluster/upload.ts and getAuthConfig in packages/server/src/utils/builders/index.ts. Reproduce the private-registry deployment, then make the chosen behavior explicit and verify that both build-server and target-node pulls use consistent registry addressing.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, typescript
Domain
devops
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.