MURX
Multi-User Resource eXchange — an authenticated routing gateway protocol. Authenticate once, get redirected to the right backend node, and the gateway is never in the data path again.
One gatekeeper, two jobs
A MURX server sits in front of a pool of backend application servers and does what would otherwise be two separate systems: it authenticates the client, and it tells the client which backend node to actually use. It never proxies the application data itself.
Authentication encapsulation
A secure envelope for client credentials. The MURX server is a centralized gatekeeper on port 2743, so unauthenticated traffic never reaches a backend application server.
Dynamic connection routing
On success, MURX doesn't serve the resource itself — it calculates the best backend node (by load, privileges, or proximity) and hands back its network coordinates.
Handoff via token
The routing reply includes a one-time, short-lived token. The client presents it to the assigned backend to prove it already cleared MURX authentication.
Architecture at a glance
Both transports share port 2743: TCP carries the client-facing handshake, UDP keeps the server's live backend registry current.
Example: a user@domain login
A common Client ID convention is
user@domain — the same shape as an email address —
with the password as the opaque credential. The domain
part doubles as the discovery key: by default a client just
connects to murx.<domain> on port 2743, no DNS
record required, with an SRV lookup as an optional override. The
backend here could just as easily be a database shard, a game
server instance, or a chat homeserver — MURX doesn't care what
it's gatekeeping.
import asyncio
from murx import MurxClient, resolve_murx_server, split_client_id
async def main():
client_id = "[email protected]"
_, domain = split_client_id(client_id)
host, port = await resolve_murx_server(domain)
route = await MurxClient.authenticate(
host=host, port=port,
client_id=client_id, auth_data=b"hunter2",
)
reader, writer = await MurxClient.connect_to_backend(route)
# reader/writer is now an authenticated session with whichever
# backend node MURX decided to route this client to.
asyncio.run(main())