PROXY Protocol Library for Asyncio
The `proxy-protocol` library provides an implementation of the PROXY protocol, including an `asyncio` server implementation, for Python. It currently supports versions 0.11.3 and is actively maintained with regular minor releases, focusing on improvements, bug fixes, and broader platform support.
Warnings
- breaking Version 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.
- breaking Version 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.
- gotcha The `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`.
- gotcha Using `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.
Install
-
pip install proxy-protocol
Imports
- ProxyProtocolDetect
from proxyprotocol.detect import ProxyProtocolDetect
- ProxyProtocolReader
from proxyprotocol.reader import ProxyProtocolReader
- SocketInfo
from proxyprotocol.sock import SocketInfo
- ProxyProtocolVersion
from proxyprotocol.version import ProxyProtocolVersion
Quickstart
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.")