A secure, stable and high-performance reverse proxy for NAT traversal, written in Rust
rathole, like frp and ngrok, can help to expose the service on the device behind the NAT to the Internet, via a server with a public IP.
- High Performance Much higher throughput can be achieved than frp, and more stable when handling a large volume of connections. See Benchmark
- Low Resource Consumption Consumes much fewer memory than similar tools. See Benchmark. The binary can be as small as ~500KiB to fit the constraints of devices, like embedded devices as routers.
- Security Users and tokens are used for authentication. With the optional Noise Protocol, encryption can be configured at ease. No need to create a self-signed certificate!
- Hot Reload Services can be added or removed dynamically by hot-reloading the configuration file. HTTP API is WIP.
A full-powered rathole can be obtained from the release page. Or build from source for other platforms and minimizing the binary. A Docker image is also available.
Assuming you have a NAS at home behind the NAT, and want to expose its ssh service to the Internet:
- On the server which has a public IP
Create server.toml:
[server]
bind_addr = "0.0.0.0:2333"
[server.users.default] # Define a user
token = "my_secret_token" # Optional password
[server.services.my_nas_ssh]
user = "default"
bind_addr = "0.0.0.0:5202"- On the host which is behind the NAT (your NAS)
Create client.toml:
[client]
remote_addr = "myserver.com:2333"
user = "default"
token = "my_secret_token"
[client.services.my_nas_ssh]
local_addr = "127.0.0.1:22"Then run rathole server.toml on the server and rathole client.toml on the client.
rathole supports a "Visitor Mode" where the client can request the server to bind to a specific address/port.
Server Configuration:
- Run
rathole --genkeyto get your server's identity. - Configure
server.toml:
[server]
bind_addr = "0.0.0.0:2333"
[server.transport]
type = "udp"
[server.transport.noise]
local_private_key = "SERVER_PRIVATE_KEY_HERE"
[server.users.alice]
token = "alice_token"
allowed_ports = "2000-3000" # Alice can bind to these portsClient Configuration:
[client]
remote_addr = "myserver.com:2333"
user = "alice"
token = "alice_token"
[client.transport]
type = "udp"
[client.transport.noise]
remote_public_key = "SERVER_PUBLIC_KEY_HERE"
[client.services.my_service]
local_addr = "127.0.0.1:8080"
remote_bind_addr = "0.0.0.0:2334" rathole:
image: ghcr.io/nelonn/rathole-ng:nightly
restart: unless-stopped
network_mode: host
volumes:
- ./rathole-config.toml:/rathole-config.toml[client]
remote_addr = "example.com:2333"
user = "default" # Default user for services
token = "test_token" # Default token for services
[client.transport]
type = "udp" # Possible values: ["tcp", "udp"]
[client.transport.noise] # Noise protocol layer
pattern = "Noise_IK_25519_ChaChaPoly_BLAKE2s"
remote_public_key = "SERVER_PUBLIC_KEY"
psk = "optional_transport_psk"
[client.services.service1]
local_addr = "127.0.0.1:1081"
# user and token can be overridden here
[server]
bind_addr = "0.0.0.0:2333"
[server.users.alice]
token = "alice_token"
allowed_ports = "2000-3000"
[server.transport]
type = "udp"
[server.transport.noise]
local_private_key = "SERVER_PRIVATE_KEY"
[server.services.service1]
user = "alice"
bind_addr = "0.0.0.0:8081"