Start, 5 minute read
Overview
Contents
A Minecraft Java Edition proxy written in Rust with embedded LuaJIT. Route hostnames through one port, authenticate players, switch backends, and manage configuration through Lua or the bundled web dashboard. No Java or separate Lua installation is needed to run Rift.
Rift can also supervise local Minecraft servers: start them on demand, stop empty servers, and operate their lifecycle from the CLI or web dashboard. Service groups can maintain minimum and spare capacity, scale from occupancy or queue pressure, and recover failed processes with bounded retries. Define local templates from server jars, plugins, configs and maps, then create instances with allocated ports and live backend registration. Persistent worlds retain files after removal; disposable game instances delete their generated files on removal. Both retain files across stop/start. See the managed-server guide, managed-server example, service groups and provisioning templates. The dashboard provides live server logs and commands, structured group/template editing, configuration deployment history and rollback, scoped operator tokens, and retained audit records. See the HTTP operator guide. Managed Minecraft processes need their own Java runtime and explicit EULA acceptance.
Quick start
Download a native archive from Releases, extract it, then run:
./rift init
# Edit listener and backend addresses in rift.lua.
./rift check
./riftOn Windows, use rift.exe. The default listener is 0.0.0.0:25565 and the backend
is 127.0.0.1:25566. rift init refuses to overwrite existing files. With no
arguments, Rift loads rift.lua from the current working directory if present
or uses those default addresses. rift check and rift --check validate that
same file by default. Use rift --config path/to/custom.lua to start with another
configuration file.
For a quick local run without a configuration file:
./rift 0.0.0.0:25565 127.0.0.1:25566Configure a local backend in server.properties:
server-ip=127.0.0.1
server-port=25566
online-mode=false
prevent-proxy-connections=falseThe default configuration uses unauthenticated offline identities. Keep
backend ports private and enable authentication for public Paper networks as
shown below. Offline backends should have forwarding disabled and
enforce-secure-profile=false.
Authentication
Start from examples/online.lua, which configures an authenticated lobby/survival network. Enable both fields in your Lua script:
rift.config.authentication = { online_mode = true, timeout_ms = 10000 }
rift.config.forwarding = { mode = "velocity", secret_env = "RIFT_FORWARDING_SECRET" }Set RIFT_FORWARDING_SECRET in Rift's environment. On each Paper backend, keep
online-mode=false in server.properties and settings.bungeecord=false in
spigot.yml, then configure config/paper-global.yml:
proxies:
velocity:
enabled: true
online-mode: true
secret: "the same secret as RIFT_FORWARDING_SECRET"Restart Paper after changing these settings. Rift verifies accounts with Mojang, handles client encryption, and forwards player identities to Paper. Failed verification never falls back to offline authentication.
Routing and configuration
Write an ordinary Lua script using rift.config; no outer return table is needed:
local config = require("rift.config")
config.listeners.public = "0.0.0.0:25565"
config.backends.lobby = "127.0.0.1:25566"
config.routes.public = "lobby"
-- Import lua/config/services.lua:
-- require("config.services")
-- Load plugins/greeting/init.lua and its lua/ modules:
-- rift.plugin("greeting")rift.on(event, callback) composes callbacks in registration order, and
rift.command(name, definition) registers authenticated commands. Local modules
and folder-based plugins are captured on load/reload, with paths relative to the
configuration file. Existing return { ... } configurations remain supported.
See the Lua API and modular example.
Generate a commented starter with rift init, or use the
network example for hostname routing, fallback, health
checks, rate limits and metrics. Hostname routing also works from the CLI:
./rift 0.0.0.0:25565 \
--route survival.example.com=127.0.0.1:25566 \
--route '*.games.example.com=127.0.0.1:25567' \
--default 127.0.0.1:25566Routes prefer exact names, then the longest wildcard suffix, then the default. Listeners require an IP and port; backends accept IPs or DNS names with ports.
Validate edits with rift check rift.lua. Reload with SIGHUP on Unix,
Ctrl-Break on Windows, or rift admin reload when administration is configured.
Invalid reloads retain the working configuration; existing sessions keep their
routes. Gameplay listener changes require a restart. Ctrl-C drains active
sessions for up to 30 seconds by default; a second Ctrl-C closes them immediately.
Authenticated extensions
Lua extensions provide login and transfer decisions, lifecycle events, commands with UUID permission checks, and FIFO server queues. API v2 adds durable namespaced state, recurring jobs, configured HTTP integrations and permissions that update during a session; v1 remains supported. The extension example demonstrates these APIs with a survival queue and staff-only server. See the extension API contract for ordering, deadlines, permissions and reload behavior. Extensions require online authentication and Java 1.19.3–26.3 (the online authentication range).
Compatibility
Minecraft Java 1.8.9 through 26.3, including all intervening releases, supports
login, /server, /hub, backend switching and crash recovery. All 66 releases
have checksum-pinned official server fixtures for joining, world/chunk delivery,
chat, switching, ban rollback and recovery. Older clients use Join Game/Respawn
world resets; 1.20.2+ uses the configuration phase.
See the protocol matrix and test scope.
Authenticated acceptance has a separate Paper test matrix for signed chat and commands, resource-pack acceptance/refusal and transfer cleanup, plus pinned LuckPerms/EssentialsX and ViaVersion/ViaBackwards combinations. CI runs their startup and rejection preflights; full acceptance requires a signed-in 1.21.11 client and records Paper observations alongside operator confirmations.
Clients and backends must use the same protocol version. Rift does not translate between Minecraft versions. Online authentication, Velocity modern forwarding and authenticated extensions require 1.19.3 or newer; earlier versions use offline backends with forwarding disabled. Bedrock/UDP, unlisted snapshots and legacy pre-1.7 pings are unsupported.
Set rift.config.network = { bungeecord = true } for existing backend plugins to
request transfers and query players/servers over the BungeeCord plugin channel.
See the supported subchannels and configuration.
Development
Building requires Rust (pinned in rust-toolchain.toml) and a C toolchain,
including MSVC on Windows. Python harnesses use the standard library.
cargo build --release --locked
cargo fmt --all --check
cargo clippy --locked --all-targets -- -D warnings
cargo test --locked --all-targets -- --test-threads=1
python3 -m unittest discover -s tests -p 'test_*.py'
node src/web_assets/tests.jsTo preview the documentation site, run npm ci and npm run serve in site/
(Node 24 or newer), then open http://localhost:4321.
CI also runs release tests, wire-protocol checks, real-server integration tests, benchmarks and packaging smoke tests. See the CI workflow and manual online-mode procedure for those checks.
On Linux, benchmark peers negotiate a 1460-byte TCP MSS to avoid loopback window stalls. Benchmark and pilot JSON reports record this cap; compare results with matching socket settings.
BSD-2-Clause. Run rift --license for the embedded license and
third-party notices, or rift --help for CLI usage.