Push an image to a private Docker registry
Authenticate, tag the intended destination, push and verify the digest, and troubleshoot registry trust and authorization.
Log in to the registry, add a fully qualified repository tag, then push that tag. The image reference determines the destination; logging in does not redirect an unqualified image name to that registry.
docker login registry.example.com
docker tag myapp:1.2 registry.example.com/team/myapp:1.2
docker push registry.example.com/team/myapp:1.2
Use an account or token authorized to push to the intended project. In Harbor, the project usually needs to exist before the push. Cloud registries may require provider-issued credentials with a limited lifetime.
Understand the reference
Adding a tag creates another local reference to the same image; it does not duplicate all its layers or remove the old tag. For a reference with a slash, a first component containing a dot or colon, or equal to localhost, identifies a registry host. An unqualified name such as myapp:1.2 normally targets Docker Hub instead.
After pushing, record the reported digest and inspect the registry entry. Pull the exact repository reference from the intended target environment when checking access. A successful login proves authentication, not push permission, pull permission for every account, or deployment readiness.
Troubleshoot the failure
| Failure | What to check |
|---|---|
| Authentication required | Registry hostname, credential helper, token validity and login account |
| Access denied | Project/repository scope, robot-account permissions and policy |
| Repository unknown | Correct repository path and required project creation |
| HTTP response to HTTPS client | Wrong endpoint or a registry serving plain HTTP |
| Certificate verification failure | Certificate chain, hostname and trusted private CA |
For a registry using a private CA, install the approved CA for Docker rather than disabling verification. On Linux Engine, Docker documents registry-specific trust under /etc/docker/certs.d/<host[:port]>/ca.crt; Docker Desktop has its own certificate integration. Preserve existing daemon configuration when changing trust settings.
An insecure-registries exception allows behavior that weakens transport trust. It is an explicit controlled-environment exception, not the standard remedy for a private certificate. Prefer configuring HTTPS and the correct CA, including on internal networks.
Push from CI
Provide the token through the CI secret mechanism, avoid shell tracing, and use standard input:
set -eu
: "${REGISTRY_TOKEN:?Supply the CI registry token}"
: "${CI_COMMIT_SHORT_SHA:?Supply a commit identifier}"
printf '%s' "$REGISTRY_TOKEN" | docker login registry.example.com \
--username ci-bot --password-stdin
docker tag myapp:build "registry.example.com/team/myapp:${CI_COMMIT_SHORT_SHA}"
docker push "registry.example.com/team/myapp:${CI_COMMIT_SHORT_SHA}"
This assumes myapp:build was built earlier in the job. A commit tag is useful traceability, but tags remain movable unless the registry enforces immutability; the digest identifies the pushed content. Configure a credential helper where available, since fallback credentials in Docker's config file are encoded, not encrypted.
FAQ
Why is pushing slow? Investigate network throughput, image size and layers. Registries can reuse blobs they already have. Multi-stage builds and removing unnecessary build artifacts can reduce transfer work.
Can the same image go to several registries? Yes. Add each destination tag and push it independently.
Can Harbor block a pull immediately after a successful push? Authorization, scanning policy, quarantine or replication state can affect availability. Check the project's actual policy instead of assuming every pushed artifact is immediately deployable.
See Registry authentication, Image tags and repository names, Docker registry certificate trust.
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan