This error occurs when Docker cannot establish a TCP connection to a container registry. The registry service may not be running, the port may be incorrect, or network/firewall rules are blocking the connection.
The "connection refused" error when connecting to a Docker registry indicates that your Docker client is attempting to reach a registry server, but the TCP connection is being actively refused. This means either nothing is listening on the specified port, or a firewall is blocking the connection at the network level. This error commonly appears in several scenarios: - **Private registries**: When connecting to a self-hosted registry like Harbor, Nexus, or the official Docker Registry image - **Local development**: When pushing/pulling from a local registry running on localhost:5000 - **CI/CD pipelines**: When the registry service container hasn't fully started yet - **BuildKit builds**: When using `docker buildx` to push to a local registry with different network contexts The URL in the error message (e.g., `https://myregistry:5000/v2/`) reveals the registry hostname, port, and protocol being used. The `/v2/` path is the Docker Registry HTTP API endpoint that clients use to check registry availability.
First, check if your registry container is actually running:
# List running containers
docker ps | grep registry
# Check all containers (including stopped)
docker ps -a | grep registryIf the registry is stopped, check the logs for errors:
docker logs registryStart or restart the registry if needed:
# If stopped
docker start registry
# If not created, start a basic local registry
docker run -d --restart=always -p 5000:5000 --name registry registry:2Verify the registry is listening on the expected port:
Check container port mapping:
docker port registry
# Should show: 5000/tcp -> 0.0.0.0:5000Verify port is listening on host:
# Linux
ss -tlnp | grep 5000
netstat -tlnp | grep 5000
# macOS
lsof -i :5000
# Windows
netstat -ano | findstr 5000Test connectivity:
# Check if registry responds
curl -v http://localhost:5000/v2/
# Expected response: {"repositories":[]} or similarIf the port isn't mapped, recreate the registry with correct port binding:
docker rm -f registry
docker run -d --restart=always -p 5000:5000 --name registry registry:2The hostname you use depends on where Docker commands run:
From host machine:
# Use localhost
docker tag myimage localhost:5000/myimage
docker push localhost:5000/myimageFrom another container (e.g., in CI/CD):
# Use the registry container name or Docker network hostname
docker tag myimage registry:5000/myimage
docker push registry:5000/myimage
# Or use host.docker.internal (Docker Desktop)
docker tag myimage host.docker.internal:5000/myimage
docker push host.docker.internal:5000/myimageIn Docker Compose:
services:
registry:
image: registry:2
ports:
- "5000:5000"
builder:
image: docker:latest
environment:
# Use service name as hostname
REGISTRY_HOST: registry:5000
depends_on:
- registryIf your registry uses HTTP instead of HTTPS, Docker requires explicit configuration:
Docker Desktop (Windows/macOS):
1. Open Docker Desktop Settings
2. Go to Docker Engine
3. Add your registry to the insecure-registries list:
{
"insecure-registries": ["myregistry:5000", "localhost:5000"]
}4. Click "Apply & Restart"
Linux - Edit daemon.json:
sudo tee /etc/docker/daemon.json << EOF
{
"insecure-registries": ["myregistry:5000", "localhost:5000"]
}
EOF
sudo systemctl restart dockerVerify configuration:
docker info | grep -A5 "Insecure Registries"Note: "Insecure" here refers to HTTP (not HTTPS), not to authentication. For production, always use HTTPS.
BuildKit (used by docker buildx) runs in a separate context and may not reach localhost registries:
Problem: BuildKit container can't reach localhost:5000 because localhost refers to the BuildKit container, not the host.
Solution 1: Use host network mode for buildx:
docker buildx create --name hostbuilder --driver docker-container --driver-opt network=host
docker buildx use hostbuilder
docker buildx build --push -t localhost:5000/myimage .Solution 2: Use host.docker.internal (Docker Desktop):
docker buildx build --push -t host.docker.internal:5000/myimage .Solution 3: Put registry and buildx on same Docker network:
# Create network
docker network create buildnet
# Start registry on network
docker run -d --name registry --network buildnet -p 5000:5000 registry:2
# Create buildx builder on same network
docker buildx create --name netbuilder --driver docker-container --driver-opt network=buildnet
docker buildx use netbuilder
# Push using registry container name
docker buildx build --push -t registry:5000/myimage .Registry containers need time to initialize. Add a wait step in CI/CD:
GitLab CI example:
services:
- name: registry:2
alias: registry
variables:
REGISTRY_HOST: registry:5000
build:
script:
# Wait for registry to be ready
- |
echo "Waiting for registry..."
timeout 30 sh -c 'until curl -sf http://registry:5000/v2/; do sleep 1; done'
echo "Registry is ready!"
- docker build -t $REGISTRY_HOST/myimage .
- docker push $REGISTRY_HOST/myimageGitHub Actions example:
services:
registry:
image: registry:2
ports:
- 5000:5000
steps:
- name: Wait for registry
run: |
timeout 30 sh -c 'until curl -sf http://localhost:5000/v2/; do sleep 1; done'
- name: Build and push
run: |
docker build -t localhost:5000/myimage .
docker push localhost:5000/myimageFirewall rules may block registry port:
Linux with UFW:
# Check status
sudo ufw status
# Allow port 5000
sudo ufw allow 5000/tcpLinux with firewalld:
# Check ports
sudo firewall-cmd --list-ports
# Allow port 5000
sudo firewall-cmd --permanent --add-port=5000/tcp
sudo firewall-cmd --reloadCheck Docker network connectivity:
# List networks
docker network ls
# Inspect network
docker network inspect bridge
# Test connectivity from a container
docker run --rm curlimages/curl curl -v http://host.docker.internal:5000/v2/Windows firewall:
# Check if port is allowed
Get-NetFirewallRule | Where-Object {$_.LocalPort -eq 5000}
# Add rule
New-NetFirewallRule -DisplayName "Docker Registry" -Direction Inbound -LocalPort 5000 -Protocol TCP -Action AllowIf the registry container keeps crashing or becomes unresponsive:
Check container logs:
docker logs registry --tail 100
docker logs registry -f # Follow logsCommon registry issues and fixes:
Storage issues:
# Check disk space in registry
docker exec registry df -h /var/lib/registry
# If full, prune old images (WARNING: removes unused images)
docker exec registry bin/registry garbage-collect /etc/docker/registry/config.ymlConfiguration problems:
# Check registry config
docker exec registry cat /etc/docker/registry/config.yml
# Start with verbose logging
docker run -d -p 5000:5000 --name registry \
-e REGISTRY_LOG_LEVEL=debug \
registry:2Memory issues:
# Check container stats
docker stats registry --no-stream
# Restart with memory limit
docker run -d -p 5000:5000 --name registry \
--memory=512m \
registry:2Understanding Docker Registry networking:
When working with registries, network context matters greatly:
- Host context: Commands run directly on the host can use localhost:5000
- Container context: Commands run inside containers must use container names, bridge IPs, or host.docker.internal
- BuildKit context: BuildKit runs in its own container and needs special network configuration
Registry authentication and TLS:
For production registries, always configure TLS and authentication:
# Generate self-signed certificate
mkdir -p certs
openssl req -newkey rsa:4096 -nodes -sha256 \
-keyout certs/domain.key -x509 -days 365 \
-out certs/domain.crt \
-subj "/CN=myregistry" \
-addext "subjectAltName=DNS:myregistry,IP:192.168.1.100"
# Start registry with TLS
docker run -d -p 5000:5000 --name registry \
-v $(pwd)/certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
registry:2
# Configure Docker to trust the certificate
sudo mkdir -p /etc/docker/certs.d/myregistry:5000
sudo cp certs/domain.crt /etc/docker/certs.d/myregistry:5000/ca.crtUsing Docker registry mirror:
For air-gapped or slow network environments, configure registry as a pull-through cache:
# config.yml for registry
version: 0.1
proxy:
remoteurl: https://registry-1.docker.io
storage:
filesystem:
rootdirectory: /var/lib/registrydocker run -d -p 5000:5000 --name mirror \
-v $(pwd)/config.yml:/etc/docker/registry/config.yml \
registry:2Debugging with Docker events:
Monitor Docker daemon events to see connection attempts:
docker events --filter 'type=image' &
docker push myregistry:5000/testAlternative registries with built-in UI:
If you frequently have registry issues, consider registries with web interfaces for easier debugging:
- Harbor (enterprise features, vulnerability scanning)
- Nexus Repository (supports multiple package formats)
- GitLab Container Registry (integrated with GitLab CI)
- Portus (open source UI for Docker Registry)
Error response from daemon: client version X.XX is too new. Maximum supported API version is X.XX
How to fix 'client version is too new' in Docker
dial tcp: i/o timeout
How to fix 'dial tcp: i/o timeout' in Docker
image operating system "linux" cannot be used on this platform
How to fix 'image operating system linux cannot be used on this platform' in Docker
manifest unknown: manifest unknown
How to fix 'manifest unknown' in Docker
cannot open '/etc/passwd': Permission denied
How to fix 'cannot open: Permission denied' in Docker