Skip to content

Guides · Connect and debug

Use an HTTP proxy with Git over HTTPS

Check access to an authorised Git repository before downloading its objects. Keep proxy login separate from repository login, use temporary settings and leave certificate verification enabled.

Published

Short answers

Which Git setting selects an HTTP proxy?

http.proxy selects a proxy for Git’s HTTP and HTTPS transport. An HTTPS repository can use an HTTP gateway through CONNECT. An SSH remote uses a different transport and is not configured by this setting.

Can Git ask for the proxy password?

Yes. A proxy URL containing a username without a password tells Git to obtain the password through its credential mechanism. The isolated example below removes saved helpers and asks on the terminal.

Does ls-remote prove that a clone will finish?

No. It reads advertised references. Downloading repository objects is a further check, and submodules, large-file downloads and build tools can use additional hosts or clients.

Should I disable SSL verification for a Git proxy?

No. Check which connection failed, the certificate hostname and its trust chain. Use an approved CA file when necessary; a proxy password cannot repair a certificate error.

Check the repository transport first

The remote URL determines the client path
Repository addressMeaning
https://git.example.org/team/project.gitGit uses HTTPS. The HTTP proxy receives a CONNECT request, then the destination TLS connection runs through that tunnel.
http://git.example.org/team/project.gitGit uses HTTP without destination TLS. Prefer the repository’s supported HTTPS address.
ssh://git@git.example.org/team/project.git or git@git.example.org:team/project.gitGit uses SSH. The HTTP settings in this guide do not configure that SSH connection.

Use a repository you own or are permitted to read and an approved gateway. The example addresses above are placeholders. If an organisation requires SSH, follow its approved SSH configuration; do not change the transport merely to work around its access policy. Git documents the supported remote URL forms.

For Portproof, select HTTP in the connection builder and keep the full generated username, gateway and HTTP port together. Current pool and country choices come from locations. This is shared proxy traffic; repository access remains controlled by the repository owner.

Read the remote references with temporary settings

Use supported Git and Python 3 installations in a macOS or Linux terminal. Start with a repository that needs no repository login, if one is available for your authorised test. Save the following script as git-proxy-check.py. It changes settings only for its Git child process and does not load your usual Git configuration, proxy exclusions, credential helpers or tracing variables.

Check versions, then query one repositorysh
git --version
python3 --version
python3 git-proxy-check.py check 'https://git.example.org/team/project.git'

Enter the complete proxy username at the hidden prompt. Git then displays a password prompt naming the proxy: check that hostname before entering its original password. A later prompt naming the repository requires repository credentials instead. Cancel an unexpected prompt; never enter the proxy password for the repository host.

git-proxy-check.pypython
import getpass
import os
from pathlib import Path
import shutil
import subprocess
import sys
import tempfile
from urllib.parse import quote, urlsplit
import warnings


def run_check(repository, server, username, destination=None, ca_file=None):
    for value in (repository, server):
        if any(ord(c) <= 32 or ord(c) == 127 for c in value):
            raise ValueError("Invalid URL")
    repo = urlsplit(repository)
    proxy = urlsplit(server)
    if (repo.scheme != "https" or not repo.hostname or repo.username is not None
            or repo.password is not None or repo.query or repo.fragment):
        raise ValueError("Use an HTTPS repository URL without credentials")
    if (proxy.scheme != "http" or not proxy.hostname or proxy.port is None
            or proxy.username is not None or proxy.password is not None
            or proxy.path not in ("", "/") or proxy.query or proxy.fragment):
        raise ValueError("Use an HTTP gateway with its port, without credentials")
    if not username or ":" in username or any(ord(c) < 33 or ord(c) > 126 for c in username):
        raise ValueError("Use the complete printable proxy username without spaces")
    git = shutil.which("git")
    if not git:
        raise ValueError("Git was not found")
    target = Path(destination).resolve() if destination else None
    if target and (target.exists() or not target.parent.is_dir()):
        raise ValueError("Choose a new clone directory with an existing parent")
    ca = str(Path(ca_file).resolve(strict=True)) if ca_file else None
    with tempfile.TemporaryDirectory(prefix="git-proxy-check-") as directory:
        template = Path(directory, "empty-template")
        template.mkdir()
        child_env = {
            "PATH": os.defpath, "HOME": directory, "XDG_CONFIG_HOME": directory,
            "GIT_CONFIG_NOSYSTEM": "1", "GIT_CONFIG_SYSTEM": os.devnull,
            "GIT_CONFIG_GLOBAL": os.devnull, "GIT_CEILING_DIRECTORIES": directory,
            "GIT_TERMINAL_PROMPT": "1", "LC_ALL": "C",
        }
        command = [
            git, "-c", "credential.helper=",
            "-c", "http.proxy=http://" + quote(username, safe="") + "@" + proxy.netloc,
            "-c", "http.sslVerify=true", "-c", "http.followRedirects=false",
            "-c", "protocol.allow=never", "-c", "protocol.https.allow=always",
            "-c", "core.hooksPath=" + os.devnull,
        ]
        if ca:
            command += ["-c", "http.sslCAInfo=" + ca]
        if target:
            command += ["clone", "--depth=1", "--no-checkout",
                        "--template=" + str(template), "--", repository, str(target)]
        else:
            command += ["ls-remote", "--exit-code", repository, "HEAD"]
        # Git itself asks for the password on the terminal. No password argument,
        # environment variable, credential helper or password file is supplied.
        return subprocess.run(command, cwd=directory, env=child_env, check=False).returncode


