Docker source: "Login Succeeded" then "pull access denied" — Registry URL never reaches the image name
To Reproduce
- Have a working private registry (e.g.
registry.example.com, image published atregistry.example.com/team/app:latest). - Add it under Registry management and hit test — it succeeds.
- 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
- Docker Image:
- 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 failedThe 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 elseregistryUrl 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
Source: Dokploy/dokploy