Run a relay
Version 1.0.3 · 11 KB · Node 18+
On the same Wi-Fi you do not need any of this — the two phones find each other. A relay is for two people on different networks, or on a router that refuses to let its own devices see each other.
Why anything is in the middle at all
React Native ships a WebSocket client and nothing that listens, so for two phones to talk, one of them would have to be a server — and neither can be. Put something in the middle and both are clients, which is why playing over the internet turned out to be the cheaper path in this game rather than the dearer one.
It is stateless, so one is enough for everybody
A room is two live sockets and a display name, and it is gone when they hang up. Nothing is written to disk, nothing is read from a database, and no game message is ever parsed — the relay is a pipe. So this is not a server per game: one instance serves every player at once, and the smallest free tier anywhere is already more machine than it needs.
Download relay.js11 KB · one file · no dependenciesThree ways to run one
Numbered by how many people each one reaches, not by difficulty.
Deploy it once, and nobody types an address again
Reaches: everybody, forever
Any host that runs a container will do. The image is the Node base plus 11 KB, there is nothing to install, and
Dockerfile,render.yamlandfly.tomlcome with the packaged version.docker build -t dtbattle-relay . docker run -p 8787:8787 dtbattle-relayA host that terminates TLS gives you a
wss://address, which the game takes as-is — paste it into the Relay field and leave the port off. Give that one address to everyone who plays and multiplayer is done.Run it on a laptop the two players can reach
Reaches: the people in the room with it
Download the file above and run it. It prints every address it can be reached on, and on your own Wi-Fi it also shouts a beacon the game picks up — so on a LAN there is nothing to type at all: the relay appears in the lobby by name, for both players.
node relay.js node relay.js 9000 # a different portOr install it as a command, from the tarball the game repo’s packaging script writes:
npm install -g ./dtbattle-relay-1.0.3.tgz dtbattle-relayThe machine has no Node on it
Reaches: one stubborn machine
The game repo’s
tools/build_relay_dist.py --seabundles the script into a self-contained executable you can copy anywhere. It is about 110 MB for an 11 KB script, because the whole Node runtime rides along — which is why it is the last option rather than the first. Installing Node is the better trade nearly every time.
Using it in the game
Both players open Play together, pick Relay, and use the same address. Then either share a room code or leave it blank: a host with a blank code is given one, and a guest with a blank code gets the list of open rooms on that relay to tap — the same way the same-Wi-Fi lobby lists games.
What it does with what passes through it
It forwards bytes between two sockets and keeps nothing. There is no record of moves, no database, no account and no analytics — see the privacy policy for the rest. Run your own and the messages pass through your machine and nobody else’s.
Checking one is alive
Two plain HTTP endpoints, so answering “is it up” never needs a WebSocket client:
GET / -> dtbattle relay
rooms: 2
GET /rooms -> [{"code":"KEEP","name":"Rowan","mode":"versus"}]/rooms lists only rooms with a host and no guest — the ones a second player can actually join. The name and mode beside each are a label the hosting phone supplies in its own connect URL; the relay still never reads a game message.