def main():
    if os.name != "posix" or not sys.stdin.isatty():
        raise ValueError("Run in a macOS or Linux terminal")
    if len(sys.argv) not in (3, 4) or sys.argv[1] not in ("check", "clone"):
        raise ValueError("Usage: git-proxy-check.py check URL | clone URL NEW_DIRECTORY")
    mode, repository = sys.argv[1:3]
    if (mode == "clone") != (len(sys.argv) == 4):
        raise ValueError("Only clone takes a new directory")
    with warnings.catch_warnings():
        warnings.simplefilter("error", getpass.GetPassWarning)
        username = getpass.getpass("Full proxy username (hidden): ")
    return run_check(repository, os.environ.get("PROXY_SERVER", "http://gw.portproof.org:7000"),
                     username, sys.argv[3] if mode == "clone" else None,
                     os.environ.get("GIT_CHECK_CA"))


if __name__ == "__main__":
    try:
        sys.exit(main())
    except (ValueError, OSError, EOFError, KeyboardInterrupt, getpass.GetPassWarning):
        print("Check stopped. Verify the URLs, terminal and destination directory.")
        sys.exit(1)
Use this isolated route only where it is approved. PROXY_SERVER can name a different approved HTTP gateway with its port and no credentials. GIT_CHECK_CA can name an approved PEM CA file for the repository’s certificate chain. The child deliberately omits inherited organisation settings, so required trust, authentication or routing must be reviewed before use. It does not install software or alter your normal shell.

Git’s proxy configuration documents the username-only URL. Its credential rules explain how a terminal prompt is chosen. The password stays out of command arguments, environment variables and saved configuration in this example. The username remains visible in Git’s process arguments and password prompt; use a trusted machine and keep terminal recordings out of shared logs.

The script has no total elapsed-time deadline. Use Ctrl-C to stop an unresponsive check. It disables redirects for a predictable starting target: use the repository owner’s final HTTPS clone URL if the server redirects. These choices are diagnostic settings, not a complete unattended job configuration.

Interpret the reference result before cloning

Example result from the synthetic repositorytext
<commit-id>	HEAD

A commit ID followed by HEAD with exit status 0 means this invocation read that reference. With --exit-code, status 2 means no matching reference was advertised; an empty repository or missing HEAD needs investigation before calling the proxy broken. Other failures need their error context. The ls-remote reference explains this distinction.

Our local Git 2.50.1 check read HEAD through an authenticated CONNECT proxy and separately cloned a synthetic repository. A rejected password prevented the repository request, an untrusted certificate failed with verification enabled, and an approved local CA allowed the request. These are client-behaviour checks, not a live gateway, location or throughput measurement.

After a successful reference check, choose a new destination whose parent already exists. The clone leaves downloaded Git data in that destination. Review or remove that specific directory if the run fails; never delete an existing working repository to retry this diagnostic.

Download one shallow history without checking out filessh
python3 git-proxy-check.py clone 'https://git.example.org/team/project.git' /absolute/path/to/new-check-directory

The sample uses --depth=1 and --no-checkout, an empty template and disabled hooks. It does not request submodules or materialise a working tree. A shallow clone can still transfer a large object set; one commit is not a byte limit. The clone options describe the reduced history. Later checkout, large-file tools, submodules and builds remain separate operations to authorise and test.

Separate gateway, TLS and repository failures

Choose the next check from the failing stage
ObservationWhat to check
Cannot resolve or connect to the proxyCheck the selected gateway and HTTP port from this worker. A different computer’s successful request does not establish this path.
407 or CONNECT authentication refusedCheck the full proxy username, password, balance and gateway error code when available. Repository credentials do not authenticate the proxy.
Certificate verification fails after CONNECTCheck the repository hostname, certificate chain and approved trust. Keep verification enabled.
Repository 401, 403 or repository not foundConfirm the exact repository URL and read permission. Some services conceal a restricted repository behind a not-found response.
Reference check succeeds; clone failsCheck the object transfer and server response. A successful reference request does not test a complete pack download.
The isolated check works; the normal command failsCompare the actual remote transport, saved configuration and environment used by that command.

Use the 407 guide for gateway authentication, CONNECT diagnostics for tunnel refusals and the certificate guide for trust failures. An HTTP gateway’s CONNECT tunnel and a TLS connection to an HTTPS proxy are different layers; this script accepts an HTTP gateway only.

HTTP proxy authentication is carried on the connection to the gateway; the repository’s HTTPS tunnel does not encrypt that earlier HTTP hop. Use an approved network path. Do not turn off certificate checks, paste token-bearing URLs into commands or share credential-bearing traces to make a failing check easier to diagnose.

Apply the result to the actual Git workflow

Git can read system, user, repository and command settings, plus environment variables. The Git environment reference explains the configuration controls used here. Outside the script, a URL-specific HTTP setting, remote-specific proxy, proxy exclusion or URL rewrite can change the result. Inspect those locally; even configuration key names can contain repository addresses, so avoid sharing a full dump.

Keep a password out of git config, remote URLs and shell history. For repeated or unattended access, use your organisation’s reviewed credential helper or secret integration and verify its proxy-host context separately from the repository-host context. The terminal-only script deliberately does not read or save a helper credential and cannot validate that automation setup.

The position of -c matters: git -c key=value clone … supplies a Git command setting, while git clone -c key=value … writes a setting into the new repository. Our example uses the first form, so the proxy does not remain configured in the cloned repository. Subsequent commands need their own approved configuration.

An npm registry ping, pip index query or curl check does not verify Git dependencies. Test the actual Git process before returning to the package manager. Measure a representative permitted transfer with traffic accounting, then review current proxy options if this route fits the workload.

What is not allowed

Read or clone only repositories you are authorised to access, through an approved route. Respect repository terms, network policy and the acceptable-use policy.