Single‑package Python 3.11+ reverse proxy. Transparent HTTP/WebSocket relay: forwards the client's own X-API-Key / api_key as-is to hide the origin client IP. Does NOT inject any key — the backend validates the client key directly.
| Action | Command |
|---|---|
| Run server | fte-proxy run (all options via FTE_PROXY_* env vars or .env) |
| Editable install | pip install -e . |
| Run all tests | pytest (no extra flags; asyncio_mode = auto via pyproject.toml) |
| Ruff lint | ruff check . (line‑length 120, double quotes, select E/F/I/G) |
CLI entrypoint: proxy/main.py:cli (click group → run subcommand).
proxy/config.py—pydantic‑settingsBaseSettingswithenv_prefix="FTE_PROXY_"; auto‑loads.env. Backend URL (backend_url) is a private attribute (set via__init__), hardcoded tohttps://api.funtimeevents.su, not configurable via env/CLIproxy/http_proxy.py— catch‑all route/{tail:.*}→ replaces origin with backend, forwards headers as-is (stripsHost, overridesUser-Agent), returns 502 on upstream failureproxy/ws_relay.py— WebSocket relay at/v1/relay; forwards every text frame (including the clientauthframe with its ownapi_key) to the backend as-isproxy/logger.py— loguru with coloured stderr sink ({module}extra field in format)proxy/__init__.py— empty
- No test runners or pre‑commit scripts — just
pytestandruff check . - SSLContext built manually from
FTE_PROXY_TLS_CERT/FTE_PROXY_TLS_KEY(paths must exist on disk; validated at startup) .envis gitignored — copy.env.exampleand adjust host/port- pytest‑asyncio with
asyncio_mode = "auto"andasyncio_default_fixture_loop_scope = "function"— every test file is async by default, no decorators needed.pytest-aiohttpprovides theaiohttp_server/aiohttp_clientfixtures - Tests use
aiohttp_server/aiohttp_clientfixtures to spin up mock backends and proxy apps in‑process; no external services required _backend_urlis a private attribute (set via__init__, not a pydantic field) — tests pass it viaSettings(backend_url=...). Do not expose it as a public field or env var.
- HTTP proxy strips the
Hostheader from client and overridesUser-AgentwithFTE_PROXY_USER_AGENT - The proxy must NEVER add or replace
X-API-Key/api_key— client authentication is the backend's job (401 / 4001 on invalid key) - WebSocket: SDK sends
authframe first or the relay drops the connection silently - Proxy never caches, stores, or modifies response bodies — only headers