Skip to content

common: honor HTTP_PROXY/HTTPS_PROXY env vars in http client - #21752

Merged
ngxson merged 7 commits into
ggml-org:masterfrom
texasich:fix/proxy-env-vars-http-client
Oct 16, 2026
Merged

ngxson merged 7 commits into
ggml-org:masterfrom
texasich:fix/proxy-env-vars-http-client

Conversation

@texasich

Copy link
Copy Markdown
Contributor

Fixes #21694

What

common_http_client() builds the httplib client but never checks standard proxy environment variables, so any download that goes through this path (e.g. -hf flag, model presets) silently fails in environments that require a proxy.

How

After constructing the client, read HTTPS_PROXY/https_proxy for https:// URLs and HTTP_PROXY/http_proxy for http:// ones (scheme-specific takes precedence). If set and parseable, pass it to cli.set_proxy() and optionally cli.set_proxy_basic_auth(). Malformed proxy URLs are caught and silently ignored so nothing breaks for callers without a proxy configured.

Reuses the existing common_http_parse_url() to handle auth credentials embedded in the proxy URL (e.g. http://user:pass@proxy:3128).

Notes

  • NO_PROXY/no_proxy bypass list not implemented yet; can be added as follow-up
  • ALL_PROXY not checked; HTTPS_PROXY and HTTP_PROXY cover the common case
  • std::getenv is available via <cstdlib> already pulled in by httplib.h

@texasich
texasich requested a review from a team as a code owner April 11, 2026 01:06
@ggml-gh-bot

ggml-gh-bot Bot commented Apr 11, 2026

Copy link
Copy Markdown

Hi @texasich, thanks for your contribution!

Per our contribution guidelines, the automated PR checker found the following issue(s) that need your attention:

  • Multiple open PRs from a new contributor: We limit new contributors (those without a previously merged PR) to 1 open PR at a time. You currently have 2 open PRs.

Please note that maintainers reserve the right to make final decisions on PRs. If you believe there is a mistake, please comment below.

@texasich

Copy link
Copy Markdown
Contributor Author

closing this to get back under the 1-PR limit for new contributors — #21630 is closer to merging so keeping that one active. will reopen this once that lands. branch is preserved on my fork.

@texasich texasich closed this Apr 13, 2026
@texasich

Copy link
Copy Markdown
Contributor Author

reopening — #21630 just merged so the new-contributor limit no longer applies. ready for review whenever the maintainers have a minute.

@texasich texasich reopened this Apr 14, 2026
@MoRanYue

Copy link
Copy Markdown

Why is this still unmerged?

@texasich

Copy link
Copy Markdown
Contributor Author

Gentle nudge on this one — been open a while. Happy to rebase if there are conflicts, or make any changes needed. Let me know if anything's blocking review. 🙏

@BoneGoat

Copy link
Copy Markdown

Please consider this PR.

@nicriverhoo

Copy link
Copy Markdown

+1. Please consider this PR.

@MoRanYue

Copy link
Copy Markdown

For a modern software, not respecting to proxy is pretty bad.

@ngxson

ngxson commented May 28, 2026

Copy link
Copy Markdown
Collaborator

I'd assume most maintainers don't use proxy so no one can confidently review / test this PR (me including)

Asking @ServeurpersoCom for your thoughts about this feature / this implementation

@ServeurpersoCom

ServeurpersoCom commented May 28, 2026 •

Copy link
Copy Markdown
Contributor

Need to methodically test the HTTP client on Linux and on Windows with a small Squid as a classic enterprise forward proxy... I'm setting up the platform and will keep you updated.

@ServeurpersoCom

Copy link
Copy Markdown
Contributor

Tested this and the proxy path works fine for -hf, both direct and through the proxy, Linux only. Windows check in progress.

A few non-blocking notes:

  • NO_PROXY/no_proxy isn't honored. The client also fetches arbitrary --model-url, docker manifests and runtime image_url, but those are all external targets so it's not urgent, possible follow-up.

  • A malformed proxy url is caught silently, so it fails open and falls back to a direct connection with no log. A LOG_WRN in the catch would make that debuggable.

  • nit: for http you read uppercase HTTP_PROXY first. Out of habit a lot of code only trusts lowercase http_proxy for the http scheme and ignores the uppercase form, since httpoxy (see: https://httpoxy.org). It doesn't apply here since this isn't CGI, so it's purely cosmetic.

  • nit: the comment mentions checking the scheme var then a generic fallback, but both vars are scheme specific and there's no generic one, so it doesn't match the code.

@ServeurpersoCom

Copy link
Copy Markdown
Contributor

Windows OK, quick test with llama-installer.sh Wine + BorringSSL (default) with Zig. If OK, LGTM.

@ServeurpersoCom ServeurpersoCom left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarify or drop that comment, otherwise LGTM

Comment thread common/http.h Outdated
@texasich

texasich commented May 28, 2026 •

Copy link
Copy Markdown
Contributor Author

Dropped the misleading fallback comment, the code only has the two scheme-specific vars, no generic one. Good catch.

@ServeurpersoCom

Copy link
Copy Markdown
Contributor

It's a minimalist proxy support that will unlock GGUF downloads for a lot of users, and we can easily do a follow-up PR later if we need to expand it. You could add the env var to the docs, but it's a super standard one for every web app on Linux.

@texasich
texasich requested a review from ggerganov as a code owner May 28, 2026 17:08
@texasich texasich closed this May 30, 2026
@namniav

namniav commented Jun 11, 2026

Copy link
Copy Markdown

Thank you for the patch and it works for me.

May I ask if there is any issue that caused this PR to be closed without being merged?

@ServeurpersoCom

Copy link
Copy Markdown
Contributor

There's quite a bit of work pending on the proxy; I'll try to make progress this weekend.

@bsproger

Copy link
Copy Markdown

+1. Please consider this PR.

+1 from me too

@marecabo

marecabo commented Sep 5, 2026 •

Copy link
Copy Markdown
Contributor

@texasich Thanks for this feature. I addressed @ServeurpersoCom's review comments (no_proxy & logging) in texasich#1.
Note, that since 2026-07-08 #24948 no_proxy handling is required to ensure CLI loopback is not sent to proxy.

On top of that, I also merged master back in proxy-env-vars-merged (cc576d1) (just one small readme conflict), tested it on RHEL 9 with ZScaler and can confirm it works, see detailed logs in the PR.

@ServeurpersoCom

Copy link
Copy Markdown
Contributor

Needs a rebase, there's a README conflict with master. I already tested the proxy and network side, Linux and Windows, and it behaves as expected, so once that's sorted the only thing missing is a second approval.

Comment thread common/http.h Outdated
cli.set_proxy_basic_auth(proxy.user, proxy.password);
}
} catch (...) {
// ignore malformed proxy URL — don't break existing callers

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

per agents.md: no em-dash

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 5, 2026
@marecabo

Copy link
Copy Markdown
Contributor

@ServeurpersoCom
@texasich rebased the branch and it does not conflict now anymore. If there is anything left to do, please let me know.

@ServeurpersoCom

Copy link
Copy Markdown
Contributor

@ServeurpersoCom @texasich rebased the branch and it does not conflict now anymore. If there is anything left to do, please let me know.

Thanks @marecabo, the NO_PROXY handling and the warning look good.

Tested on Linux behind Squid: with HTTP_PROXY set and no NO_PROXY, llama cli now hangs forever on "Loading model...". It talks to its own server on 127.0.0.1 through common_http_client, so the /health polling goes to the proxy and gets a 403 in a loop. Same with lowercase http_proxy, and setting NO_PROXY=localhost,127.0.0.1 makes it work. Master works fine in the same setup, so this is a regression for exactly the users this PR targets.

We're not sure yet which way to fix it is best, there are a few options:

  • always bypass the proxy for loopback hosts (localhost, 127.0.0.0/8, ::1) in common_http_client, like Go's net/http does, though curl and Python don't, so it's not a universal convention
  • apply the proxy only on the download paths (download.cpp, hf-cache.cpp), leaving every other common_http_client caller direct as on master, but then --server-base to a remote server never goes through the proxy
  • keep the env handling as is and have llama cli reach its spawned server with a direct client, since it knows that address is local, which keeps --server-base proxy aware

@texasich

Copy link
Copy Markdown
Contributor Author

Good catch, thanks for the detailed report. Pushed a fix that makes common_http_client bypass the proxy unconditionally for loopback destinations (localhost, *.localhost, 127.0.0.0/8, ::1, 0.0.0.0): a remote proxy can never reach the machine's own loopback, so the 403 loop was unavoidable there. Same approach Go net/http uses. NO_PROXY handling and proxy support for downloads and remote --server-base endpoints stay unchanged. @marecabo GitHub shows the branch merging clean again, so nothing else needed on the rebase.

Comment thread README.md Outdated
Comment on lines +39 to +41
> [!TIP]
> If you're behind a corporate proxy, set the `HTTP_PROXY` and `HTTPS_PROXY` environment variables before running commands that download models (e.g. `export HTTPS_PROXY=http://proxy.example.com:8080`). Hosts listed in `NO_PROXY` and loopback addresses are contacted directly.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not a good place to put this, move it to server docs

@ngxson ngxson left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can merge once you resolve my remarks about docs

texasich and others added 7 commits October 15, 2026 23:50
common_http_client() was ignoring standard proxy env vars, causing
downloads via -hf and similar flags to fail silently in environments
behind an HTTP proxy (corporate networks, air-gapped infra, etc.).

Checks HTTPS_PROXY/https_proxy for https:// URLs and HTTP_PROXY/http_proxy
for http:// URLs, in that order. If a proxy URL is set and parseable,
passes it to httplib's set_proxy() and set_proxy_basic_auth() as
appropriate. Malformed proxy URLs are silently ignored so existing
callers aren't affected.

Fixes ggml-org#21694
The comment referenced a 'generic one' that doesn't exist in the code — both
HTTP_PROXY and HTTPS_PROXY are scheme-specific. Reviewer noted the mismatch.

Addresses review feedback from @ServeurpersoCom.
llama cli talks to its spawned server on 127.0.0.1 through common_http_client, so with HTTP_PROXY set and no NO_PROXY the health polling went to the corporate proxy, which rejects loopback targets, and the wait loop never exits ("Loading model..." hangs forever).

A remote proxy can never reach the client machine's own loopback, so these destinations are now always contacted directly, before NO_PROXY is consulted: localhost, *.localhost, 127.0.0.0/8, ::1 and 0.0.0.0. Similar to Go's net/http. Proxy handling for downloads and remote --server-base endpoints is unchanged.

Signed-off-by: texasich <101962694+texasich@users.noreply.github.com>
per review: the top level README stays lean; the proxy howto now lives with the server docs under Usage

Signed-off-by: texasich <101962694+texasich@users.noreply.github.com>
@texasich
texasich force-pushed the fix/proxy-env-vars-http-client branch from 55a122e to 3ba20f8 Compare October 16, 2026 05:11
@texasich
texasich requested a review from a team as a code owner October 16, 2026 05:11
@texasich

Copy link
Copy Markdown
Contributor Author

Moved. The tip is out of the README and now lives in tools/server/README.md under Usage (Running behind a proxy). Branch rebased onto current master. @ngxson

@ngxson
ngxson merged commit 7182ef7 into ggml-org:master Oct 16, 2026
9 of 12 checks passed
edwardyoon pushed a commit to edwardyoon/focus-llama that referenced this pull request Oct 24, 2026
…g#21752)

* common: honor HTTP_PROXY/HTTPS_PROXY env vars in http client

common_http_client() was ignoring standard proxy env vars, causing
downloads via -hf and similar flags to fail silently in environments
behind an HTTP proxy (corporate networks, air-gapped infra, etc.).

Checks HTTPS_PROXY/https_proxy for https:// URLs and HTTP_PROXY/http_proxy
for http:// URLs, in that order. If a proxy URL is set and parseable,
passes it to httplib's set_proxy() and set_proxy_basic_auth() as
appropriate. Malformed proxy URLs are silently ignored so existing
callers aren't affected.

Fixes ggml-org#21694

* common: drop misleading comment about generic proxy fallback

The comment referenced a 'generic one' that doesn't exist in the code — both
HTTP_PROXY and HTTPS_PROXY are scheme-specific. Reviewer noted the mismatch.

Addresses review feedback from @ServeurpersoCom.

* common : warn when the proxy URL from the environment is malformed

* common : honor NO_PROXY when selecting the http proxy

* ci : retrigger checks (test-thread-safety flake)

* common : bypass the proxy for loopback destinations

llama cli talks to its spawned server on 127.0.0.1 through common_http_client, so with HTTP_PROXY set and no NO_PROXY the health polling went to the corporate proxy, which rejects loopback targets, and the wait loop never exits ("Loading model..." hangs forever).

A remote proxy can never reach the client machine's own loopback, so these destinations are now always contacted directly, before NO_PROXY is consulted: localhost, *.localhost, 127.0.0.0/8, ::1 and 0.0.0.0. Similar to Go's net/http. Proxy handling for downloads and remote --server-base endpoints is unchanged.

Signed-off-by: texasich <101962694+texasich@users.noreply.github.com>

* docs: move proxy tip from README to server docs

per review: the top level README stays lean; the proxy howto now lives with the server docs under Usage

Signed-off-by: texasich <101962694+texasich@users.noreply.github.com>

---------

Signed-off-by: texasich <101962694+texasich@users.noreply.github.com>
Co-authored-by: texasich <texasich@users.noreply.github.com>
Co-authored-by: texasich <texasich@gmail.com>
Co-authored-by: marecabo <23156476+marecabo@users.noreply.github.com>
auRose94 pushed a commit to auRose94/llama.cpp that referenced this pull request Oct 28, 2026
…g#21752)

* common: honor HTTP_PROXY/HTTPS_PROXY env vars in http client

common_http_client() was ignoring standard proxy env vars, causing
downloads via -hf and similar flags to fail silently in environments
behind an HTTP proxy (corporate networks, air-gapped infra, etc.).

Checks HTTPS_PROXY/https_proxy for https:// URLs and HTTP_PROXY/http_proxy
for http:// URLs, in that order. If a proxy URL is set and parseable,
passes it to httplib's set_proxy() and set_proxy_basic_auth() as
appropriate. Malformed proxy URLs are silently ignored so existing
callers aren't affected.

Fixes ggml-org#21694

* common: drop misleading comment about generic proxy fallback

The comment referenced a 'generic one' that doesn't exist in the code — both
HTTP_PROXY and HTTPS_PROXY are scheme-specific. Reviewer noted the mismatch.

Addresses review feedback from @ServeurpersoCom.

* common : warn when the proxy URL from the environment is malformed

* common : honor NO_PROXY when selecting the http proxy

* ci : retrigger checks (test-thread-safety flake)

* common : bypass the proxy for loopback destinations

llama cli talks to its spawned server on 127.0.0.1 through common_http_client, so with HTTP_PROXY set and no NO_PROXY the health polling went to the corporate proxy, which rejects loopback targets, and the wait loop never exits ("Loading model..." hangs forever).

A remote proxy can never reach the client machine's own loopback, so these destinations are now always contacted directly, before NO_PROXY is consulted: localhost, *.localhost, 127.0.0.0/8, ::1 and 0.0.0.0. Similar to Go's net/http. Proxy handling for downloads and remote --server-base endpoints is unchanged.

Signed-off-by: texasich <101962694+texasich@users.noreply.github.com>

* docs: move proxy tip from README to server docs

per review: the top level README stays lean; the proxy howto now lives with the server docs under Usage

Signed-off-by: texasich <101962694+texasich@users.noreply.github.com>

---------

Signed-off-by: texasich <101962694+texasich@users.noreply.github.com>
Co-authored-by: texasich <texasich@users.noreply.github.com>
Co-authored-by: texasich <texasich@gmail.com>
Co-authored-by: marecabo <23156476+marecabo@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation server

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Misc. bug: Remote download fails behind proxy with -hf flag

9 participants