21 个版本

0.5.0 2023年10月1日
0.4.8 2023年5月26日
0.4.7 2022年11月30日
0.4.2 2022年5月23日
0.2.0 2021年12月26日

#840 in 网络编程

Download history 2/week @ 2024-04-07 7/week @ 2024-04-21 119/week @ 2024-04-28 25/week @ 2024-05-05 219/week @ 2024-05-12 161/week @ 2024-05-19 23/week @ 2024-05-26 91/week @ 2024-06-02 11/week @ 2024-06-09 73/week @ 2024-06-16 52/week @ 2024-06-23 2/week @ 2024-06-30 54/week @ 2024-07-07 97/week @ 2024-07-14 24/week @ 2024-07-21

每月196 次下载
用于 flowsnet

Apache-2.0

140KB
3K SLoC

rathole

rathole-logo

GitHub stars GitHub release (latest SemVer) GitHub Workflow Status (branch) GitHub all releases Docker Pulls Join the chat at https://gitter.im/rapiz1/rathole

英文 | 简体中文

一个安全、稳定且高性能的 NAT 穿越反向代理,用 Rust 编写

rathole,类似于 frpngrok,可以通过具有公网 IP 的服务器,将 NAT 背后的设备上的服务暴露到互联网上。

功能

  • 高性能 比 frp 实现更高的吞吐量,处理大量连接时更稳定。见 基准测试
  • 低资源消耗 比类似工具消耗更少的内存。见 基准测试。二进制文件可以 小至 ~500KiB 以适应如路由器等嵌入式设备的限制。
  • 安全性 服务的令牌是强制性的,且服务级别的。服务器和客户端各自负责自己的配置。可选的 Noise 协议允许轻松配置加密。无需创建自签名证书!也支持 TLS。
  • 热重载 可以通过热重载配置文件动态添加或删除服务。HTTP API 处于开发中。

快速入门

可以从发布页面获取全功能的rathole。或者,为了其他平台和最小化二进制文件,您可以从源代码构建。同时,也提供了Docker镜像

rathole的使用与frp非常相似。如果您熟悉后者,那么配置对您来说非常简单。唯一的区别是服务的配置被分为客户端和服务器端,并且必须使用令牌。

要使用rathole,您需要一个公网IP的服务器,以及一个位于NAT后面的设备,其中包含一些需要暴露到互联网上的服务。

假设您家中有一个位于NAT后面的NAS,并且想将它的ssh服务暴露到互联网上

  1. 在具有公网IP的服务器上

创建server.toml并添加以下内容,并根据您的需要进行调整。

# 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 a arbitrary value.
bind_addr = "0.0.0.0:5202" # `5202` specifies the port that exposes `my_nas_ssh` to the Internet

然后运行

./rathole server.toml
  1. 在位于NAT后面(您的NAS)的主机上

创建client.toml并添加以下内容,并根据您的需要进行调整。

# 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 forwarded

然后运行

./rathole client.toml
  1. 现在客户端将尝试连接到服务器的myserver.com端口2333,并且任何发送到myserver.com:5202的流量都将转发到客户端的端口22

因此,您可以通过ssh myserver.com:5202来SSH连接到您的NAS。

在Linux上作为后台服务运行rathole,请查阅systemd示例

配置

rathole可以根据配置文件的内容自动确定运行在服务器模式或客户端模式,如果只有[server][client]中的一个存在,就像快速入门中的示例一样。

但是,[client][server]块也可以放在一个文件中。然后在服务器端,运行rathole --server config.toml,在客户端,运行rathole --client config.toml以显式告诉rathole运行模式。

在深入了解完整配置规范之前,建议先浏览配置示例,以了解配置格式。

有关加密和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. 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"

日志记录

与许多其他Rust程序一样,rathole使用环境变量来控制日志级别。有infowarnerrordebugtrace可供选择。

RUST_LOG=error ./rathole config.toml

将以错误级别日志运行 rathole

如果不存在 RUST_LOG,则默认日志级别为 info

调整

从 v0.4.7 版本开始,rathole 默认启用 TCP_NODELAY,这应该有助于降低延迟并提高 rdp、Minecraft 服务器等交互式应用程序的性能。然而,这会略微降低带宽。

如果带宽更重要,可以使用 nodelay = false 来禁用 TCP_NODELAY。

基准测试

rathole 的延迟与 frp 类似,但可以处理更多的连接,提供更大的带宽,同时内存使用更少。

有关更多详细信息,请参阅单独的页面 Benchmark

但是,不要以为 rathole 可以神奇地将您的转发服务速度提高几倍。 该基准是在本地回环中进行的,表示任务为 CPU 限制时的性能。如果网络不是瓶颈,则可以获得相当大的改进。遗憾的是,对许多用户来说并非如此。在这种情况下,主要的好处是资源消耗更低,而带宽和延迟可能不会有显著提高。

http_throughput tcp_bitrate udp_bitrate mem

规划

  • 配置的 HTTP API

Out of Scope 列出了未计划实现的功能及其原因。

依赖项

~11–27MB
~419K SLoC