Slow GitHub clones, Docker image pulls, and package installs can look like one network problem, but they often travel through different processes and proxy settings. A desktop VPN client may route a browser while leaving Git, the Docker daemon, or a CI runner on its original connection. The practical fix is to identify which process is making the request, choose a suitable route, and verify that the request actually uses it.

Map the network path before changing settings

A command-line tool can connect directly, use an HTTP proxy, or inherit routing from a VPN client. These paths are not interchangeable. A VPN tunnel typically changes the network route for selected device traffic; an application proxy directs requests from a particular program to a proxy endpoint. Some clients provide both options, but an available local proxy does not mean every application is configured to use it.

Start by identifying the exact operation that is slow. A Git clone may contact GitHub over HTTPS or SSH and then fetch large Git LFS objects from a separate endpoint. A Docker pull is usually performed by the Docker Engine, which may run as a background service and have different settings from the terminal. A package manager can use its own proxy configuration, environment variables, or a registry mirror. In a CI job, the runner’s network and credentials matter; your laptop’s VPN settings do not automatically apply.

Also separate name resolution from transfer speed. If a hostname takes a long time to resolve, changing download concurrency will not solve the initial delay. If a request connects promptly but transfers unevenly, look at route quality, packet loss, local Wi-Fi, and the remote service. Compare one operation at a time, using the same repository, image, or package source where possible.

120+

Countries covered

170+

Routes

5

Supported platforms

Unlimited

Concurrent devices

Route availability is not a guarantee that every developer service will be fast or reachable. Select a route based on the destination and the behavior you observe, not on a label alone. For an overview of the service and its access options, see VPN for China.

Configure the terminal and Git deliberately

First check whether the VPN client is in a system-wide mode, a rule-based mode, or a local-proxy mode. In system-wide mode, applications may be routed through the tunnel without individual proxy settings. In rule-based mode, the selected rule may send developer domains direct or through a different route. In local-proxy mode, applications usually need an explicit proxy address and port. Read the client’s current instructions rather than assuming a port or protocol.

When the client provides a local HTTP proxy, you can test it for a single command without making a permanent change. Replace the example address and port with the values shown by your client:

HTTPS_PROXY=http://127.0.0.1:PORT \
HTTP_PROXY=http://127.0.0.1:PORT \
git ls-remote https://github.com/OWNER/REPOSITORY.git

This is a temporary diagnostic for a compatible HTTP proxy, not a universal VPN command. A SOCKS proxy needs a client and tool configuration that support SOCKS; do not label a SOCKS endpoint as HTTP. If the command succeeds through the proxy but not through the default route, the issue is likely in the route or the application’s proxy handling. If both fail, check DNS, authentication, the repository address, and the service response before changing more settings.

For Git, keep proxy configuration scoped as narrowly as practical. A repository-specific setting avoids sending unrelated Git traffic through a proxy:

git config --local http.proxy http://127.0.0.1:PORT
git config --local --get http.proxy
git config --local --unset http.proxy

Run the first command inside the relevant repository. Use a global setting only when you intend the same proxy to apply to every repository for that user, and record how to remove it. A stale proxy value can make Git appear broken after the VPN client closes. Inspect the effective setting with git config --show-origin --get-all http.proxy; this helps locate a value inherited from system, global, or repository configuration.

HTTPS and SSH are separate connection methods. An HTTPS clone can use an HTTP proxy when Git and the proxy support the required behavior. SSH commonly connects to a different destination and does not automatically use an HTTP proxy setting. If SSH is slow or unavailable, test an HTTPS remote as a diagnostic, while preserving your normal credential and host-verification practices. Do not disable certificate validation or host-key checking to make a clone work.

  • ✅ Test a small metadata request such as git ls-remote before retrying a large clone.
  • ✅ Check whether the remote uses HTTPS or SSH and whether Git LFS is involved.
  • ✅ Remove temporary proxy settings when the test is over, especially on a shared workstation.
  • ❌ Do not paste a subscription URL, access token, or credential-bearing proxy URL into a public issue or terminal screenshot.

Route Docker pulls, builds, and containers separately

Docker has several network layers. The Docker Engine downloads image manifests and layers when you run docker pull or when a build needs a base image. A build process can also make requests while executing package installation commands. A running container has its own network namespace and may need separate proxy variables. Setting a proxy only in your interactive shell may therefore affect none, some, or all of these operations depending on how Docker is installed and launched.

If only image pulls are slow, check which daemon is serving the CLI. A local Docker Engine, Docker Desktop, and a remote context can use different networking environments. Confirm the active context with docker context show and inspect the daemon’s status before editing configuration. If the CLI targets a remote daemon, changing proxy variables on your laptop will not configure that remote service.

For a self-managed Linux Engine, proxy configuration is commonly provided to the daemon through its service configuration. The exact location and restart procedure depend on the distribution and installation method. A configuration may contain fields like this, but the values must match a reachable proxy endpoint and the syntax required by that Docker Engine version:

{
  "proxies": {
    "http-proxy": "http://127.0.0.1:PORT",
    "https-proxy": "http://127.0.0.1:PORT",
    "no-proxy": "localhost,127.0.0.1"
  }
}

Do not copy this snippet blindly into an existing JSON file: merge the keys without deleting other daemon settings, validate the JSON, and follow the installation’s official instructions for applying changes. A daemon running as a separate service may not be able to reach a proxy bound only to a loopback interface in your desktop session. Docker Desktop also has its own settings and networking boundary, so a host-local address may behave differently there.

Build-time proxy settings are another layer. Docker supports passing proxy configuration to build operations, but that does not replace daemon proxy configuration for pulling the base image. For example, a build may receive standard proxy variables while a preceding image pull still fails. Keep proxy values out of image layers: do not write credentials into a Dockerfile, copy a developer’s environment file into an image, or print secret variables in build logs. Use the build system’s supported proxy mechanism and secret handling, and confirm that the resulting image contains no credentials.

