On this page
First determine whether the timeout occurs in Docker, during the build, or inside an already running container
Routing VS Code Dev Containers through Clash is not a matter of entering one proxy address. Pulling the base image, executing the Dockerfile, running Git inside the container, and downloading remote extensions are initiated by different processes.
Find the stage containing the failed command in the “Dev Containers” output, then pass the proxy to the corresponding process. Otherwise, even a complete containerEnv cannot fix a container that has not yet been created.
Four network locations
| Failed action | Component making the request | Configuration entry point |
|---|---|---|
| docker pull / pull a base image | Docker daemon | Docker Desktop or daemon proxy |
| Dockerfile RUN apt/npm | Image build stage | build args or BuildKit configuration |
| curl/Git/pip inside the container | Running container | containerEnv, remoteEnv, or tool-specific configuration |
| VS Code remote extension download | Dev Containers remote service | The container environment and extensions' own network requests |
If the error appears before “Starting Dev Container,” containerEnv in .devcontainer/devcontainer.json usually cannot fix it because the container is not running yet. Record the failed command and its stage in the VS Code output panel first.
- VS Code hostPulls extensions and starts Docker
- Docker build stageReads build args or Docker proxy settings
- Running containerReads containerEnv
- Remote extensions and terminalReads remoteEnv or the tool's own configuration
Configure the proxy only for the stage that fails. Do not treat the host, build stage, and container runtime as one environment-variable set.
127.0.0.1 inside the container is not the host machine
When Clash runs on the host, http://127.0.0.1:7890 inside a container points to the container itself. Docker Desktop provides host.docker.internal on Windows and macOS; Linux Docker can map the same name through host-gateway.
If Clash listens only on the host loopback address, the container may still be unable to connect. When enabling local-network access or binding mixed-port to an interface the container can reach, also restrict sources with the system firewall. Never expose 7890 directly to the public internet.
CLASH_HOST=host.docker.internal
CLASH_PORT=7890
getent hosts "$CLASH_HOST" || true
curl -v -x "http://$CLASH_HOST:$CLASH_PORT" https://www.example.com/
# Linux Docker 临时测试
docker run --rm --add-host=host.docker.internal:host-gateway curlimages/curl:latest -v -x http://host.docker.internal:7890 https://www.example.com/On a Linux host, add host-gateway to devcontainer.json
{
"runArgs": [
"--add-host=host.docker.internal:host-gateway"
]
}After editing, run Dev Containers: Rebuild Container. An existing container will not automatically receive the new hosts mapping.
For a Docker Compose project, use extra_hosts: ["host.docker.internal:host-gateway"] under the service. Do not add it in both places.
After the port is reachable, configure the proxy for the running container
The previous step passes only after curl receives an HTTP response. Next, give that same address to the terminal inside the container and to VS Code remote processes. If mixed-port is not 7890, change the port in all three places below.
{
"containerEnv": {
"HTTP_PROXY": "http://host.docker.internal:7890",
"HTTPS_PROXY": "http://host.docker.internal:7890",
"NO_PROXY": "localhost,127.0.0.1,::1,host.docker.internal"
},
"remoteEnv": {
"HTTP_PROXY": "${containerEnv:HTTP_PROXY}",
"HTTPS_PROXY": "${containerEnv:HTTPS_PROXY}",
"NO_PROXY": "${containerEnv:NO_PROXY}"
}
}Using http:// at the start of HTTPS_PROXY is usually correct: it means reaching HTTPS through an HTTP CONNECT proxy, not turning the proxy port itself into HTTPS. Add Compose service names, the corporate intranet, and local development domains to NO_PROXY as well; otherwise, container requests to a database or API may be routed through Clash.
After saving, run Rebuild Container, then execute env | grep -i proxy in a new terminal. Existing terminal processes do not automatically refresh remoteEnv.
Image pulls and Dockerfile builds require separate configuration
FROM image pulls are initiated by the Docker daemon and should be handled on Docker Desktop's Proxies page or in daemon configuration. Dockerfile RUN commands execute in a build container and can receive a temporary proxy through build.args, but do not use ENV to leave personal ports or credentials in image layers.
{
"build": {
"dockerfile": "Dockerfile",
"args": {
"HTTP_PROXY": "http://host.docker.internal:7890",
"HTTPS_PROXY": "http://host.docker.internal:7890",
"NO_PROXY": "localhost,127.0.0.1"
}
}
}After curl succeeds, test Git, apt, and extensions separately
In the container terminal, confirm that HTTP_PROXY, HTTPS_PROXY, and NO_PROXY are present, then run Git and package-manager commands separately. Git normally reads the environment variables. If it still uses an old address, inspect Git's own configuration.
Remote extensions are downloaded by the container-side VS Code Server. After changing remoteEnv, you must Rebuild Container, then inspect marketplace requests in the output panel.
REPO_URL='https://github.com/octocat/Hello-World.git'
env | grep -i '_proxy'
git config --show-origin --get-regexp 'http.*proxy' || true
git ls-remote "$REPO_URL"
# 只有 Git 不读取环境变量时才临时写入
git config --global http.proxy http://host.docker.internal:7890
git config --global --unset-all http.proxycurl works, but Git still connects to the old port
Run git config --show-origin --get-regexp 'http.*proxy' and remove stale user or repository settings.
apt update fails
Inspect the actual repository domain, certificate, and any independent proxy under /etc/apt/apt.conf.d.
The project runs, but remote extensions will not install
Find the marketplace request in the Dev Containers log and confirm that the remote service inherited remoteEnv.
The container has internet access, but the local database connection fails
Add the database service name and private address range to NO_PROXY.
The Rebuild stage still fails
Return to daemon image pulls or Dockerfile build args; do not keep editing the running container.
Do not hard-code a personal proxy in a shared repository
For team projects, devcontainer.json can read each developer's local environment with ${localEnv:HTTP_PROXY}, or you can provide an .env.example without a real address.
Document in README that HTTP_PROXY must be a complete address, such as http://host.docker.internal:7890. Before committing, confirm that the proxy URL contains no username, password, or token.
After verification, docker pull, Rebuild Container, Git/package-manager commands inside the container, and local service access should each succeed. If one fails, keep the log for that stage instead of collapsing all four network layers back into “Dev Container has no internet.”
