Docker Proxy and SOCKS5 Configuration: Daemon, Build, Containers, and Bridges
Docker does not have one proxy switch. The daemon, the build process, and each container read proxy settings in different places — and SOCKS5 is not supported by the daemon at all. Here is how to configure each layer and verify it works.
Docker Proxy and SOCKS5 Configuration: Daemon, Build, Containers, and Bridges
If you search for a 'socks5 configurator' because Docker pulls keep timing out, you are not alone. Docker has at least three proxy layers, and they do not share settings. A proxy that works for docker pull may not help apt-get inside a build, and SOCKS5 — common on many proxy services — is not accepted by Docker's daemon proxy variables. This guide walks through each layer with copy-paste configuration and verification steps, so you can route only what needs routing and avoid leaking DNS or credentials.
The three Docker proxy layers (and where each one applies)
| Layer | What it affects | Where you set it | Protocol support |
|---|---|---|---|
| Daemon | docker pull, docker push, registry auth |
systemd drop-in (Linux) or Docker Desktop settings | HTTP/HTTPS proxy URLs |
| Build | RUN commands during docker build (apt, pip, npm) |
--build-arg + ARG in Dockerfile |
HTTP/HTTPS proxy URLs |
| Container runtime | Traffic from your app inside the container | -e flags or Compose environment |
Depends on app (HTTP, HTTPS, SOCKS5 if app supports it) |
A fourth place people forget: the host's own package manager and tools. If you cannot reach the Docker registry, you usually cannot reach apt or pip on the host either. Set a host-level proxy first, then configure Docker. For per-app routing on the host, see our SOCKS5 configurator guide for browsers, SSH, curl, git, and Python.
Daemon-level proxy: for pulling images and talking to registries
The Docker daemon reads standard proxy environment variables from its systemd service. Create a drop-in file:
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf > /dev/null <<'EOF'
[Service]
Environment=HTTP_PROXY=http://user:[email protected]:3128
Environment=HTTPS_PROXY=http://user:[email protected]:3128
Environment=NO_PROXY=localhost,127.0.0.1,::1,.internal.example,registry.internal.example
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
Notes:
- The value is the proxy URL. For a standard HTTP proxy that supports CONNECT, use
http://. If your proxy endpoint itself is TLS-wrapped, usehttps://. NO_PROXYshould include any internal registry or host you do not want proxied. The leading dot in.internal.examplematches subdomains in many implementations, but behavior varies.- Credentials in the systemd file are visible to root. For shared machines, consider a local forwarder that does not require credentials in the environment.
Verify:
docker info | grep -i -A2 'Proxy'
You should see HTTP Proxy, HTTPS Proxy, and No Proxy lines. If they are empty, the daemon did not pick up the drop-in.
Then test a pull:
docker pull alpine:latest
If it still fails, check the daemon logs:
journalctl -u docker.service --no-pager -n 50
Docker Desktop (macOS/Windows) has a GUI proxy setting under Settings, Resources, Proxies. It writes the same variables for the daemon.
Build-time proxy: when the pull works but RUN apt-get does not
The daemon proxy does not automatically apply to build containers. You must pass proxy args and declare them in the Dockerfile.
FROM debian:bookworm-slim
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates && rm -rf /var/lib/apt/lists/*
Build:
docker build --build-arg HTTP_PROXY=http://user:[email protected]:3128 --build-arg HTTPS_PROXY=http://user:[email protected]:3128 --build-arg NO_PROXY=localhost,127.0.0.1 -t myapp .
Important: --build-arg values can be visible in image history and build logs. Never bake credentials into a final image. Use multi-stage builds and unset the args before the final stage, or use BuildKit secret mounts for credentials.
Per-container proxy: setting environment variables at runtime
For apps that read proxy env vars, set them when you start the container:
docker run --rm -e HTTP_PROXY=http://proxy.example:3128 -e HTTPS_PROXY=http://proxy.example:3128 -e NO_PROXY=localhost,127.0.0.1 myapp
In Docker Compose:
services:
app:
image: myapp
environment:
HTTP_PROXY: http://proxy.example:3128
HTTPS_PROXY: http://proxy.example:3128
NO_PROXY: localhost,127.0.0.1,.internal.example
Not every application respects these variables. Some read only lowercase http_proxy, some ignore NO_PROXY entirely, and some have their own config file. Always check the app's documentation.
SOCKS5: why Docker's proxy variables do not accept it
The Docker daemon and --build-arg proxy variables expect HTTP or HTTPS proxy URLs. socks5:// is not a supported scheme for the daemon. If your proxy service only gives you a SOCKS5 endpoint, you have three practical options:
- Run a local HTTP-to-SOCKS5 bridge. A small forwarder listens on
127.0.0.1:3128and forwards to your SOCKS5 proxy. Then point Docker's HTTP_PROXY at the bridge. This keeps SOCKS5 credentials out of Docker's environment. - Use SSH dynamic forwarding plus a bridge.
ssh -D 1080gives you a local SOCKS5 proxy; the bridge converts it to HTTP for Docker. This works well when you already have SSH access to a remote host. - Configure the application inside the container to use SOCKS5 directly. Many tools (curl, requests, git) support
socks5h://natively. This bypasses Docker's proxy settings entirely and only affects that app.
Example: testing SOCKS5 from inside a container without a bridge, using curl. On Linux, add --add-host=host.docker.internal:host-gateway so the container can reach a proxy running on the host.
docker run --rm --add-host=host.docker.internal:host-gateway curlimages/curl:latest --socks5-hostname host.docker.internal:1080 https://ifconfig.me
--socks5-hostname sends the hostname to the proxy for DNS resolution, which avoids DNS leaks. If you use --socks5, curl resolves DNS locally and only tunnels the TCP connection — a common source of incorrect geolocation and leaks.
For application code, the socks5h scheme is often clearer:
curl --proxy socks5h://user:[email protected]:1080 https://ifconfig.me
Verifying the proxy is actually used (and catching leaks)
After configuration, verify at each layer:
- Daemon:
docker info | grep -i proxyshows the variables. Thendocker pullshould hit the proxy. You can also check the proxy's own logs for a CONNECT request toregistry-1.docker.io:443. - Build: Add a
RUNstep that prints the observed IP:RUN curl -s https://ifconfig.me || true. If the IP is your real one, the build is not proxied. Remove this line before shipping. - Container:
docker exec -it <container> sh -c 'curl -s https://ifconfig.me'and compare with your real IP. - DNS: HTTP proxies usually resolve DNS on the proxy side for HTTPS (via CONNECT), but plain HTTP requests may leak DNS if the client resolves locally. SOCKS5 with
socks5halways resolves remotely. If DNS matters, test with a DNS leak checker or inspect proxy logs.
Common pitfalls with Docker and proxies
NO_PROXYis not automatic. If your internal registry or a service on the host is being proxied unnecessarily, add it toNO_PROXY. Includelocalhost,127.0.0.1, and any internal domains.- Upper vs lower case. Some tools read
HTTP_PROXY, othershttp_proxy. Set both if unsure. In Dockerfiles,ARG HTTP_PROXYis enough to make the build process read the uppercase variant; addARG http_proxyif a specific tool needs lowercase. - Credentials in build history.
--build-argvalues can appear indocker history. Use BuildKit secret mounts (--mount=type=secret) for tokens and passwords. - Docker Desktop vs Linux daemon. On Linux you edit systemd; on Docker Desktop you use the GUI or
settings.json. Do not assume a Linux tutorial applies to Docker Desktop. - IPv6 and dual-stack. If your proxy only supports IPv4, force the container or daemon to prefer IPv4. Some tools need an explicit flag.
A practical workflow for restricted or filtered networks
If you are working from a network where registry access is slow, throttled, or filtered — common in some corporate and national networks — start with the daemon proxy so image pulls succeed. Then add build-time args for package managers. Finally, set runtime env vars only for containers that need egress through the proxy. If your only proxy endpoint is SOCKS5, run a local bridge and point Docker's HTTP proxy variables at it, or keep SOCKS5 inside the container for apps that support it directly.
This layered approach avoids sending all container traffic through the proxy when only image pulls and build steps require it. It also keeps credentials in fewer places.
Takeaway
Docker proxy configuration is not one setting; it is a daemon setting, a build-time argument, and a per-container environment variable. SOCKS5 is supported only where the application supports it — Docker's daemon does not. By configuring each layer deliberately and verifying with docker info, a test pull, and an in-container IP check, you can keep builds working without leaking DNS or baking credentials into images.