mchost 0.1.0
Run a Minecraft server jar and expose it through a Cloudflare Tunnel — no port forwarding, no public IP
what it is
mchost runs a vanilla Minecraft server jar and exposes it through a Cloudflare Tunnel with a WebSocket bridge, since Cloudflare edges only speak HTTP(S) and not raw Minecraft TCP. Players join by pasting one invite string into the bundled Fabric client mod or the `mchost connect` CLI helper. Supports quick tunnels (default, random trycloudflare.com name) and named tunnels via a Cloudflare Zero Trust token.
readme
mchost
Run a Minecraft server jar and expose it through a Cloudflare Tunnel — no port forwarding, no public IP.
Two tunnel modes:
| Mode | Flag | Address players see | Cloudflare account needed? |
|------|------|---------------------|----------------------------|
| Quick tunnel | (default) | a random something-words.trycloudflare.com name, new on every run | no |
| Named tunnel | --token <TOKEN> | the domain you bought and pointed at Cloudflare | yes (token from the Zero Trust dashboard) |
How players join
Cloudflare's tunnel edge only speaks HTTP(S), not raw Minecraft TCP, so mchost runs a small WebSocket bridge and points the tunnel at it. Players connect through the tunnel with either:
- the Fabric client mod (in-game: Multiplayer → Tunnel... → paste the invite), or
- the CLI helper
mchost connect <invite>— same thing without the mod.
Both accept one shareable invite string that mchost prints (and writes to
mchost-address.txt for the server mod to show in-game):
┌──────────────┐ vanilla MC ┌────────────────┐ WebSocket over TLS ┌────────┐ ws ┌────────┐
│ MC client │─────────────▶│ mod / helper │─────────────────────▶│tunnel │─────▶│ bridge │──▶127.0.0.1:25565
│127.0.0.1:25565│ │ (player runs) │ wss://<tunnel-url> │ edge │ │(server)│
└──────────────┘ └────────────────┘ └────────┘ └────────┘
They paste one line and play in their normal vanilla client — no port forwarding, no public IP.
Build
cargo build --release # binary: target/release/mchost
Requires: Rust to build, Java 21+ to run a modern server jar, and the
cloudflared binary on your PATH (or pass --cloudflared <path>).
Quick start (with the bundled Fabric server)
If you've installed the Fabric server into server/ (see mod/README.md):
./start.sh # builds mchost if needed, starts server/ behind a
# quick tunnel with a random invite secret
SECRET=hunter2 ./start.sh # stable invite secret
TOKEN=eyJh... PUBLIC_HOST=mc.example.com ./start.sh # your own domain
./start.sh --no-tunnel # local only
The first run writes eula=true to server/eula.txt (accepting
Minecraft's EULA on your behalf — only run it
if you're fine with that). DRY_RUN=1 ./start.sh prints the command instead.
Usage
# Quick tunnel: random trycloudflare.com name, no account
mchost server.jar
# Accept the Minecraft EULA for you and give the JVM 4G
mchost -m 4G --eula server.jar
# Named tunnel: served from your purchased domain (see setup below)
mchost server.jar --token eyJhIjoiXXXXXXXX...
# Local only
mchost --no-tunnel server.jar
# Extra arguments for the server jar go after --
mchost paper.jar -- -XX:+UseG1GC
# Player side: share the tunnel as a local TCP port for a vanilla client
mchost connect https://funny-name.trycloudflare.com --secret my-secret
# ...or paste the short invite mchost prints:
mchost connect 'mchost://funny-name.trycloudflare.com/mc?s=my-secret'
The server prints the exact invite to share with players whenever the tunnel
comes up (and again when you type tunnel). The same invite is written to
mchost-address.txt in the server directory, which the Fabric server mod
turns into a click-to-copy chat message in-game.
If you don't name a jar, mchost picks the newest server-looking jar in the
server directory. The port is read from server.properties (server-port,
default 25565) or forced with --port.
Everything the server prints shows up prefixed with [server], everything
cloudflared prints with [tunnel]. While it runs you can type into the console:
stop— gracefully stop the server (same as typingstopin the MC console)tunnel— show the current tunnel addresshelp— list commands- anything else — forwarded straight to the Minecraft server console
Ctrl-C does a graceful stop too (second Ctrl-C forces). A quick tunnel that
drops is restarted automatically with a fresh random name (up to --restarts,
default 5).
Named tunnel setup (purchased domain)
- Buy a domain and add it to Cloudflare (its DNS must be on Cloudflare).
- In the Zero Trust dashboard go to Networks → Tunnels → Create a tunnel, choose Cloudflared, name it.
- Copy the token from the install command Cloudflare shows you — that's the
--tokenvalue for mchost. - Still in the tunnel's configuration, add a Public Hostname:
- Subdomain/Domain: e.g.
mc.example.com - Service: type HTTP, URL
http://localhost:8081— the WebSocket bridge mchost runs (use your--bridge-portif you changed it)
- Subdomain/Domain: e.g.
- Run
mchost server.jar --token <TOKEN>. mchost just runscloudflared tunnel run --token ...; Cloudflare routesmc.example.comto your server, and players runmchost connect https://mc.example.com --secret ...as usual.
(If you run with --no-bridge and Cloudflare Spectrum, use service type TCP
and localhost:25565 instead — then players connect directly, no helper.)
How it works (and why a bridge)
Cloudflare's tunnel edge is HTTP-only: a vanilla Minecraft client cannot speak
raw TCP to a *.trycloudflare.com name or a tunnelled custom domain. mchost
handles that end to end:
- It runs a WebSocket bridge on
127.0.0.1:8081that maps each WebSocket session onto the local Minecraft TCP port (--bridge-portto change,--no-bridgeto disable). - It points the tunnel at the bridge (
http://127.0.0.1:8081). mchost connect <url>(player side) opens a WebSocket to the tunnel and listens on127.0.0.1:25565, so the player's unmodified Minecraft client just joins127.0.0.1. Every local connection gets its own tunnel session, so several players behind one helper can play together (--bind 0.0.0.0opens it to the whole LAN).
Practical notes:
- Use
--bridge-secret(and pass it with--secreton the player side). Quick-tunnel URLs are public-ish; the secret makes the bridge answer 401 to strangers and the helper fails fast with a clear message. As always, real protection isonline-mode=trueinserver.properties. - Right after a quick tunnel starts, its random name can take a few seconds to appear in DNS. The helper retries on its own and reports progress.
- The WebSocket rides an HTTP/1.1 upgrade. Generic HTTP tools that default to HTTP/2 (curl, for instance) will get a 502 from the bridge — that is the edge, not a bug; the helper speaks HTTP/1.1 and works.
- If you want vanilla-direct connections with no helper, you need one of:
Cloudflare Spectrum (paid TCP proxying) with
--no-bridge, a Zero Trust private network + WARP on the players' side, or a TCP tunnel tool built for it (playit.gg, ngrok TCP, a VPS + Tailscale).
Minecraft mods (Fabric)
mod/ contains two optional Fabric mods for Minecraft 26.3 that make
sharing fully in-game:
- mchost client — a Tunnel... button in the Multiplayer screen: players paste the invite and join with a vanilla client, no CLI needed. Remembers the last invite.
- mchost server — shows the invite in chat, click-to-copy: when mchost
publishes it, when an operator joins, and via
/mchost.
Build with ./gradlew build in each folder (JDK 25, see mod/README.md).
Use --public-host mc.example.com with --token so the invite uses your own
domain.
Options
mchost [SERVER_JAR] [options]
-j, --jar <PATH> Server jar to run (auto-detected when omitted)
-d, --dir <PATH> Server working directory (default: the jar's directory)
--java <PATH> Java executable (default: java)
-m, --memory <SIZE> JVM heap, e.g. 2G or 4096M (default: 2G)
-p, --port <PORT> Minecraft port (default: server.properties, else 25565)
--eula Write eula=true into eula.txt (accept the Minecraft EULA)
--token <TOKEN> Cloudflare Tunnel token (named tunnel on your domain)
--no-tunnel Run without any tunnel
--cloudflared <PATH> Path to the cloudflared binary
--restarts <N> Quick-tunnel restart budget (default: 5)
--bridge-port <PORT> Local port of the WebSocket bridge (default: 8081)
--bridge-secret <S> Require this secret from joining players
--no-bridge Disable the bridge (Spectrum/TCP-style setups only)
-h, --help Show help
-V, --version Show version
mchost connect <URL> [options]
--local-port <PORT> Local TCP port for the vanilla client (default: 25565)
--bind <ADDR> Local address to listen on (default: 127.0.0.1)
--secret <SECRET> The server's --bridge-secret value, if it has one
files
31 files — expand to browse
mod/
client/
gradle/
src/
main/
java/
dev/
mchost/
client/
config/
screen/
tunnel/
resources/
try it
$ cargo build --release
$ ./start.sh
built on
CachyOS · x86_64 · 12th Gen Intel(R) Core(TM) i9-12900K (24 cores) · 31.1 GB ram · gpu: GPU[0] : Card Series: AMD Radeon RX 9070 XT
nd download mchost
nd run mchost
nd fork mchost
/api/projects/mchost/context
/api/projects/mchost/context