A super fast reverse tunnel system written in Rust that allows you to expose local services to the internet through secure tunnels. Similar to ngrok or Cloudflare Tunnel, but self-hosted.
Do you want to show your local web server to a friend? Or open up a local Minecraft server to play with others? Maybe test webhooks without deploying?
NRelay is a reverse proxy tunneling solution that consists of a relay server (running on a public server) and clients (running locally). It allows you to expose local development servers, APIs, or any network service to the internet without port forwarding or firewall configuration.
- Multiple Protocol Support: HTTP, HTTPS (TLS/SNI), TCP, UDP, Minecraft, and SSH - all in one tool
- Flexible Routing: Hostname-based routing for HTTP/HTTPS, port-based for TCP/UDP
- Self-Hosted: Run it on your own infrastructure with complete control
- High Performance: Built with Rust and Tokio for blazing fast async I/O
- Token-Based Security: Each tunnel gets its own unique authentication token
- Origin Management: Easily organize and manage multiple relay server configurations
- Admin API: RESTful API for programmatic tunnel management
- Protocol Sniffing: Automatically routes traffic based on intelligent protocol detection
| Protocol | Exposure Mode | Default Port | Routing Method |
|---|---|---|---|
| HTTP | Hostname | 80 | Host header |
| HTTPS/TLS | Hostname | 443 | SNI (Server Name Indication) |
| TCP Raw | Port | 20000-30000 | Direct port mapping |
| UDP Raw | Port | 30000-40000 | Direct port mapping |
| Minecraft | Port | 25565 | Handshake parsing |
| SSH | Port | 20000-30000 | Direct port mapping |
- Rust: 1.70 or higher
- Operating System: Linux, macOS, or Windows
- Public IP Address: Required for the relay server
- Open Ports:
- Control port (default: 7000)
- Admin API port (default: 7001)
- Protocol-specific ports (80 for HTTP, 443 for HTTPS, etc.)
- Rust: 1.70 or higher
- Network Access: Ability to connect to the relay server's control port
Make sure you have Rust installed. If not, install it from rustup.rs:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shClone the repository and build all components:
git clone https://github.com/sammwyy/NRelay.git
cd NRelay
# Build all workspace members
cargo build --release
# Binaries will be available in target/release/
# - nrelay (CLI tool)
# - nrelay_server (Relay server)
# - nrelay_client (Tunnel client)# Install all binaries to ~/.cargo/bin/
cargo install --path nrelay
cargo install --path nrelay_server
cargo install --path nrelay_clientπ‘ Pro Tip: Make sure
~/.cargo/binis in your PATH to run the binaries from anywhere!
On your public server, start the relay server:
# Set admin API token
export ADMIN_TOKEN="your-secret-admin-token"
# Run the server
nrelay_server \
--control-port 7000 \
--admin-port 7001 \
--domain yourdomain.comServer Options:
--control-port: Port for client control connections (default: 7000)--admin-port: Port for admin API (default: 7001)--admin-iface: Interface to bind admin API (default: 0.0.0.0)--domain: Base domain for hostname-based tunnels--admin-token: Bearer token for admin API authentication (can use env var)
Add your relay server as an "origin":
nrelay origin add myserver \
--server relay.yourdomain.com:7000 \
--admin-url http://relay.yourdomain.com:7001 \
--token your-secret-admin-token \
--kind serverOrigin Modes:
--kind server(self-hosted): CLI acts as ADMIN, directly connects to relay server. Use this for personal/self-hosted deployments.--kind service(SaaS mode, default): CLI acts as USER, requests permissions from a backend service. Used for team/business deployments with dashboard authentication. (Note: SaaS backend not yet implemented)
π‘ Pro Tip: For self-hosted deployments, always use
--kind serverto avoid permission errors!
List configured origins:
nrelay origin listSet default origin:
nrelay origin set-default myserverπ‘ Pro Tip: Once you set a default origin, you won't need to specify
--originin your tunnel commands!
Expose a local HTTP server:
# Expose localhost:8080 via HTTP
nrelay http localhost:8080
# Output: Your tunnel is available at http://{tunnel-id}.yourdomain.comExpose a local HTTPS server:
nrelay https localhost:8443Expose a local TCP service:
# Expose local SSH server
nrelay tcp localhost:22
# Output: Your tunnel is available at relay.yourdomain.com:25432Expose a Minecraft server:
nrelay minecraft localhost:25565π‘ Pro Tip: The Minecraft tunnel runs on port 25565 by default, so your friends can connect directly without specifying a port!
# Specify origin
nrelay http localhost:3000 --origin myserver
# With custom configuration
nrelay tcp localhost:5432 --origin production-relay# List all origins
nrelay origin list
# Remove an origin
nrelay origin remove myserver
# Show origin details
nrelay origin show myserverβββββββββββββββββββββββββββββββββββββββββββ
β Public Internet Traffic β
β (HTTP/HTTPS/TCP/UDP/Minecraft/SSH) β
βββββββββββββββββββ¬ββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββ
β NRelay Server (Public) β
β β
β βββββββββββββββββββββββββββββββββββ β
β β Protocol Listeners β β
β β - HTTP:80 β β
β β - HTTPS:443 β β
β β - TCP: 20000-30000 β β
β β - UDP: 30000-40000 β β
β β - Minecraft: 25565 β β
β βββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββ β
β β Tunnel Registry β β
β β (In-memory state) β β
β βββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββ β
β β Admin API (:7001) β β
β β - POST /tunnels β β
β β - Bearer token auth β β
β βββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββ β
β β Control Port (:7000) β β
β β - Client connections β β
β β - Protobuf protocol β β
β βββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββ¬βββββββββββββββββββββββ
β Control Protocol
β (Protobuf over TCP)
βΌ
ββββββββββββββββββββββββββββββββββββββββββ
β NRelay Client (Local) β
β β
β βββββββββββββββββββββββββββββββββββ β
β β Control Connection β β
β β - Receives tunnel requests β β
β β - Spawns tunnel handlers β β
β βββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββ β
β β Tunnel Handlers β β
β β - Bidirectional proxy β β
β β - Per-connection spawning β β
β βββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββ¬βββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββ
β Local Service β
β (localhost:8080, :3000, etc.) β
βββββββββββββββββββββββββββββββββββββββββββ
- Tunnel Creation: Client calls admin API to create tunnel, receives unique token
- Control Connection: Client establishes persistent connection to relay server
- Incoming Traffic: External request arrives at relay server
- Protocol Sniffing: Server extracts routing info (Host header, SNI, etc.)
- Tunnel Matching: Server identifies which tunnel should handle the request
- Connection Request: Server sends
OpenTunnelRequestto client via control connection - Tunnel Connection: Client spawns handler, connects back to server with tunnel token
- Bidirectional Proxy: Data flows: External β Server β Client β Local Service
NRelay/
βββ nrelay/ # CLI tool for tunnel management
βββ nrelay_server/ # Relay server (gateway)
βββ nrelay_client/ # Tunnel client
βββ nrelay_core/ # Shared types and protocol definitions
βββ nrelay_proto_http/ # HTTP protocol sniffer
βββ nrelay_proto_sni/ # TLS/SNI sniffer
βββ nrelay_proto_tcp/ # TCP proxy handler
βββ nrelay_proto_udp/ # UDP proxy handler
βββ nrelay_proto_mc/ # Minecraft protocol handler
Origins are stored in ~/.nrelay/origins.toml:
[[origins]]
name = "myserver"
server = "relay.example.com:7000"
admin_url = "http://relay.example.com:7001"
admin_token = "your-admin-token"
kind = "server" # "server" for self-hosted, "service" for SaaS (not yet implemented)
default = trueServer:
ADMIN_TOKEN: Admin API bearer token
Client:
RUST_LOG: Logging level (e.g.,info,debug,trace)
- Admin API: Protected by bearer token authentication
- Tunnel Access: Each tunnel has a unique access token
- Dual Auth Modes: Separate authentication for control and data connections
- Message Size Limits: 64KB maximum for control messages to prevent DoS
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
Sammwy
Built with:
(qβ₯βΏβ₯q) Happy Relaying π