A lightweight local proxy client for Minewire - it exposes a SOCKS5 or HTTP CONNECT proxy on your machine and tunnels traffic to a Minewire server disguised as Minecraft protocol traffic.
This is the core/CLI counterpart to the Minewire server. If you're looking for the old Flutter/Android client, that's a separate, partly outdated project - better not to use it for now.
- SOCKS5 or HTTP CONNECT local proxy - point your browser, curl, or system proxy settings at it
- AES-GCM Encryption - matches the server, keyed from your shared password
- Minecraft Camouflage - performs a real handshake/login/settings sequence before tunneling
- Stream Multiplexing - multiple simultaneous connections over one tunnel (yamux)
- Auto-Reconnect - maintains the tunnel session in the background with bounded backoff, and shuts down cleanly on Ctrl+C / SIGTERM
- Fast / Realistic modes - optionally throttle upload to match a server running in realistic mode
- Leveled logging -
error/warn/info/debug - Daemon mode - run as a background process controlled via line-delimited JSON over stdin/stdout, for a desktop UI to drive
- gomobile-ready core - the tunnel engine is a plain Go library (
src/core) with a thin Android facade (src/mobile) for building an.aar
- Go 1.22+ (only if building from source)
- A running Minewire server and a password that's whitelisted on it
Download the binary for your platform from Releases, place it next to client.yaml, edit the config, and run it.
git clone https://github.com/dmitrymodder/minewire-cli.git
cd minewire-cli
go mod tidy
go build -o minewire-cli ./src
./minewire-cliEdit client.yaml:
local_port: ":1080"
server_address: "IP_HERE:25565"
password: "PASSWORD_HERE"
proxy_type: "http" # "socks5" or "http"
mode: "fast" # "fast" or "realistic" - should match your server's mode
realistic_bandwidth_kb: 128
realistic_burst_kb: 512proxy_type: "socks5"gives you a plain SOCKS5 proxy onlocal_port(no auth).proxy_type: "http"gives you an HTTP proxy that supportsCONNECT(works for HTTPS and most system-wide "HTTP proxy" settings; plain unencrypted HTTP-only requests aren't proxied in this MVP).modeonly matters if the server you're connecting to is also running inrealisticmode - throttling only one direction of the tunnel doesn't accomplish anything.
./minewire-cli
# or explicitly:
./minewire-cli -config client.yaml -log-level infoThen point your browser / OS / app at 127.0.0.1:1080 using the proxy type you configured. Ctrl+C (or SIGTERM) now triggers a graceful shutdown instead of killing the tunnel mid-stream.
Flags:
| Flag | Default | Meaning |
|---|---|---|
-config |
client.yaml |
path to the config file (ignored in -daemon mode) |
-log-level |
info |
error, warn, info, or debug |
-daemon |
off | run in background/JSON mode instead of reading client.yaml |
-v / -version |
- | print version and exit |
Run with -daemon and the process no longer touches client.yaml - instead it reads newline-delimited JSON commands from stdin and writes newline-delimited JSON events to stdout. This is meant to be spawned as a child process by the UI and driven over its stdio pipes (no local socket/port to manage, no permission prompts).
Commands the UI sends (stdin), one JSON object per line:
Sending start again (e.g. after editing settings) swaps in a fresh engine after cleanly stopping the previous one - no need to stop first.
Events the daemon emits (stdout), one JSON object per line:
{"event":"status","data":{"running":true,"connected":true,"mode":"fast","proxy_type":"http","local_addr":":1080","server_address":"1.2.3.4:25565"}}
{"event":"log","level":"INFO","message":"connected and logged in"}
{"event":"error","message":"start failed: ..."}
{"event":"shutdown"}A status event is emitted automatically after start/stop, and can also be requested any time with {"cmd":"status"}. All log lines are mirrored as log events, so the UI doesn't need a separate channel to show what's happening. If the UI process dies and stdin just closes, the daemon stops the tunnel on its own rather than leaking a background connection.
Quick manual test:
echo '{"cmd":"start","config":{"local_port":":1080","server_address":"1.2.3.4:25565","password":"secret","proxy_type":"http","mode":"fast"}}' | ./minewire-cli -daemonThe core engine has no CLI/daemon-specific code in it, so it binds cleanly with gomobile:
go install golang.org/x/mobile/cmd/gomobile@latest
gomobile init
gomobile bind -o libminewire.aar -target=android ./src/mobileThis produces libminewire.aar exposing a mobile.Client with Start(...), Stop(), IsConnected(), LastError(), and a LogCallback interface to receive log lines in Kotlin/Java. See src/mobile/mobile.go for the exact signatures.
# Windows
GOOS=windows GOARCH=amd64 go build -o minewire-cli.exe ./src
# Linux
GOOS=linux GOARCH=amd64 go build -o minewire-cli-linux ./src
# Android AAR (needs gomobile + Android SDK/NDK set up)
gomobile bind -o libminewire.aar -target=android ./src/mobileThe protocol itself (packet IDs, handshake sequence, encryption, camouflage timing) is unchanged - only the code around it was restructured so the same core can run as a CLI, a background daemon, or an Android library.
minewire-cli/
├── client.yaml
├── go.mod
├── src/
│ ├── main.go # package main - thin entrypoint: flags, CLI mode vs daemon mode, signal handling
│ ├── core/ # package core - the actual engine, importable as a library
│ │ ├── engine.go # Engine type: Start/Stop/Status/Wait, replaces the old global session/cfg vars
│ │ ├── tunnel.go # Minecraft handshake, encrypted yamux tunnel, background camouflage traffic
│ │ ├── proxy.go # SOCKS5 and HTTP CONNECT handlers (now Engine methods)
│ │ ├── protocol.go # Minecraft protocol primitives (VarInt, String, etc.) - kept in sync with the server's
│ │ ├── throttle.go # token-bucket rate limiter used for realistic-mode upload throttling
│ │ ├── config.go # Config struct (shared by client.yaml and the JSON daemon protocol) + defaults
│ │ ├── logger.go # leveled logger (error/warn/info/debug) with an optional sink for log forwarding
│ │ └── daemon.go # JSON IPC control protocol (Commands in, Events out) over any io.Reader/io.Writer
│ └── mobile/ # package mobile - the ONLY nested subpackage, required by gomobile bind
│ └── mobile.go # flat, primitive-typed facade over core.Engine for Kotlin/Java consumers
MIT
{"cmd":"start","config":{"local_port":":1080","server_address":"1.2.3.4:25565","password":"...","proxy_type":"http","mode":"fast","realistic_bandwidth_kb":128,"realistic_burst_kb":512}} {"cmd":"stop"} // stop the tunnel + local proxy, process stays alive {"cmd":"status"} // ask for an immediate status snapshot {"cmd":"shutdown"} // stop everything and exit the process