To narrow the fault, try pulling a small, known image, then build a minimal image that does not install packages. If the pull fails but the build has not started, investigate daemon routing and registry access. If the pull works but a package installation step fails, investigate the build network, package mirror, DNS, and package-manager proxy. If the build works but an application inside the running container cannot connect, check the container’s own environment and network policy rather than changing the host client at random.

A practical troubleshooting sequence

Use this sequence when a clone, pull, or install is slow. Change one variable at a time and keep a note of the original settings. That makes it easier to reverse a test and prevents several overlapping proxy configurations from obscuring the result.

  1. Record the scope. Note the command, destination, time of failure, and whether the same operation works in a browser. Record whether you are on a local network, a VPN route, or a CI runner. Do not include tokens or subscription links in the notes.
  2. Check basic connectivity. Verify that ordinary network access works and that the target hostname resolves. If other applications also have trouble, check the local connection and VPN route before modifying Git or Docker.
  3. Test the smallest relevant request. For Git, use git ls-remote. For Docker, try pulling a small image from the registry you actually need. For a package manager, request package metadata or install a small dependency in a disposable environment.
  4. Compare routes. If permitted by the service and your network, compare the default connection with one VPN route and, when available, another route suited to the destination. A difference can identify a path-related problem; it does not prove that the application is configured correctly.
  5. Check the process boundary. Confirm whether the request is made by the shell, Docker Engine, Docker Desktop, a container, or a remote runner. Apply settings at that layer and avoid adding the same proxy independently at every layer.
  6. Undo and verify. Remove temporary environment variables or Git settings, restart only the service whose configuration changed, and repeat the test. Confirm that normal traffic and local resources still behave as intended.

Useful comparisons need not be large downloads. A metadata request can establish whether a connection and authentication path work without repeatedly transferring the same data. If a large transfer is necessary, avoid running parallel retries while diagnosing: they can consume local bandwidth, trigger rate limits, and make the results harder to interpret. When using a VPN for China, compare the same developer endpoint across routes and remember that a VPN changes the network path, not GitHub’s, Docker Hub’s, or a package registry’s own service state.

Diagnostic rule: Identify the process that makes the request, test its smallest relevant operation, and then change only that process’s route or proxy configuration.

Handle CI runners, tokens, and proxy credentials safely

A hosted CI runner usually uses the network provided by the CI platform for that job. A VPN connected on your own computer does not route a remote runner. If a job needs a particular egress route, first review the platform’s networking options and your organization’s policies. A self-hosted runner can use a managed VPN or proxy, but it needs controlled access, maintenance, and a clear way to recover when the route is unavailable.

Configure CI proxy values through the runner or job environment using the platform’s protected secret mechanism where credentials are involved. Limit secret access to the jobs that need it, avoid printing the environment, and do not put credentials in a committed workflow file, container image, cached layer, or artifact. Check how the CI platform masks secrets: masking is helpful but is not a reason to echo them. Rotate a credential if it appears in public logs or a repository.

For Git operations in automation, use the CI platform’s recommended token or credential mechanism and grant only the permissions required for the task. Do not embed a personal access token directly in a clone URL that could appear in process listings or logs. For Docker registries, authenticate using the platform’s supported secret integration, and avoid saving an interactive developer’s Docker configuration into an artifact or shared runner image.

Proxy configuration can also affect internal services. Define a deliberate bypass list for localhost and required internal hostnames where appropriate, but do not place broad or guessed domain patterns in a no-proxy setting. A mistaken exclusion may send sensitive traffic outside the intended route; a missing exclusion may prevent access to internal package services. Review the actual destination names used by the job and test them from the runner environment.

  • ✅ Keep VPN subscriptions, proxy credentials, registry tokens, and Git credentials out of source control.
  • ✅ Separate developer workstation settings from CI runner settings and document who maintains each.
  • ✅ Confirm that logs, caches, artifacts, and built images do not contain secrets.
  • ❌ Do not assume a successful browser request proves the CI runner or Docker daemon uses the same route.

Choose a route and plan for the workload

For occasional repository access, a route that reliably handles the host and protocol you use may be enough. Frequent image pulls and dependency installs create a different pattern: they may involve large layers, multiple registries, package mirrors, and background automation. Before selecting a plan, estimate your monthly data use across devices and include repeated builds, cache misses, and large source assets. A local build cache can reduce redundant transfers, but it cannot replace a working route when a dependency is not cached.

VPNSR lists coverage of 120+ countries and 170+ routes, supports Windows, macOS, iOS, Android, and Linux, and allows unlimited concurrently connected devices. Monthly subscriptions include 60GB for ¥9.9 per month, 250GB for ¥18 per month, or 500GB for ¥28 per month. Monthly traffic resets on the activation date. A traffic pack is a separate option for usage that does not need to reset monthly; its balance does not expire. Review the current plan details before choosing, because a plan’s data allowance is not a promise of a particular download speed or availability from a third-party registry.

Choose a route by testing the actual tools you rely on: Git over your intended transport, a Docker pull through the daemon, and the package source used in your builds. Prefer a route that behaves consistently for those tasks and does not interfere with required internal services. If you change routes, retest the affected layer rather than assuming every application follows the same path.

Finally, keep a simple recovery checklist: know how to turn off the client, remove a temporary Git proxy, restore the Docker daemon’s previous configuration, and clear temporary shell variables. That checklist is useful when a proxy becomes unreachable or when a developer switches networks. The goal is not to force every developer tool through one setting; it is to make the intended traffic path explicit, verifiable, and reversible.