mchost 0.1.0

Run a Minecraft server jar and expose it through a Cloudflare Tunnel — no port forwarding, no public IP

minecraftminecraft-servercloudflare-tunnelwebsocketgame-servervanillano-port-forwardinginvitemod rusttokiotokio-tungsteniterustlswebsocketcloudflarecloudflaredfabric rustjava

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 typing stop in the MC console)
  • tunnel — show the current tunnel address
  • help — 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)

  1. Buy a domain and add it to Cloudflare (its DNS must be on Cloudflare).
  2. In the Zero Trust dashboard go to Networks → Tunnels → Create a tunnel, choose Cloudflared, name it.
  3. Copy the token from the install command Cloudflare shows you — that's the --token value for mchost.
  4. 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-port if you changed it)
  5. Run mchost server.jar --token <TOKEN>. mchost just runs cloudflared tunnel run --token ...; Cloudflare routes mc.example.com to your server, and players run mchost 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:

  1. It runs a WebSocket bridge on 127.0.0.1:8081 that maps each WebSocket session onto the local Minecraft TCP port (--bridge-port to change, --no-bridge to disable).
  2. It points the tunnel at the bridge (http://127.0.0.1:8081).
  3. mchost connect <url> (player side) opens a WebSocket to the tunnel and listens on 127.0.0.1:25565, so the player's unmodified Minecraft client just joins 127.0.0.1. Every local connection gets its own tunnel session, so several players behind one helper can play together (--bind 0.0.0.0 opens it to the whole LAN).

Practical notes:

  • Use --bridge-secret (and pass it with --secret on 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 is online-mode=true in server.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

click a file to view it · full files tab ↗

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

⑂ fork download bundle (.tar.gz) nd download mchost nd run mchost nd fork mchost /api/projects/mchost/context /api/projects/mchost/context readme recent small · by kenton · 31 files · 174304 bytes · 16 downloads · 52 views · updated 2026-10-16

doubles — similar projects

all doubles →