← Back to Blog

Setting Up Proxy in Docker for Pulling Images and Container Applications: A Complete Guide

We discuss how to configure a proxy in Docker for downloading images through corporate firewalls and for applications inside containers β€” with configuration examples and real scenarios.

πŸ“…April 4, 2026
```html

Are you working with Docker in a corporate network, on a server with limited access, or do you want your containers to access the internet through a specific IP? Without the correct proxy configuration, Docker simply won't be able to download images from Docker Hub or any other registry. In this article, we will explore all levels of proxying β€” from the daemon to individual containers.

Why Docker Needs a Proxy

Docker is a tool that constantly interacts with external resources. With every docker pull or docker build, the daemon accesses Docker Hub, GitHub Container Registry, Google Container Registry, or your private registry. This is where problems begin.

Situations where a proxy is essential:

  • Corporate Network with Firewall β€” all traffic must go through the corporate proxy server, otherwise the connection is blocked.
  • Geo-Restrictions β€” Docker Hub or specific registries are not accessible from your country or data center.
  • Limited Server without Direct Internet Access β€” VPS in a closed loop where the internet is only available through a gateway.
  • Control of Outgoing Traffic from Containers β€” you want applications inside containers to access the network through a specific IP, for example, for scraping, API requests, or testing geo-dependent content.
  • Anonymization of Requests β€” hide the real IP of the server when accessing external services from the container.
  • Rate Limiting β€” Docker Hub limits the number of pull requests for anonymous users (100 pulls every 6 hours). Using a proxy with IP rotation can bypass this limitation.

It is important to understand that Docker is not a single application, but a system of several components. The daemon (dockerd) runs on the host and pulls images. Containers are isolated processes with their own network settings. Therefore, configuring a proxy for the daemon and for containers are two different tasks that are solved differently.

Three Levels of Proxying in Docker

Before diving into configurations, it is necessary to understand the architecture. Docker has three independent levels, each requiring separate proxy configuration:

Level What It Does Where to Configure
Docker Daemon Downloads images (docker pull), accesses registries systemd override or daemon.json
Docker Build Executes commands during image build (RUN apt-get, pip install, etc.) ARG and ENV in Dockerfile or --build-arg
Runtime Container Running application that makes HTTP requests ENV during docker run or in docker-compose.yml

A common mistake is to configure the proxy only at one level and wonder why images still do not pull or the application does not see the proxy. Let’s examine each level in detail.

Configuring Proxy for Docker Daemon (Pulling Images)

This is the most important configuration if you want to pull images through a proxy. The Docker daemon is a system service that runs through systemd. It does not see your user's environment variables or even root. You need to pass the proxy specifically to the service's environment.

Method 1: Through systemd override (recommended)

Create a directory for overriding service settings:

sudo mkdir -p /etc/systemd/system/docker.service.d

Create a file /etc/systemd/system/docker.service.d/http-proxy.conf with the following content:

[Service]
Environment="HTTP_PROXY=http://username:password@proxy-host:port"
Environment="HTTPS_PROXY=http://username:password@proxy-host:port"
Environment="NO_PROXY=localhost,127.0.0.1,::1,your-private-registry.example.com"

If the proxy does not require authentication, simply remove username:password@. After creating the file, reload the systemd configuration and restart Docker:

sudo systemctl daemon-reload
sudo systemctl restart docker

Check that the settings have been applied:

sudo systemctl show --property=Environment docker

Your HTTP_PROXY and HTTPS_PROXY variables should appear in the output.

Method 2: Through ~/.docker/config.json (Docker Desktop and newer versions)

Starting from Docker Engine 23.0, there is a more convenient way β€” configuring the proxy through the client configuration file. Create or edit the file ~/.docker/config.json:

{
  "proxies": {
    "default": {
      "httpProxy": "http://username:password@proxy-host:port",
      "httpsProxy": "http://username:password@proxy-host:port",
      "noProxy": "localhost,127.0.0.1,::1"
    }
  }
}

This method is convenient as it does not require root privileges and does not require restarting the daemon. The settings are automatically passed to containers during build as build arguments. However, to manage pull requests from the daemon itself, the systemd method is still required.

πŸ’‘ Important about NO_PROXY

Always add your internal registry and service addresses to NO_PROXY. Otherwise, Docker will attempt to reach them through the proxy and receive connection errors. A typical list includes: localhost,127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16

Proxy Inside the Container During Build (Build-Time)

When Docker builds an image and executes commands like RUN apt-get install, RUN pip install, or RUN npm install β€” these commands are executed inside a temporary container. By default, it does not have access to the host's proxy. You need to explicitly pass the proxy through build arguments.

Passing Proxy Through --build-arg

docker build \
  --build-arg HTTP_PROXY=http://proxy-host:port \
  --build-arg HTTPS_PROXY=http://proxy-host:port \
  --build-arg NO_PROXY=localhost,127.0.0.1 \
  -t my-image .

Configuration in Dockerfile

If the proxy is only needed during the build phase and you do not want it to be included in the final image β€” use ARG instead of ENV:

FROM ubuntu:22.04

# Declare build arguments
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY

# Use them in commands
RUN apt-get update && apt-get install -y curl wget

# After this block, the proxy will not be in the container's ENV

If the proxy is needed in the running container as well β€” use ENV:

FROM python:3.11

ENV HTTP_PROXY=http://proxy-host:port
ENV HTTPS_PROXY=http://proxy-host:port
ENV NO_PROXY=localhost,127.0.0.1

RUN pip install requests beautifulsoup4

CMD ["python", "app.py"]

⚠️ Attention: Security

Do not hardcode the proxy username and password directly in the Dockerfile if the image will be public or will be stored in a repository. Use --build-arg and pass values from CI/CD environment variables. The command docker history can show ARG values, so for secrets, use Docker BuildKit secrets.

Proxy for Running Containers (Runtime)

This is the most common scenario for applications that make HTTP requests during operation β€” scrapers, bots, microservices that need to exit through a specific IP. Here, the configuration is as simple as possible: you need to pass environment variables when starting the container.

Through docker run

docker run \
  -e HTTP_PROXY=http://username:password@proxy-host:port \
  -e HTTPS_PROXY=http://username:password@proxy-host:port \
  -e NO_PROXY=localhost,127.0.0.1 \
  my-image

Most popular HTTP libraries automatically pick up the HTTP_PROXY and HTTPS_PROXY variables: Python requests, curl, wget, Go's net/http, Node.js https-proxy-agent, and others. No additional code needs to be specified.

Through .env file

It is more convenient to store settings in a .env file and pass it entirely:

# .env file
HTTP_PROXY=http://username:password@proxy-host:port
HTTPS_PROXY=http://username:password@proxy-host:port
NO_PROXY=localhost,127.0.0.1
docker run --env-file .env my-image

SOCKS5 Proxy in the Container

If you are using a SOCKS5 proxy (for example, residential proxies most often support this protocol), the syntax is slightly different:

docker run \
  -e ALL_PROXY=socks5://username:password@proxy-host:port \
  my-image

Note: not all libraries support SOCKS5 through the environment variable without additional dependencies. Python requests requires installing requests[socks], and curl must be built with support for libcurl-socks.

Proxy in Docker Compose

In real projects, raw docker run is rarely used. Most often, work is done with Docker Compose, where multiple services are described in one file. Proxy configuration here is done at the level of each service or through a variable file.

Option 1: Environment in docker-compose.yml

version: '3.8'

services:
  scraper:
    image: my-scraper:latest
    environment:
      - HTTP_PROXY=http://username:password@proxy-host:port
      - HTTPS_PROXY=http://username:password@proxy-host:port
      - NO_PROXY=localhost,127.0.0.1
    restart: unless-stopped

  api:
    image: my-api:latest
    # This service without proxy β€” accesses only internal resources
    ports:
      - "8080:8080"

Option 2: Through .env file (recommended)

Create a .env file in the directory with docker-compose.yml. Docker Compose automatically picks up this file:

# .env
PROXY_HOST=proxy-host
PROXY_PORT=8080
PROXY_USER=username
PROXY_PASS=password
version: '3.8'

services:
  scraper:
    image: my-scraper:latest
    environment:
      - HTTP_PROXY=http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
      - HTTPS_PROXY=http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
      - NO_PROXY=localhost,127.0.0.1

Proxy During Build in Compose

If there is a build section in Compose and you need to pass the proxy during the build phase:

version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        HTTP_PROXY: http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
        HTTPS_PROXY: http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
    environment:
      - HTTP_PROXY=http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}
      - HTTPS_PROXY=http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}:${PROXY_PORT}

Which Type of Proxy to Choose for Docker

The choice of proxy type depends on the task. For Docker environments, three main types are relevant, each with its niche:

Proxy Type Speed Anonymity Best Scenario for Docker
Datacenter ⚑ High Medium Pulling images, CI/CD pipelines, bypassing Docker Hub rate limiting
Residential πŸ”„ Medium High Scraping sites with protection, APIs with geo-restrictions, testing
Mobile πŸ”„ Medium Maximum Applications working with mobile APIs (Instagram, TikTok)

For pulling images and CI/CD, datacenter proxies are optimal β€” they provide maximum speed when downloading large images (several gigabytes) and a stable connection for long builds.

For scraper containers, which need to bypass site protection and appear as regular users, residential proxies are better suited. They have IPs of real home users, which reduces the likelihood of blocking even with intensive requests.

For applications working with mobile platforms β€” Instagram Graph API, TikTok API, mobile versions of services β€” consider mobile proxies. They use IPs from mobile operators and raise minimal suspicion with anti-bot systems.

Protocols: HTTP vs SOCKS5

The Docker daemon only supports HTTP/HTTPS proxies β€” SOCKS5 does not work for pulling images. If you have a SOCKS5 proxy and need to download images, you will have to use a local converter like privoxy or microsocks, which will accept HTTP and proxy through SOCKS5.

For runtime containers, the situation is better: most HTTP libraries directly support SOCKS5 through the ALL_PROXY=socks5://... variable.

Common Errors and How to Fix Them

Let’s discuss the most common problems encountered when configuring proxies in Docker:

Error 1: Proxy is configured on the host, but Docker does not see it

Symptom:

Error response from daemon: Get "https://registry-1.docker.io/v2/": dial tcp: connection refused

Cause: The Docker daemon runs as a system service and does not inherit the environment variables of the current user, even if you set export HTTPS_PROXY=... in the terminal.

Solution: Configure the proxy through systemd override (method 1 from the section above). Be sure to execute systemctl daemon-reload && systemctl restart docker.

Error 2: apt-get / pip / npm do not work during build

Symptom:

Err:1 http://archive.ubuntu.com/ubuntu focal InRelease
Could not connect to archive.ubuntu.com:80

Cause: The proxy configuration for the daemon does not automatically propagate to commands inside RUN in the Dockerfile. These are two different contexts.

Solution: Pass the proxy through --build-arg or use ~/.docker/config.json with the proxies section (Docker 23.0+, automatically passes arguments during build).

Error 3: Internal services are not accessible through the proxy

Symptom:

curl: (7) Failed to connect to internal-service.local port 8080: Connection refused

Cause: The proxy attempts to proxy requests to internal addresses that are not accessible from the outside.

Solution: Add all internal domains and subnets to NO_PROXY. For corporate networks, a typical list includes: localhost,127.0.0.1,::1,.internal,.local,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16

Error 4: Proxy authentication does not work β€” special characters in password

If the password contains special characters (@, #, %), the URL is parsed incorrectly.

Solution: URL-encode the password. For example, p@ss#word β†’ p%40ss%23word. In Python, you can quickly get the encoded version:

python3 -c "from urllib.parse import quote; print(quote('p@ss#word', safe=''))"
# Output: p%40ss%23word

Error 5: Proxy works, but SSL certificate is not verified

Corporate proxies often perform SSL inspection (MITM) and replace certificates. In this case, Docker throws an error:

x509: certificate signed by unknown authority

Solution: Add the corporate root certificate to trusted on the host and restart Docker. On Ubuntu/Debian:

sudo cp corporate-ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
sudo systemctl restart docker

Error 6: Kubernetes / Docker Swarm β€” proxy does not work on all nodes

In clustered environments, the proxy needs to be configured on each node separately. For Kubernetes, you also need to configure environment variables in pod manifests or through ConfigMap. This can be automated using Ansible or other configuration management tools.

Conclusion

Configuring a proxy in Docker is not a single setting, but three independent levels: the daemon for pulling images, build-time for building, and runtime for running containers. By understanding this architecture, you can flexibly manage which traffic goes through the proxy and which goes directly.

A brief checklist for proper configuration:

  • βœ… For pulling images β€” configure systemd override with HTTP_PROXY and HTTPS_PROXY variables
  • βœ… For building β€” pass the proxy through --build-arg or ~/.docker/config.json
  • βœ… For runtime β€” use environment variables via -e or --env-file
  • βœ… Always configure NO_PROXY for internal addresses
  • βœ… Do not store proxy passwords in Dockerfile β€” use build-args and .env files
  • βœ… For CI/CD pipelines, choose fast datacenter proxies
  • βœ… For scraper containers β€” residential or mobile proxies

If your container applications make requests to external services, scrape data, or work with APIs that have geo-restrictions, we recommend using residential proxies β€” they provide a high level of trust from services and minimal risk of blocking even with intensive work.

```