Run Your Own Proxy

MUDBasher's proxy is open source. Point the app at your own copy and the background connection runs on a machine you control.

A proxy world in MUDBasher does not connect to your MUD from your phone. It connects to a small server that holds the telnet session for you, so iOS suspending the app does not kill the game connection. The connections guide explains why that is necessary.

By default that server is ours. It does not have to be. The proxy is a separate open source project, mud-web-proxy, released under GPL-3.0-or-later, and MUDBasher will talk to any instance of it you can reach over wss://. MUD administrators run one for their own game. Privacy-minded players run one on a VPS so their session never crosses our infrastructure.

The Two Setups

The shape is identical either way: three hops, two sockets, one persistent telnet connection held off your device. The only thing that moves is who operates the middle box.

Default: our proxy

Nothing to set up. Push alerts and silent-push background sync work. Your telnet traffic passes through a machine we run.

Self-hosted: your proxy

You supply the host, the domain and the certificate. Sessions survive backgrounding and replay when you return, but push notifications do not work. Your telnet traffic never touches our infrastructure.

What Changes When the Proxy Is Yours

MUDBasher treats proxies it does not recognise more cautiously than its own, and that costs you two features. Worth knowing before you spend an evening on it.

Our proxy

  • Session survives backgrounding
  • Buffered output replayed on return
  • Push notifications for events
  • Silent-push background sync
  • App Attest on every connection
  • We keep it patched and running
  • Traffic passes through our host

Your proxy

  • Session survives backgrounding
  • Buffered output replayed on return
  • No push notifications
  • No silent-push background sync
  • No App Attest
  • You patch it and keep it running
  • Traffic passes through your host
Why push stops. Push alerts are addressed to your device with an Apple push token, and the app only hands that token to the two proxy hosts we operate. A proxy at any other address is never sent it, so it has no way to reach your lock screen, and it cannot wake the app for a background sync either. This is deliberate: the token is device-derived data, and handing it to an arbitrary host is not a trade we make on your behalf. The consequence is real though. On a self-hosted proxy you find out what you missed when you reopen the app, not before.

For the same reason, App Attest is skipped for a self-hosted proxy: the app only attests to hosts it knows are ours. Leave REQUIRE_APP_AUTH off on your instance, or MUDBasher will be refused at the handshake.

What You Need

  • A host. A small Linux VPS is plenty. The proxy is a single process holding one socket pair per player.
  • A domain name pointing at it. iOS requires wss://, and wss:// requires a certificate, which requires a name. MUDBasher rejects plain ws:// for anything but localhost.
  • Inbound ports 80 and 443. Traffic runs on 443, but certificate issuance and renewal need 80. A firewall that only opens 443 is the usual cause of a certificate that quietly stops renewing.
  • Docker with Compose, or Bun. Two supported paths. Both put Caddy in front to terminate TLS and get certificates automatically.

Sessions live in memory only. Restarting the proxy to upgrade it disconnects everyone connected to it, and they reconnect from scratch. There is no handover.

Setting It Up

The repository is the authority on the commands, and it stays in step with the code in a way this page cannot. What follows is the shape of the job, so you know what it involves before you start.

1. Get the code
Clone mud-web-proxy and check out the current release rather than main.
2. Set four values
Copy the example environment file and fill in your domain, an email address for certificate notices, and the host and port of the MUD you want to reach. The examples ship empty on purpose, so an unedited copy fails immediately with a named error instead of starting on placeholder settings.
3. Start it
Either Docker Compose, which is the portable path, or Bun under systemd, which is the native single-VM path.
4. Check it
Request /health over HTTPS. A healthy instance answers with a status of healthy and the version actually running. If that works from a browser, the certificate and both ports are right.

The four values that matter

MWP_DOMAIN is the domain pointing at this host, e.g. proxy.example.com

MWP_ACME_EMAIL is where Let's Encrypt sends expiry notices

TN_HOST is the MUD to connect to, e.g. mud.example.com

TN_PORT is its port, e.g. 4000

Everything else has a default. The configuration reference covers every variable.

One MUD per proxy, by default. The proxy starts in a mode that permits exactly one destination, the TN_HOST and TN_PORT you configured, and refuses anything else with a message naming the target it does allow. Your MUDBasher world's hostname and port must match those two values exactly. If you want one proxy to serve several worlds, switch it to allowlist mode and name each host:port you intend to reach. See target policy before you widen it further than that.

Pointing MUDBasher at It

Per world, not globally. You can keep some worlds on our proxy, move others to yours, and leave the rest on a direct connection.

  • Edit the world and find Connection Mode.
  • Set it to Proxy. A Proxy URL field appears, pre-filled with our proxy.
  • Replace it with your own, as wss://proxy.example.com.
  • Check the world's hostname and port still match the TN_HOST and TN_PORT your proxy allows.
  • Save. The change applies on the next connection.

The field will not accept a URL that is not wss://, other than ws://localhost for testing against a proxy on your own machine. The session resume message carries an auth token, so cleartext to a remote host is refused rather than warned about.

If It Will Not Connect

  • The app rejects the URL as you type it. It is not wss://, or the host is empty. Only loopback may use ws://.
  • It connects, then closes immediately. Check the proxy's logs. A close from the proxy carries a reason naming the HTTP status it corresponds to, and the two you are likely to see are 401, meaning it wants authentication MUDBasher cannot supply, and 403, meaning an origin restriction is rejecting the app.
  • It refuses your MUD by name. The proxy is in fixed-target mode and your world's hostname and port do not match TN_HOST and TN_PORT exactly.
  • 401 on every attempt. Leave AUTH_MODE at none and REQUIRE_APP_AUTH off. MUDBasher has no field for a shared secret, and it does not attest to proxies it does not recognise as ours.
  • 403 on every attempt. Leave ALLOWED_ORIGINS unset. It exists to constrain browsers; a native app sends no origin header, and setting the variable makes an absent origin a refusal.
  • Certificate errors after a few months. Port 80 is closed. Renewal needs it even though traffic runs on 443.
  • Everyone drops at once. The proxy restarted. Sessions are in memory and do not survive it.

The operations guide has a troubleshooting entry for every startup error the proxy can refuse to start with, and the project tests that this stays true.

Docs and Help

Where each question is answered.
You want Go to
The install commands, start to finish README
The container path in full Docker Compose deployment
The single-VM path in full Native systemd deployment
Every setting and its default Configuration reference
What this exposes, and what it does not protect Security model
Certificates, upgrades, logs, health Operations
To ask a question Discussions
To report a bug in the proxy Issues

Problems with the proxy itself belong in that repository. Problems with the app talking to it belong on the support page. Tell us the proxy URL scheme you used and whether /health answers from a browser.

In short

Self-hosting moves the persistent telnet connection onto hardware you control and keeps your game traffic off ours. You keep background session survival and replay. You give up push notifications and background sync, and you take on a certificate, a host to patch, and a restart that disconnects your players.

If that trade suits you, the README is where to start.

MUDBasher, self-hosted proxy guide.