The 'Client.Timeout exceeded' error occurs when Docker cannot complete a connection to a registry (Docker Hub, private registry, or self-hosted) within the default timeout period. This is typically caused by network connectivity issues, proxy misconfigurations, DNS problems, firewall restrictions, or the registry being unreachable.
Fixes Error response from daemon: Get https://myregistry:5000/v2/: net/http: request canceled (Client.Timeout exceeded)
# For a private registry
curl -v https://myregistry:5000/v2/
# For Docker Hub
curl -v https://registry-1.docker.io/v2/
# Test DNS resolution
nslookup myregistry
# or
dig myregistry
# Test network connectivity
ping myregistry
telnet myregistry 5000# For a private registrycurl -v https://myregistry:5000/v2/# For Docker Hubcurl -v https://registry-1.docker.io/v2/# Test DNS resolutionnslookup myregistry# ordig myregistry# Test network connectivityping myregistrytelnet myregistry 5000Error response from daemon: Get https://myregistry:5000/v2/: net/http: request canceled (Client.Timeout exceeded)
The error message "Error response from daemon: Get https://myregistry:5000/v2/: net/http: request canceled (Client.Timeout exceeded)" indicates that Docker's HTTP client initiated a request to a container registry but did not receive a response within the allowed time limit. The request was automatically canceled after the timeout threshold was reached. This error can occur when connecting to any container registry, including: - Docker Hub (registry-1.docker.io) - Private registries (your own registry at a custom domain:port) - GitHub Container Registry (ghcr.io) - Amazon ECR, Google Container Registry, Azure Container Registry The timeout mechanism is a safety feature that prevents Docker commands from hanging indefinitely. However, when triggered unexpectedly, it usually points to one of these underlying issues: 1. **Network path issues**: The request never reaches the registry server due to firewall rules, routing problems, or the registry being down. 2. **Slow connections**: On low-bandwidth connections, large operations may exceed the timeout before completing. 3. **Proxy misconfiguration**: Corporate proxies that aren't properly configured for Docker traffic. 4. **DNS resolution failures**: The registry hostname cannot be resolved to an IP address. 5. **TLS/SSL handshake problems**: Certificate issues that cause the connection to stall. Unlike a "connection refused" error where the server actively rejects the connection, a timeout error means the connection attempt simply took too long with no response at all.
First, check if the registry is reachable from your host machine (outside of Docker):
# For a private registry
curl -v https://myregistry:5000/v2/
# For Docker Hub
curl -v https://registry-1.docker.io/v2/
# Test DNS resolution
nslookup myregistry
# or
dig myregistry
# Test network connectivity
ping myregistry
telnet myregistry 5000If curl works but Docker fails, the issue is likely Docker-specific configuration (proxy, DNS, or certificates). If curl also fails, the issue is at the network level.
Ensure your firewall allows outbound connections to the registry:
# Check if port is open (Linux)
sudo iptables -L -n | grep 5000
# For Docker Hub, ensure port 443 is open
sudo iptables -L -n | grep 443
# Test connection with nc (netcat)
nc -zv myregistry 5000
# On macOS, check Application Firewall
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstateCommon ports to allow:
- Port 443: Docker Hub, ghcr.io, and most cloud registries
- Port 5000: Default port for self-hosted Docker Registry
- Port 5001: Often used for registry authentication
If behind a corporate firewall, contact your IT team to whitelist the registry domain and port.
If you're behind a corporate proxy, Docker needs explicit configuration:
Linux (systemd):
# Create drop-in directory
sudo mkdir -p /etc/systemd/system/docker.service.d
# Create proxy configuration
sudo nano /etc/systemd/system/docker.service.d/http-proxy.confAdd your proxy settings:
[Service]
Environment="HTTP_PROXY=http://proxy.company.com:8080"
Environment="HTTPS_PROXY=http://proxy.company.com:8080"
Environment="NO_PROXY=localhost,127.0.0.1,myregistry,.company.internal"Reload and restart Docker:
sudo systemctl daemon-reload
sudo systemctl restart dockerDocker Desktop (Windows/Mac):
Go to Settings > Resources > Proxies and configure your proxy settings there.
Verify proxy is applied:
sudo systemctl show --property=Environment dockerDNS issues are a common cause of registry timeouts. Configure Docker to use reliable DNS servers:
# Edit Docker daemon configuration
sudo nano /etc/docker/daemon.jsonAdd DNS configuration:
{
"dns": ["8.8.8.8", "8.8.4.4", "1.1.1.1"]
}Restart Docker:
sudo systemctl restart dockerFor private registries, ensure the hostname is resolvable:
# Add to /etc/hosts if needed
echo "192.168.1.100 myregistry" | sudo tee -a /etc/hostsFor Docker Desktop: Go to Settings > Docker Engine and add the DNS configuration to the JSON editor.
If your private registry uses a self-signed certificate, Docker won't trust it by default. You have two options:
Option 1: Add certificate to Docker's trust store (recommended)
# Create certificate directory
sudo mkdir -p /etc/docker/certs.d/myregistry:5000
# Copy the registry's CA certificate
sudo cp ca.crt /etc/docker/certs.d/myregistry:5000/ca.crt
# Restart Docker
sudo systemctl restart dockerOption 2: Configure as insecure registry (not recommended for production)
sudo nano /etc/docker/daemon.jsonAdd:
{
"insecure-registries": ["myregistry:5000"]
}sudo systemctl restart dockerNote: Using insecure registries exposes you to man-in-the-middle attacks. Only use this for testing or isolated networks.
IPv6 can cause DNS resolution delays on some networks:
# Check if IPv6 is causing issues
curl -4 -v https://myregistry:5000/v2/ # Force IPv4
curl -6 -v https://myregistry:5000/v2/ # Force IPv6 (may fail)If IPv4 works but IPv6 fails, disable IPv6:
# Add to /etc/sysctl.conf
sudo nano /etc/sysctl.confAdd:
net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.default.disable_ipv6=1
net.ipv6.conf.lo.disable_ipv6=1Apply and restart Docker:
sudo sysctl --system
sudo systemctl restart dockerVPNs often interfere with Docker registry connections:
1. Test without VPN: Temporarily disconnect your VPN and try the Docker command again.
2. If it works without VPN, configure split tunneling to exclude registry traffic:
Most VPN clients allow you to exclude specific domains or IP ranges. Add these to your VPN's split tunnel configuration:
- Your private registry domain (myregistry)
- Docker Hub: registry-1.docker.io, auth.docker.io, production.cloudflare.docker.com
3. Alternative: Use VPN's internal DNS if your registry is inside the VPN network:
# Configure Docker to use VPN's DNS
sudo nano /etc/docker/daemon.json{
"dns": ["10.0.0.1"] // Your VPN's DNS server
}On slow or unstable connections, reduce the number of parallel operations:
sudo nano /etc/docker/daemon.jsonAdd:
{
"max-concurrent-downloads": 1,
"max-concurrent-uploads": 1
}sudo systemctl restart dockerThis reduces bandwidth usage per operation, making each individual request less likely to timeout. The default values are 3 for downloads and 5 for uploads.
For very slow connections, you can also try pulling during off-peak hours when network congestion is lower.
If the issue is intermittent, retry with additional debugging information:
# Enable Docker daemon debug mode
sudo nano /etc/docker/daemon.jsonAdd:
{
"debug": true
}sudo systemctl restart docker
# Watch Docker logs while running your command
sudo journalctl -u docker -f &
# Try your command
docker pull myregistry:5000/myimage:latestFor transient issues, implement retry logic:
# Retry script
for i in {1..5}; do
docker pull myregistry:5000/myimage:latest && break
echo "Attempt $i failed, waiting 10 seconds..."
sleep 10
doneDon't forget to disable debug mode after troubleshooting:
{
"debug": false
}### Understanding Docker's Timeout Behavior
Docker uses Go's net/http client for registry communication. The default timeout is typically 30 seconds for most operations. When this error occurs, it means:
1. The TCP connection was established (or attempted)
2. The HTTP request was sent
3. No response headers were received within the timeout period
The full error pattern is:
Error response from daemon: Get "https://myregistry:5000/v2/": net/http: request canceled (Client.Timeout exceeded while awaiting headers)### WSL2 and Windows-Specific Issues
When using Docker Desktop with WSL2:
- Docker runs inside a WSL2 VM, which has its own network stack
- Hosts file entries must be in the Windows hosts file (C:\Windows\System32\drivers\etc\hosts), not WSL's /etc/hosts
- DNS resolution uses the Windows DNS client
Windows network adapter issues:
1. Open Network Connections (ncpa.cpl)
2. Find "vEthernet (WSL)" or "vEthernet (DockerNAT)"
3. Right-click > Properties > IPv4 > Properties
4. Set DNS to 8.8.8.8 and 8.8.4.4
### Private Registry Best Practices
For self-hosted registries, ensure:
1. Proper TLS configuration: Use certificates from a trusted CA or properly distribute your CA certificate to all Docker clients.
2. Health checks: Configure load balancers with appropriate health check endpoints (/v2/ returns 200 OK for healthy registries).
3. Timeout tuning on registry side: If your registry is under heavy load, increase its own timeout settings:
# Registry config.yml
http:
addr: :5000
net: tcp
relativeurls: false
draintimeout: 60s4. Dedicated network: Place the registry on a stable, low-latency network path.
### CI/CD Pipeline Considerations
In CI/CD environments (GitHub Actions, GitLab CI, Jenkins), this error often indicates:
- Rate limiting: Too many unauthenticated pulls
- Shared infrastructure: Other jobs consuming bandwidth
- Ephemeral networking: CI runners with inconsistent network paths
Solutions:
1. Authenticate to increase limits: docker login in your pipeline
2. Use a pull-through cache: Configure a local registry as a mirror
3. Cache base images: Pre-pull images in your CI environment
4. Add retry logic: Wrap Docker commands in retry scripts
### Alternative Diagnosis with Docker Events
Monitor Docker events during a timeout:
# In one terminal, start event monitoring
docker events --filter 'type=image'
# In another terminal, attempt the pull
docker pull myregistry:5000/myimage:latestThis can reveal if Docker is making progress or stuck at a particular stage.