How to Configure the Docker Daemon Proxy

The Docker daemon (dockerd) is what runs docker pull, so start here when pulls fail. On Docker Engine 23.0 and later, put a proxies block in /etc/docker/daemon.json. The keys are case-sensitive, so a typo like http-Proxy stops the daemon from starting.
{
"proxies": {
"http-proxy": "http://proxy.example.com:3128",
"https-proxy": "http://proxy.example.com:3128",
"no-proxy": "localhost,127.0.0.0/8,registry.internal.example.com"
}
}Restart with sudo systemctl restart docker. Both entries normally point at the same address, since HTTPS_PROXY means the proxy for HTTPS destinations, not a proxy on port 443. On older engines, use a systemd drop-in, as the daemon proxy configuration reference shows:
- Run
sudo mkdir -p /etc/systemd/system/docker.service.d. - Save the following as
http-proxy.confin that directory. [Service]
Environment="HTTP_PROXY=http://proxy.example.com:3128"
Environment="HTTPS_PROXY=http://proxy.example.com:3128"
Environment="NO_PROXY=localhost,127.0.0.1,registry.internal.example.com" - Run
sudo systemctl daemon-reload && sudo systemctl restart docker. - Verify with
sudo systemctl show --property=Environment docker.
One thing worth knowing: Docker Desktop ignores daemon.json proxies. Set them under Settings, Resources, Proxies instead, and remember that only covers pulls.
How to Pass Proxy Settings to Containers

Nothing the daemon knows reaches the inside of a container. To inject proxy variables into every new container, add a proxies block to ~/.docker/config.json on the machine running the Docker CLI.
{
"proxies": {
"default": {
"httpProxy": "http://proxy.example.com:3128",
"httpsProxy": "http://proxy.example.com:3128",
"noProxy": "localhost,127.0.0.1,.internal.example.com"
}
}
}It applies to new containers and builds immediately, with no restart, and does nothing for existing ones. Docker sets each variable in both uppercase and lowercase because tools disagree on which one they read. curl, for example, only reads lowercase http_proxy while accepting either case for the others. For a one-off container, pass the values with --env:
docker run --rm \
-e HTTP_PROXY=http://proxy.example.com:3128 \
-e HTTPS_PROXY=http://proxy.example.com:3128 \
-e NO_PROXY=localhost,127.0.0.1 \
alpine sh -c 'env | grep -i _proxy'Also Read: How to Use a Proxy Server on Any Device
Using a Proxy During Docker Build

Pass the proxy as a build argument. HTTP_PROXY, HTTPS_PROXY, NO_PROXY, and ALL_PROXY are predefined, so you do not declare them with ARG, and their values stay out of the final image and docker history.
docker build \
--build-arg HTTP_PROXY=http://proxy.example.com:3128 \
--build-arg HTTPS_PROXY=http://proxy.example.com:3128 \
-t my-app .Older guides still tell you to write ENV http_proxy into the Dockerfile. Do not. That hardcodes the proxy into every container built from the image, breaks it on any other network, and exposes the credentials to anyone who can run docker inspect.
Docker Compose Proxy Configuration

Define runtime values under environment and build-time values under build.args, interpolated from a .env file so credentials stay out of version control. Declaring them in the Compose file keeps the behavior identical on every machine and in CI.
services:
scraper:
build:
context: .
args:
HTTP_PROXY: ${HTTP_PROXY}
HTTPS_PROXY: ${HTTPS_PROXY}
environment:
HTTP_PROXY: ${HTTP_PROXY}
HTTPS_PROXY: ${HTTPS_PROXY}
NO_PROXY: localhost,127.0.0.1,db,redis
db:
image: postgres:16
redis:
image: redis:7Put your service names in NO_PROXY. Otherwise a request from scraper to db goes to the proxy, which has no idea what db is, and the failure looks nothing like a proxy problem.
Using Authenticated Proxies With Docker

Commercial proxies, including residential proxies and datacenter proxies from Proxyon, authenticate with credentials in the proxy URL as user:pass@host:port, and Docker passes that string through unchanged at every layer above. Special characters in the password must be percent-encoded, so @ becomes %40 and # becomes %23, and inside a systemd drop-in every % is doubled to %% because systemd treats it as a specifier. The proxy formatter handles that conversion.
Credentials in environment variables are readable through docker inspect. On a server with a fixed IP, IP whitelisting on the proxy side removes them entirely, and the container only needs the host and port. Then confirm the route:
docker run --rm \
-e HTTPS_PROXY=http://user:pass@gateway.proxyon.io:8000 \
curlimages/curl -s https://api.ipify.orgThe response should show the proxy's IP, not your server's.
Also Read: How to Set Up Rotating Proxies for Web Scraping
FAQ Section

Why does docker pull work but apt-get fails during the build?
The daemon has a proxy and the build container does not. Pulling the base image is daemon traffic, while apt-get runs inside a temporary container that only knows about HTTP_PROXY if you pass it as a build argument or set it in ~/.docker/config.json.
Do I need to restart Docker after changing the proxy settings?
Only for the daemon. Changes to daemon.json or a systemd drop-in need systemctl restart docker, while changes to ~/.docker/config.json apply to the next container or build you start.
What is the docker-proxy process I see on my host?
It is Docker's userland proxy, a small binary that forwards published ports (-p 8080:80) to containers. It has nothing to do with outbound HTTP proxies, and it can be disabled with "userland-proxy": false in daemon.json, though that changes how published ports behave on localhost.
Does Docker support SOCKS5 proxies?
The daemon does. Its proxy handling accepts socks5:// URLs in daemon.json or the systemd drop-in, although socks5h:// is not recognized. Inside a container it comes down to the client: curl handles socks5://, Python requests needs the PySocks extra, and many tools ignore SOCKS URLs in the proxy variables entirely, so an HTTP proxy is the safer default for containers.
What should go in NO_PROXY?
localhost, 127.0.0.1, any internal registry, your Compose service names, and your internal domain suffix. Docker matches example.com against its subdomains as well, and a leading dot limits the match to subdomains only. Keep the list identical in both cases, because tools that read no_proxy and tools that read NO_PROXY will otherwise behave differently.
Is a registry mirror the same as a proxy?
No. A registry mirror ("registry-mirrors" in daemon.json) is a pull-through cache that keeps copies of images closer to you. It does not route container traffic anywhere, and it can be combined with a proxy, but it does not replace one.
Final Thoughts
The right Docker proxy setup comes down to which traffic you need to move. If only image pulls are blocked, configure the daemon and stop there. If the application inside the container needs to reach the outside world through a proxy, set the variables at the container or Compose level and keep credentials out of the image. For scraping and automation workloads, Proxyon's residential and datacenter proxies accept the same authenticated URL at every one of these layers, with IP whitelisting available when you would rather not store credentials at all.