Install & Compatibility
Where this runs
tested against v0.11.3 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.95 runs
installs and imports cleanly · install 0.0s · import 0.066s · 18.4MB
glibcpy 3.10–3.95 runs
installs and imports cleanly · install 1.7s · import 0.062s · 19MB
16MB installed
● package 16MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
ProxyProtocolDetect
✓ from proxyprotocol.detect import ProxyProtocolDetect
ProxyProtocolReader
✓ from proxyprotocol.reader import ProxyProtocolReader
SocketInfo
✓ from proxyprotocol.sock import SocketInfo
ProxyProtocolVersion
✓ from proxyprotocol.version import ProxyProtocolVersion
This example sets up an asyncio server that listens for incoming connections. It uses `ProxyProtocolDetect` to automatically detect PROXY protocol v1 or v2 headers. Once a connection is established and the header is parsed (if present), the `on_connection` callback receives a `SocketInfo` object containing the original client and destination address details, and then echoes any received data back to the client. This demonstrates how to integrate `proxy-protocol` with a standard `asyncio.start_server` setup.
import asyncio
from asyncio import StreamReader, StreamWriter
from proxyprotocol.detect import ProxyProtocolDetect
from proxyprotocol.reader import ProxyProtocolReader
from proxyprotocol.sock import SocketInfo
async def on_connection(reader: StreamReader, writer: StreamWriter, info: SocketInfo) -> None:
print(f"Connection from: {info.family.name} {info.peername}")
print(f"Original client: {info.source_addr}:{info.source_port} -> {info.dest_addr}:{info.dest_port}")
# Echo back received data (optional, for demonstration)
while True:
data = await reader.read(1024)
if not data: break
writer.write(data)
await writer.drain()
writer.close()
await writer.wait_closed()
async def main(host: str, port: int) -> None:
pp_detect = ProxyProtocolDetect()
callback = ProxyProtocolReader(pp_detect).get_callback(on_connection)
server = await asyncio.start_server(callback, host, port)
async with server:
await server.serve_forever()
if __name__ == '__main__':
# To test, configure your proxy (e.g., HAProxy, NGINX) to send PROXY protocol
# to localhost:10007. Then connect to the proxy directly.
# Example with `netcat` after a proxy is set up:
# echo 'hello' | nc -q 1 localhost 10007
try:
asyncio.run(main('127.0.0.1', 10007))
except KeyboardInterrupt:
print("Server stopped.")
Debug
Known issues
breakingVersion 0.11.0 changed how address family (AF_*) constants are handled internally to enable support for Windows. This change 'Avoid using AF_* as proxy result type' might subtly affect applications that previously relied on specific `AF_*` values or behavior on non-Windows platforms, although it primarily enabled broader compatibility.fixReview code that interacts with `SocketInfo.family` or other address family-related attributes. Ensure compatibility with potentially updated or normalized `AF_*` values, especially if you manually handle socket families.
affects: 0.11.0
breakingVersion 0.9.0 introduced a 'rework of the API with better abstractions.' This signifies significant changes to the library's interfaces and how components are used. Existing code written against older APIs will likely break.fixConsult the official release notes and documentation for 0.9.0 and later to understand the new API structure. Update import paths and method calls according to the new abstractions, particularly around `ProxyProtocolReader` and how callbacks are registered.
affects: 0.9.0
gotchaThe `proxy-protocol` library, when handling PROXY protocol v2, can throw a 'bad exception' if the optional `crc32c` module is missing. While fixed in 0.11.2 to gracefully handle the absence, earlier versions might crash or behave unexpectedly. Even with the fix, performance or full checksum validation for v2 might be impacted without `crc32c`.fixFor robust PROXY protocol v2 handling, especially in environments where checksum validation is critical, ensure `crc32c` is installed (`pip install crc32c`). If not installed, be aware that v2 checksums cannot be validated, even if the library handles the missing module gracefully.
affects: <0.11.2 (potential for hard crash), >=0.11.2 (graceful, but missing feature)
gotchaUsing `ProxyProtocolVersion.get(None)` or similar configurations for a `ProxyProtocolReader` explicitly disables PROXY protocol header detection. This means the server will treat all connections as direct, without parsing any PROXY headers, potentially leading to incorrect source IP information.fixCarefully configure `ProxyProtocolReader` or `ProxyProtocolVersion`. If you intend to detect and use PROXY protocol headers, use `ProxyProtocolVersion.get('detect')`, `ProxyProtocolVersion.get('v1')`, or `ProxyProtocolVersion.get('v2')` as appropriate, rather than `None`. affects: All versions
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'proxyprotocol'
The `proxy-protocol` library has not been installed or the Python environment where the code is run does not have it installed.
fixInstall the library using pip: `pip install proxy-protocol`
from proxyprotocol.detect import ProxyProtocolDetect
ModuleNotFoundError: No module named 'proxyprotocol.detect'
The specific submodule `detect` (or another submodule like `reader`, `sock`, `version`) cannot be found, possibly due to a typo in the import path or an incomplete installation.
fixEnsure the library is correctly installed (`pip install proxy-protocol`) and verify the exact import path against the library's API reference or examples.
ConnectionResetError: [WinError 10054] An existing connection was forcibly closed by the remote host
This error often occurs when an `asyncio` server using `proxy-protocol` expects a PROXY protocol header, but the connecting client either does not send one, sends a malformed one, or closes the connection prematurely. The server interprets the unexpected data (or lack thereof) as a protocol violation and closes the socket.
fixEnsure the client connecting to the `proxy-protocol` server is configured to send valid PROXY protocol headers (either v1 or v2). If the client should not send PROXY protocol, configure the server to either not use `proxy-protocol` for that listener or handle non-PROXY protocol connections gracefully.
TypeError: 'ProxyProtocolReader' object is not callable
This error typically arises when attempting to use an instance of `ProxyProtocolReader` directly as a callback function for `asyncio.start_server`, instead of calling its `get_callback()` method.
fixWhen using `ProxyProtocolReader` with `asyncio.start_server`, you must provide the callback returned by `get_callback()`: `callback = ProxyProtocolReader(pp_detect).get_callback(on_connection)`
Upgrade
Version history
0.11.3latest on PyPI · released Apr 27, 2024
Audit
Dependencies
python>=3.8requiredRequired Python version as specified by PyPI metadata.
crc32coptionalOptional dependency for PROXY protocol v2 checksum validation. If missing, v2 handling might raise exceptions or lack full validation.