rathole-org/rathole
rathole
rathole transmet un service que vous administrez. Cette page ne décrit pas l'accès à un réseau que vous n'administrez pas.
rathole
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.
Features
- 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 Tokens of services are mandatory and service-wise. The server and clients are responsible for their own configs. With the optional Noise Protocol, encryption can be configured at ease. No need to create a self-signed certificate! TLS is also supported.
- Hot Reload Services can be added or removed dynamically by hot-reloading the configuration file. HTTP API is WIP.
Quickstart
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.
The usage of rathole is very similar to frp. If you have experience with the latter, then the configuration is very easy for you. The only difference is that configuration of a service is split into the client side and the server side, and a token is mandatory.
To use rathole, you need a server with a public IP, and a device behind the NAT, where some services that need to be exposed to the Internet.
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 with the following content and accommodate it to your needs.
# server.toml
[server]
bind_addr = "0.0.0.0:2333" # `2333` specifies the port that rathole listens for clients
[server.services.my_nas_ssh]
token = "use_a_secret_that_only_you_know" # Token that is used to authenticate the client for the service. Change to an arbitrary value.
bind_addr = "0.0.0.0:5202" # `5202` specifies the port that exposes `my_nas_ssh` to the InternetThen run:
./rathole server.toml- On the host which is behind the NAT (your NAS)
Create client.toml with the following content and accommodate it to your needs.
# client.toml
[client]
remote_addr = "myserver.com:2333" # The address of the server. The port must be the same with the port in `server.bind_addr`
[client.services.my_nas_ssh]
token = "use_a_secret_that_only_you_know" # Must be the same with the server to pass the validation
local_addr = "127.0.0.1:22" # The address of the service that needs to be forwardedThen run:
./rathole client.toml- Now the client will try to connect to the server
myserver.comon port2333, and any traffic tomyserver.com:5202will be forwarded to the client's port22.
So you can ssh myserver.com:5202 to ssh to your NAS.
To run rathole run as a background service on Linux, checkout the systemd examples.
Configuration
rathole can automatically determine to run in the server mode or the client mode, according to the content of the configuration file, if only one of [server] and [client] block is present, like the example in Quickstart.
But the [client] and [server] block can also be put in one file. Then on the server side, run rathole --server config.toml and on the client side, run rathole --client config.toml to explicitly tell rathole the running mode.
Before heading to the full configuration specification, it's recommend to skim the configuration examples to get a feeling of the configuration format.
See Transport for more details about encryption and the transport block.
Here is the full configuration specification:
[client]
remote_addr = "example.com:2333" # Necessary. The address of the server
default_token = "default_token_if_not_specify" # Optional. The default token of services, if they don't define their own ones
heartbeat_timeout = 40 # Optional. Set to 0 to disable the application-layer heartbeat test. The value must be greater than `server.heartbeat_interval`. Default: 40 seconds
retry_interval = 1 # Optional. The interval between retry to connect to the server. Default: 1 second
[client.transport] # The whole block is optional. Specify which transport to use
type = "tcp" # Optional. Possible values: ["tcp", "tls", "noise"]. Default: "tcp"
[client.transport.tcp] # Optional. Also affects `noise` and `tls`
proxy = "socks5://user:[email protected]:1080" # Optional. The proxy used to connect to the server. `http` and `socks5` is supported.
nodelay = true # Optional. Determine whether to enable TCP_NODELAY, if applicable, to improve the latency but decrease the bandwidth. Default: true
keepalive_secs = 20 # Optional. Specify `tcp_keepalive_time` in `tcp(7)`, if applicable. Default: 20 seconds
keepalive_interval = 8 # Optional. Specify `tcp_keepalive_intvl` in `tcp(7)`, if applicable. Default: 8 seconds
[client.transport.tls] # Necessary if `type` is "tls"
trusted_root = "ca.pem" # Necessary. The certificate of CA that signed the server's certificate
hostname = "example.com" # Optional. The hostname that the client uses to validate the certificate. If not set, fallback to `client.remote_addr`
[client.transport.noise] # Noise protocol. See `docs/transport.md` for further explanation
pattern = "Noise_NK_25519_ChaChaPoly_BLAKE2s" # Optional. Default value as shown
local_private_key = "key_encoded_in_base64" # Optional
remote_public_key = "key_encoded_in_base64" # Optional
[client.transport.websocket] # Necessary if `type` is "websocket"
tls = true # If `true` then it will use settings in `client.transport.tls`
[client.services.service1] # A service that needs forwarding. The name `service1` can change arbitrarily, as long as identical to the name in the server's configuration
type = "tcp" # Optional. The protocol that needs forwarding. Possible values: ["tcp", "udp"]. Default: "tcp"
token = "whatever" # Necessary if `client.default_token` not set
local_addr = "127.0.0.1:1081" # Necessary. The address of the service that needs to be forwarded
nodelay = true # Optional. Override the `client.transport.nodelay` per service
retry_interval = 1 # Optional. The interval between retry to connect to the server. Default: inherits the global config
[client.services.service2] # Multiple services can be defined
local_addr = "127.0.0.1:1082"
[server]
bind_addr = "0.0.0.0:2333" # Necessary. The address that the server listens for clients. Generally only the port needs to be change.
default_token = "default_token_if_not_specify" # Optional
heartbeat_interval = 30 # Optional. The interval between two application-layer heartbeat. Set to 0 to disable sending heartbeat. Default: 30 seconds
[server.transport] # Same as `[client.transport]`
type = "tcp"
[server.transport.tcp] # Same as the client
nodelay = true
keepalive_secs = 20
keepalive_interval = 8
[server.transport.tls] # Necessary if `type` is "tls"
pkcs12 = "identify.pfx" # Necessary. pkcs12 file of server's certificate and private key
pkcs12_password = "password" # Necessary. Password of the pkcs12 file
[server.transport.noise] # Same as `[client.transport.noise]`
pattern = "Noise_NK_25519_ChaChaPoly_BLAKE2s"
local_private_key = "key_encoded_in_base64"
remote_public_key = "key_encoded_in_base64"
[server.transport.websocket] # Necessary if `type` is "websocket"
tls = true # If `true` then it will use settings in `server.transport.tls`
[server.services.service1] # The service name must be identical to the client side
type = "tcp" # Optional. Same as the client `[client.services.X.type]
token = "whatever" # Necessary if `server.default_token` not set
bind_addr = "0.0.0.0:8081" # Necessary. The address of the service is exposed at. Generally only the port needs to be change.
nodelay = true # Optional. Same as the client
[server.services.service2]
bind_addr = "0.0.0.1:8082"Logging
rathole, like many other Rust programs, use environment variables to control the logging level. info, warn, error, debug, trace are available.
RUST_LOG=error ./rathole config.tomlwill run rathole with only error level logging.
If RUST_LOG is not present, the default logging level is info.
Tuning
From v0.4.7, rathole enables TCP_NODELAY by default, which should benefit the latency and interactive applications like rdp, Minecraft servers. However, it slightly decreases the bandwidth.
If the bandwidth is more important, TCP_NODELAY can be opted out with nodelay = false.
Benchmark
rathole has similar latency to frp, but can handle a more connections, provide larger bandwidth, with less memory usage.
For more details, see the separate page Benchmark.
However, don't take it from here that rathole can magically make your forwarded service faster several times than before. The benchmark is done on local loopback, indicating the performance when the task is cpu-bounded. One can gain quite a improvement if the network is not the bottleneck. Unfortunately, that's not true for many users. In that case, the main benefit is lower resource consumption, while the bandwidth and the latency may not improved significantly.
Planning
- HTTP APIs for configuration
Out of Scope lists features that are not planned to be implemented and why.
rathole
安全、稳定、高性能的内网穿透工具,用 Rust 语言编写
rathole,类似于 frp 和 ngrok,可以让 NAT 后的设备上的服务通过具有公网 IP 的服务器暴露在公网上。
Features
- 高性能 具有更高的吞吐量,高并发下更稳定。见Benchmark
- 低资源消耗 内存占用远低于同类工具。见Benchmark。二进制文件最小可以到 ~500KiB,可以部署在嵌入式设备如路由器上。
- 安全性 每个服务单独强制鉴权。Server 和 Client 负责各自的配置。使用 Noise Protocol 可以简单地配置传输加密,而不需要自签证书。同时也支持 TLS。
- 热重载 支持配置文件热重载,动态修改端口转发服务。HTTP API 正在开发中。
Quickstart
一个全功能的 rathole 可以从 release 页面下载。或者 从源码编译 获取其他平台和最小化的二进制文件。
rathole 的使用和 frp 非常类似,如果你有后者的使用经验,那配置对你来说非常简单,区别只是转发服务的配置分离到了服务端和客户端,并且必须要设置 token。
使用 rathole 需要一个有公网 IP 的服务器,和一个在 NAT 或防火墙后的设备,其中有些服务需要暴露在互联网上。
假设你在家里的 NAT 后面有一个 NAS,并且想把它的 ssh 服务暴露在公网上:
- 在有一个公网 IP 的服务器上
创建 server.toml,内容如下,并根据你的需要调整。
# server.toml
[server]
bind_addr = "0.0.0.0:2333" # `2333` 配置了服务端监听客户端连接的端口
[server.services.my_nas_ssh]
token = "use_a_secret_that_only_you_know" # 用于验证的 token
bind_addr = "0.0.0.0:5202" # `5202` 配置了将 `my_nas_ssh` 暴露给互联网的端口然后运行:
./rathole server.toml- 在 NAT 后面的主机(你的 NAS)上
创建 client.toml,内容如下,并根据你的需要进行调整。
# client.toml
[client]
remote_addr = "myserver.com:2333" # 服务器的地址。端口必须与 `server.bind_addr` 中的端口相同。
[client.services.my_nas_ssh]
token = "use_a_secret_that_only_you_know" # 必须与服务器相同以通过验证
local_addr = "127.0.0.1:22" # 需要被转发的服务的地址然后运行:
./rathole client.toml- 现在
rathole客户端会连接运行在myserver.com:2333的rathole服务器,任何到myserver.com:5202的流量将被转发到客户端所在主机的22端口。
所以你可以 ssh myserver.com:5202 来 ssh 到你的 NAS。
Systemd examples 中提供了一些让 rathole 在 Linux 上作为后台服务运行的配置示例。
Configuration
如果只有一个 [server] 和 [client] 块存在的话,rathole 可以根据配置文件的内容自动决定在服务器模式或客户端模式下运行,就像 Quickstart 中的例子。
但 [client] 和 [server] 块也可以放在一个文件中。然后在服务器端,运行 rathole --server config.toml。在客户端,运行 rathole --client config.toml 来明确告诉 rathole 运行模式。
推荐首先查看 examples 中的配置示例来快速理解配置格式,如果有不清楚的地方再查阅完整配置格式。
关于如何配置 Noise Protocol 和 TLS 来进行加密传输,参见 Transport。
下面是完整的配置格式。
[client]
remote_addr = "example.com:2333" # Necessary. The address of the server
default_token = "default_token_if_not_specify" # Optional. The default token of services, if they don't define their own ones
heartbeat_timeout = 40 # Optional. Set to 0 to disable the application-layer heartbeat test. The value must be greater than `server.heartbeat_interval`. Default: 40 seconds
retry_interval = 1 # Optional. The interval between retry to connect to the server. Default: 1 second
[client.transport] # The whole block is optional. Specify which transport to use
type = "tcp" # Optional. Possible values: ["tcp", "tls", "noise"]. Default: "tcp"
[client.transport.tcp] # Optional. Also affects `noise` and `tls`
proxy = "socks5://user:[email protected]:1080" # Optional. The proxy used to connect to the server. `http` and `socks5` is supported.
nodelay = true # Optional. Override the `client.transport.nodelay` per service
keepalive_secs = 20 # Optional. Specify `tcp_keepalive_time` in `tcp(7)`, if applicable. Default: 20 seconds
keepalive_interval = 8 # Optional. Specify `tcp_keepalive_intvl` in `tcp(7)`, if applicable. Default: 8 seconds
[client.transport.tls] # Necessary if `type` is "tls"
trusted_root = "ca.pem" # Necessary. The certificate of CA that signed the server's certificate
hostname = "example.com" # Optional. The hostname that the client uses to validate the certificate. If not set, fallback to `client.remote_addr`
[client.transport.noise] # Noise protocol. See `docs/transport.md` for further explanation
pattern = "Noise_NK_25519_ChaChaPoly_BLAKE2s" # Optional. Default value as shown
local_private_key = "key_encoded_in_base64" # Optional
remote_public_key = "key_encoded_in_base64" # Optional
[client.transport.websocket] # Necessary if `type` is "websocket"
tls = true # If `true` then it will use settings in `client.transport.tls`
[client.services.service1] # A service that needs forwarding. The name `service1` can change arbitrarily, as long as identical to the name in the server's configuration
type = "tcp" # Optional. The protocol that needs forwarding. Possible values: ["tcp", "udp"]. Default: "tcp"
token = "whatever" # Necessary if `client.default_token` not set
local_addr = "127.0.0.1:1081" # Necessary. The address of the service that needs to be forwarded
nodelay = true # Optional. Determine whether to enable TCP_NODELAY for data transmission, if applicable, to improve the latency but decrease the bandwidth. Default: true
retry_interval = 1 # Optional. The interval between retry to connect to the server. Default: inherits the global config
[client.services.service2] # Multiple services can be defined
local_addr = "127.0.0.1:1082"
[server]
bind_addr = "0.0.0.0:2333" # Necessary. The address that the server listens for clients. Generally only the port needs to be change.
default_token = "default_token_if_not_specify" # Optional
heartbeat_interval = 30 # Optional. The interval between two application-layer heartbeat. Set to 0 to disable sending heartbeat. Default: 30 seconds
[server.transport] # Same as `[client.transport]`
type = "tcp"
[server.transport.tcp] # Same as the client
nodelay = true
keepalive_secs = 20
keepalive_interval = 8
[server.transport.tls] # Necessary if `type` is "tls"
pkcs12 = "identify.pfx" # Necessary. pkcs12 file of server's certificate and private key
pkcs12_password = "password" # Necessary. Password of the pkcs12 file
[server.transport.noise] # Same as `[client.transport.noise]`
pattern = "Noise_NK_25519_ChaChaPoly_BLAKE2s"
local_private_key = "key_encoded_in_base64"
remote_public_key = "key_encoded_in_base64"
[server.transport.websocket] # Necessary if `type` is "websocket"
tls = true # If `true` then it will use settings in `server.transport.tls`
[server.services.service1] # The service name must be identical to the client side
type = "tcp" # Optional. Same as the client `[client.services.X.type]
token = "whatever" # Necessary if `server.default_token` not set
bind_addr = "0.0.0.0:8081" # Necessary. The address of the service is exposed at. Generally only the port needs to be change.
nodelay = true # Optional. Same as the client
[server.services.service2]
bind_addr = "0.0.0.1:8082"Logging
rathole,像许多其他 Rust 程序一样,使用环境变量来控制日志级别。
支持的 Logging Level 有 info, warn, error, debug, trace
比如将日志级别设置为 error:
RUST_LOG=error ./rathole config.toml如果 RUST_LOG 不存在,默认的日志级别是 info。
Tuning
从 v0.4.7 开始, rathole 默认启用 TCP_NODELAY。这能够减少延迟并使交互式应用受益,比如 RDP,Minecraft 服务器。但它会减少一些带宽。
如果带宽更重要,比如网盘类应用,TCP_NODELAY 仍然可以通过配置 nodelay = false 关闭。
Benchmark
rathole 的延迟与 frp 相近,在高并发情况下表现更好,能提供更大的带宽,内存占用更少。
关于测试进行的更多细节,参见单独页面 Benchmark。
但是,不要从这里得出结论,rathole 能让内网转发出来的服务快上数倍。 Benchmark 是在本地回环上进行的,其结果说明了任务受 CPU 限制时的结果。当用户的网络不是瓶颈时,用户能得到很大的提升。但是,对很多用户来说并不是这样。在这种情况下,rathole 能带来的主要好处是更少的资源占用,而带宽和延迟不一定有显著的改善。
Development Status
rathole 正在积极开发中
- 支持 TLS
- 支持 UDP
- 热重载
- 用于配置的 HTTP APIs
Out of Scope 列举了没有计划开发的特性并说明了原因。
Out of Scope
rathole focuses on the forwarding for the NAT traversal, rather than being a all-in-one development tool or a load balancer or a gateway. It's designed to be used with them, not replace them.
But that doesn't mean it's not useful for other purposes. In the future, more configuration APIs will be added and rathole can be used with an external dashboard.
Make each program do one thing well.
-
Domain based forwarding for HTTP
Introducing these kind of features into
ratholeitself ultimately reinvent a nginx. Use nginx to do this and setratholeas the upstream. This method achieves better performance as well as flexibility. -
HTTP Request Logging
ratholedoesn't interference with the application layer traffic. A right place for this kind of stuff is the web server, and a network capture tool. -
frp's STCP or other setup that requires visitors' side configurationIf that kind of setup is possible, then there are a lot more tools available. You may want to consider secure tunnels like wireguard or zerotier.
ratholeprimarily focuses on NAT traversal by forwarding, which doesn't require any setup for visitors. -
Caching
local_ip's DNS recordsAs responded in issue #183,
local_ipcache is not feasible because we have no reliable way to detect ip change. Handle DNS TTL and so on should be done with a DNS server, not a client. Caching ip is generally dangerous for clients. If you care about thelocal_ipquery you can set up a local DNS server and enable caching. Then the local lookup should be trivial.
Lire l'original · README · README 中文 · Out of scope
https://github.com/rathole-org/rathole · Bibliothèque

