Metadata-Version: 2.4
Name: pyhaproxy-lb
Version: 0.1.1
Summary: HAProxy-like L7 load balancer and reverse proxy in pure Python (async).
Author: Kubenew
License: MIT
License-File: LICENSE
Keywords: asyncio,haproxy,http,load-balancer,reverse-proxy
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27.0
Requires-Dist: prometheus-client>=0.20.0
Requires-Dist: pyyaml>=6.0.1
Requires-Dist: starlette>=0.37.2
Requires-Dist: typer>=0.12.3
Requires-Dist: uvicorn>=0.30.0
Provides-Extra: dev
Requires-Dist: pyhaproxy[test]; extra == 'dev'
Requires-Dist: ruff>=0.1; extra == 'dev'
Provides-Extra: test
Requires-Dist: httpx>=0.27.0; extra == 'test'
Requires-Dist: pytest-asyncio>=0.21; extra == 'test'
Requires-Dist: pytest>=7.0; extra == 'test'
Description-Content-Type: text/markdown

# pyhaproxy

[![PyPI](https://img.shields.io/pypi/v/pyhaproxy)](https://pypi.org/project/pyhaproxy/)
[![Python Versions](https://img.shields.io/pypi/pyversions/pyhaproxy)](https://pypi.org/project/pyhaproxy/)
[![License](https://img.shields.io/pypi/l/pyhaproxy)](https://github.com/Kubenew/pyhaproxy/blob/main/LICENSE)
[![Tests](https://img.shields.io/github/actions/workflow/status/Kubenew/pyhaproxy/ci.yml?label=tests)](https://github.com/Kubenew/pyhaproxy/actions)

**pyhaproxy** is a minimal HAProxy-like reverse proxy and load balancer written in Python.

This is **not** a wrapper around the HAProxy binary. It is a pure Python async implementation focused on extensibility.

## MVP Features

- **Frontends** — bind to multiple host:port pairs, each with its own routing rules
- **ACL-like routing** — route requests by `host` or `path_prefix`
- **Backend pools** — groups of servers behind a single backend name
- **Load balancing** — round-robin and least-connections
- **Health checks** — concurrent async HTTP checks per backend
- **Prometheus metrics** — request count and latency histograms
- **Connection pooling** — shared `httpx.AsyncClient` with keep-alive
- **X-Forwarded-* headers** — automatically added to proxied requests

## Quickstart

```bash
pip install pyhaproxy
```

### Run

```bash
pyhaproxy run -c examples/config.yml
```

### Test

```bash
curl -H "Host: example.com" http://localhost:9000/
curl -H "Host: example.com" http://localhost:9000/api/users
```

## Example Config

```yaml
frontends:
  - name: "http_front"
    bind: "0.0.0.0:9000"
    default_backend: "app_backend"
    rules:
      - if: "host == example.com"
        backend: "app_backend"
      - if: "path_prefix == /api"
        backend: "api_backend"

backends:
  app_backend:
    balance: "roundrobin"
    servers:
      - url: "http://localhost:5000"
      - url: "http://localhost:5001"
  api_backend:
    balance: "leastconn"
    servers:
      - url: "http://localhost:6000"

healthcheck:
  enabled: true
  interval_seconds: 5
  timeout_seconds: 2
  path: "/health"

metrics:
  enabled: true
  path: "/metrics"
```

## Architecture

```
Client ──► Uvicorn ──► Starlette ──► Frontend.resolve_backend()
                                         │
                                    ┌─────▼──────┐
                                    │  ACL rules  │
                                    │ host/path   │
                                    └─────┬──────┘
                                          │ backend name
                                          ▼
                                    BackendRegistry
                                          │
                                    ┌─────▼──────┐
                                    │  Balancer   │
                                    │ RR / Least  │
                                    └─────┬──────┘
                                          │ server URL
                                          ▼
                                   proxy.forward()
                                          │
                                    ┌─────▼──────┐
                                    │  Backend    │
                                    │  server     │
                                    └────────────┘
```

## Changelog

### 0.1.1
- **Multi-frontend support**: CLI now runs all configured frontends concurrently.
- **Connection pooling**: Shared `httpx.AsyncClient` with keep-alive limits (was creating a client per request).
- **Concurrent health checks**: Servers are checked in parallel via `asyncio.gather`.
- **X-Forwarded-* headers**: Proxied requests now include `x-forwarded-for`, `x-forwarded-proto`, `x-forwarded-host`.
- **Better error messages**: Balancer errors say "at least one server".
- **Improved type annotations**: Full type hints on all public classes.
- **Comprehensive tests**: Balancers, config, registry, frontend, ACL, proxy.

## License

MIT
