A Docker proxy is three separate settings that people often mix up: the daemon proxy that dockerd uses to pull images, the build proxy passed to docker build as --build-arg HTTPS_PROXY=..., and the container proxy passed to running containers as environment variables. Setting one never sets the others. For most scraping jobs you want the third:
docker run --rm -e HTTPS_PROXY="http://USERNAME:PASSWORD@HOST:PORT" \
curlimages/curl -sS "https://api.ipify.org?format=json"
We ran the build and container commands on this page on 2026-09-30 with Docker Engine 29.8, BuildKit 0.33 and Compose 5.5 against a local proxy that enforces a username and password. The daemon settings were checked against the Docker daemon proxy docs the same day but not applied.
Before you start
- Open your order in the dashboard at https://app.proxyhive.io.
- Copy HOST, PORT (the HTTP port), USERNAME and PASSWORD. Every datacenter or ISP IP is its own endpoint.
- Keep them in a file outside the repository, readable only by you:
printf 'HTTPS_PROXY=http://USERNAME:PASSWORD@HOST:PORT\nNO_PROXY=localhost,127.0.0.1\n' > ~/proxy.env
chmod 600 ~/proxy.env
An IP allowlist on the order removes the password from the URL entirely, which is the cleanest option for a fixed build server. Username and password vs IP allowlist weighs the two.
The three Docker proxies at a glance
| What goes through the proxy | Where you set it | Used by |
|---|---|---|
| Image pulls and registry logins | systemd drop-in, daemon.json, or Docker Desktop settings | dockerd |
RUN steps during a build | --build-arg, Compose build.args, or ~/.docker/config.json | the build container |
| Traffic from your running app | -e, --env-file, Compose environment, or ~/.docker/config.json | the container |
Docker container proxy environment variables
Pass the variables at run time. The env file from above keeps the password off the command line and out of shell history:
docker run --rm --env-file ~/proxy.env curlimages/curl -sS "https://api.ipify.org?format=json"
Three details that bit us in testing:
HTTP_PROXYcovershttp://URLs only. With onlyHTTP_PROXYset, curl sent an https request straight out. SetHTTPS_PROXYfor https targets.- Many tools read the lowercase names, and curl reads
http_proxyin lowercase only. Setting both cases is harmless. - Anything passed with
-eis stored in the container config.docker inspectprinted our full proxy URL, password included, so treat access to the Docker socket as access to the credentials.
Docker Compose proxy
Compose reads a .env file next to compose.yaml for substitution. Keep .env in .gitignore:
services:
scraper:
image: curlimages/curl
environment:
HTTPS_PROXY: ${PROXY_URL}
NO_PROXY: localhost,127.0.0.1
command: ["-sS", "https://api.ipify.org?format=json"]
PROXY_URL=http://USERNAME:PASSWORD@HOST:PORT
Docker build proxy: --build-arg and what leaks
HTTP_PROXY, HTTPS_PROXY, NO_PROXY, ALL_PROXY (and their lowercase forms) are predefined build args: every RUN step sees them without an ARG line.
docker build --build-arg HTTPS_PROXY="http://USERNAME:PASSWORD@HOST:PORT" -t myimage .
The Dockerfile reference says these are left out of docker history. Here is what we found when we checked each place a password could end up:
| Where we looked | Predefined arg, no ARG line | ARG HTTPS_PROXY declared in the Dockerfile | Custom ARG PROXY_URL | Secret mount |
|---|---|---|---|---|
docker history --no-trunc | not present | full URL | full URL | not present |
docker image inspect, container env | not present | not present | not present | not present |
| Image provenance attestation | not present | not checked | not checked | not checked |
Builder record, docker buildx history inspect | full URL | full URL | full URL | not present |
Two conclusions. Do not write ARG HTTPS_PROXY in the Dockerfile: declaring it turns off the protection. And the build record lives on the builder, not in the image, but anyone with access to that builder can read it. For a shared CI builder, use a secret mount (Dockerfile syntax 1.10 or later), which exposes the value to one RUN step only:
# syntax=docker/dockerfile:1
FROM curlimages/curl
RUN --mount=type=secret,id=proxy,env=HTTPS_PROXY \
curl -sS "https://api.ipify.org?format=json"
export PROXY_URL="http://USERNAME:PASSWORD@HOST:PORT"
docker build --secret id=proxy,env=PROXY_URL -t myimage .
Never put the proxy in an ENV line: that stores it in the image config for everyone who pulls the image. In Compose, the same predefined args go under build.args.
Docker daemon proxy for image pulls
If docker pull itself must go through the proxy, configure dockerd. The container settings above do not affect pulls.
Linux with systemd
Create /etc/systemd/system/docker.service.d/http-proxy.conf:
[Service]
Environment="HTTP_PROXY=http://USERNAME:PASSWORD@HOST:PORT"
Environment="HTTPS_PROXY=http://USERNAME:PASSWORD@HOST:PORT"
Environment="NO_PROXY=localhost,127.0.0.1"
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl show --property=Environment docker
daemon.json (Docker Engine 23.0 and later)
{
"proxies": {
"http-proxy": "http://USERNAME:PASSWORD@HOST:PORT",
"https-proxy": "http://USERNAME:PASSWORD@HOST:PORT",
"no-proxy": "localhost,127.0.0.1"
}
}
Put it in /etc/docker/daemon.json and restart Docker. These fields take precedence over the environment variables. Add any internal registry to the no-proxy list.
Docker Desktop
Open Settings, then Resources, then Proxies, choose manual configuration and enter the proxy under Web Server (HTTP) and Secure Web Server (HTTPS). Docker Desktop has separate proxy settings for its own traffic and for containers, and image pulls follow the containers proxy.
Set a default for every container with ~/.docker/config.json
The Docker CLI proxy docs describe a proxies block that injects the variables into every new container and build started by that client, with no restart:
{
"proxies": {
"default": {
"httpProxy": "http://USERNAME:PASSWORD@HOST:PORT",
"httpsProxy": "http://USERNAME:PASSWORD@HOST:PORT",
"noProxy": "localhost,127.0.0.1"
}
}
}
It is convenient and global: every container you start, including ones that should not use the proxy, gets the password in its environment. Prefer per-project env files unless the whole machine should egress through one IP.
Verify the exit IP
docker run --rm curlimages/curl -sS "https://api.ipify.org?format=json"
docker run --rm --env-file ~/proxy.env curlimages/curl -sS "https://api.ipify.org?format=json"
The second IP should be the one on your order. To give several containers different static IPs, keep one env file per IP and start each container with its own file. The cURL proxy guide covers the flags used here.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
CONNECT tunnel failed, response 407 (curl exit 56) | Wrong credentials | Re-copy them; percent-encode @ or : in the password |
docker pull times out, containers are fine | Daemon has no proxy | Configure dockerd as above |
Build RUN step goes direct | No build arg passed | Add --build-arg HTTPS_PROXY=... or the proxies block |
Proxy on localhost unreachable from a container | localhost is the container | Use the host's address, or --network host on Linux |
| Internal service now fails | Traffic sent to the proxy | Add it to NO_PROXY |
More status codes are decoded in proxy error codes. Pricing for a single static IP is on the datacenter pricing page, from $3.20/IP.