Px: a local proxy that answers the NTLM handshake so your apps do not have to
An HTTP proxy server to automatically authenticate through an NTLM proxy
At a glance
- What is it?
- Px is a Python HTTP and HTTPS proxy server that sits in front of an NTLM or Kerberos corporate proxy and completes the authentication handshake on your application's behalf, using Windows SSPI or an explicit username and password. It is MIT licensed, needs Python 3.10 or newer, and defaults to listening on port 3128.
- Who is it for?
- Px suits a developer on a corporate network whose tooling, a package manager or a CI runner cannot perform an NTLM handshake, because pointing the tool at a local Px instance turns the multi-leg negotiation into a single hop and the tool never sees the challenge at all.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem is a handshake most clients cannot do
The description is narrow and exact: an HTTP proxy server to automatically authenticate through an NTLM proxy.
The situation it addresses is common inside corporate networks. The upstream proxy requires NTLM or Kerberos authentication, which is a multi-leg conversation: the client sends a request, receives a challenge, computes a response using its logged-in Windows credentials, and repeats. Most command line tools, package managers and build systems do not implement that, so they either fail with an authentication error or prompt for credentials that do not exist on a non-Windows machine.
Px inserts itself in the middle. Applications point at Px, Px talks to the upstream proxy using libcurl, and the application never sees the handshake. The README states that Px leverages Windows SSPI or single sign-on and automatically authenticates using the currently logged in Windows user account, and that it is also possible to run Px on Windows, Linux and MacOS without single sign-on by configuring the domain, username and password.
That last sentence is the important one for adoption. A Windows-only tool would be of limited use; a proxy that runs anywhere and can be given a stored credential extends the same escape hatch to a Linux CI runner or a container.
The authentication coverage comes from libcurl. The README states that Px uses libcurl and supports all the authentication mechanisms supported by libcurl, and the --auth option accepts ANY, NTLM, NEGOTIATE, BASIC and NONE.
The audience is therefore a developer or system administrator working behind an authenticating corporate proxy, and the project is classified in its packaging metadata for system administrators as well as developers and end users on the desktop.
Five ways to install it, and what each one costs you
The install section offers more routes than most small tools, and the differences are practical rather than cosmetic.
pip install px-proxy
uv tool install px-proxy
pipx install px-proxyOn Windows, Winget and Scoop are also supported.
winget install genotrance.px
scoop install pxPrebuilt binaries and offline wheel packages are available on the releases page, and the installation guide covers all options including Docker, WinSW and source installs.
The offline wheel is the one to notice. Corporate environments frequently block PyPI or proxy it behind the authenticating proxy that Px exists to solve, which is a chicken-and-egg problem: you cannot pip install the tool that fixes your proxy access. An offline wheel sidesteps it, and a prebuilt binary sidesteps it further by removing the Python dependency too.
The packaging metadata confirms the shape of the distribution. The project name is px-proxy, the console script is px mapped to px.main:main, and there is a second entry point pxw in the gui-scripts group, which is the Windows GUI wrapper with the px.ico icon in the repository root. The classifiers list Win32, MacOS X and POSIX Linux environments, and Python 3.10 through 3.14, with requires-python set to 3.10 or newer. The README states the same requirement, Python 3.10 or above.
The runtime dependencies are worth reading as a description of the implementation: h11 for HTTP parsing, keyring and keyrings.alt for credential storage, netaddr for address handling, psutil for process information, pymcurl for the libcurl binding, pyspnego for the NTLM and Kerberos protocol work, python-dotenv for environment loading, and quickjs-ng, a JavaScript engine, which suggests some scripting is available in the configuration.
Configuration from four sources, one precedence order
Px can be configured via command-line flags, environment variables with the PX_ prefix, dotenv files, or px.ini. The full reference is in the configuration documentation, and px --help lists all the options.
The common options table in the README gives the shape of it.
--proxy=HOST:PORT
--pac=URL
--port=NUM
--gateway
--hostonly
--noproxy=LIST
--auth=TYPE
--username=DOMAIN\user
--log=4--proxy takes upstream proxy servers, comma-separated, and --pac takes a PAC file URL or a local path. --port sets the listening port with a default of 3128. --gateway allows remote clients and --hostonly restricts to local interfaces, which are the two flags that decide who can reach the proxy. --noproxy lists hosts or IPs that bypass the upstream proxy entirely.
The quick start section shows how these combine in practice.
# Run with an upstream proxy
px --proxy=proxyserver.com:8080
# Run with a PAC file
px --pac=http://example.com/proxy.pac
# Run with verbose logging
px --proxy=proxyserver.com:80 --verbose
# Save configuration to px.ini
px --proxy=proxyserver.com:8080 --save
# Test connectivity
px --testTwo of these deserve a second look. The --save flag writes the current configuration to px.ini, and there is a px.ini file in the repository root, so a deployment is a matter of editing that file rather than constructing a long command line in a service manager. And --test checks connectivity, which is the command you want before pointing anything at it.
The PAC file support is a nice touch. A PAC file expresses which hosts go through which proxy, and Px can consume that same expression, so a machine that already has a corporate PAC configuration does not need a second, hand-written bypass list.
Where the password lives, and where it should not
The credential story is the part of the design that most deserves care, and the README handles it in a specific order.
If SSPI is not available, you provide --username in domain\username format. The password is stored in the system keyring.
px --username=domain\username --passwordThe --password flag without a value is a prompt, which is the right shape for a command line tool: the secret is typed at the terminal rather than appearing in shell history or in a process listing.
PX_PASSWORD is described as an alternative when keyring is not available. That is the escape hatch, and it is the one to use carefully, because an environment variable is visible to other processes in many configurations and tends to end up in CI configuration files. The usage guide covers platform-specific keyring setup and client authentication.
The keyring dependencies in pyproject.toml are keyring and keyrings.alt, so the credential storage is treated as a real implementation problem rather than a detail.
Note what is not here. There is no option described for writing the credential into px.ini, and the --save flag saves the configuration, not a secret. That separation is the right design and it is worth confirming it holds in the configuration you end up running.
The build and test tooling is thorough
The development section requires uv, and the workflow is four commands.
git clone https://github.com/genotrance/px.git
cd px
make install
make testThe Makefile gives the full menu. make install creates the virtual environment, installs dependencies and installs pre-commit hooks. make check runs the linters and type checking, which the Makefile shows as pre-commit run -a followed by mypy. make test runs the suite with coverage, with pytest configured to run tests -n auto for parallel execution and to emit an XML coverage report. make benchmark runs concurrency benchmarks, and make test-large-data runs large data transfer reliability tests.
Then there are the container targets. make docker builds both a full image and a mini image from docker/Dockerfile. make test-kerberos is the interesting one: it builds a KDC in Docker and runs the Kerberos integration tests against it, with separate Dockerfiles for a MIT KDC, a Heimdal KDC and a Heimdal client. That is a serious testing decision, because it means the Kerberos path is exercised against a real KDC rather than mocked.
There is also a pair of targets that test the build itself in the two Linux C library worlds, make test-musl for Alpine containers and make test-glibc for manylinux containers.
The dev dependency group lists pytest, pytest-xdist, pytest-httpbin, pytest-cov, pre-commit, mypy and ruff, and pytest-httpbin explains how the HTTP layer is tested without reaching the internet.
The Makefile also derives the version from pyproject.toml and uses the TAG variable to tag the built Docker images, so the image version and the package version cannot drift apart.
Beta status, a work in progress, and the default that matters
The packaging metadata classifies the project as Development Status:: 4 - Beta, and the README says plainly that Px is definitely a work in progress and that any feedback or suggestions are welcome.
The release history shows v0.12.0 from 2026-07-21, v0.11.0 from 2026-04-03 and v0.10.3 from 2026-03-11, and the last push was on 2026-10-03. The default branch is devel rather than master, which is consistent with a project that ships releases from a development branch.
One default deserves attention. The listening port defaults to 3128, the conventional port for a proxy server, and the --gateway option is what allows remote clients, while --hostonly restricts to local interfaces. The presence of both flags implies the permissive behaviour is a mode you can select, and on a shared machine or a laptop on a public network, the distinction between a local listener and one reachable from the network is the difference between a convenience and an open relay to your corporate proxy.
The licence is MIT, in LICENSE.txt, and the README credits contributors and says Px is based on code from all over the internet, acknowledging innumerable sources. The project has a community presence through Gitter and Matrix rooms, and issues and pull requests are welcome on GitHub.
For a tool that sits between your applications and a corporate proxy, beta status and an MIT licence are a reasonable combination, and the documentation set is unusually complete for a project at that stage: installation, usage, configuration, architecture, build, testing and a changelog, all under docs/ in the repository.
Editorial conclusion
Px suits a developer on a corporate network whose tooling, a package manager or a CI runner cannot perform an NTLM handshake, because pointing the tool at a local Px instance turns the multi-leg negotiation into a single hop and the tool never sees the challenge at all. It is the wrong tool for a network without an authenticating upstream proxy, and it is the wrong choice if you need a forward proxy with filtering or caching, since Px is built to forward and authenticate rather than to police traffic. Before you deploy it, check that the upstream proxy's auth type matches what libcurl in your Px build supports, and note that the listening port defaults to 3128 and that the gateway and hostonly flags decide who can reach it before it runs anywhere shared.
Frequently asked questions
How do I install Px?
Run pip install px-proxy, uv tool install px-proxy or pipx install px-proxy. On Windows, winget install genotrance.px and scoop install px also work, and prebuilt binaries and offline wheel packages are on the releases page for networks where PyPI is unreachable.
What Python version does Px require?
Python 3.10 or newer. The README states the requirement and the packaging metadata sets requires-python to >=3.10, with classifiers for Python 3.10 through 3.14.
How does Px store the upstream proxy password?
If SSPI is not available you pass --username in domain\username format and the password is stored in the system keyring. The README notes that PX_PASSWORD can be used as an alternative when a keyring is not available.
Which upstream authentication types does Px support?
The --auth option accepts ANY, NTLM, NEGOTIATE, BASIC and NONE, and the README states that Px uses libcurl and supports all the authentication mechanisms supported by libcurl.
Can Px read a PAC file to decide which hosts go through the proxy?
Yes. The --pac option takes a PAC file URL or a local path, and the --noproxy option lists hosts or IPs that bypass the upstream proxy.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/genotrance-px)Was this useful?