websocket-tunnel
一个类似 frp 的内网穿透工具:Python + uv 实现,传输层使用 WebSocket 多路复用,
支持任意 TCP 服务(HTTP/HTTPS/SSH/MySQL 等)的字节流透传。构建产物通过
uv build 生成,安装后提供 wtunnel CLI,分为 server 与 client 两种模式。
与 frp 的主要差异:代理不区分服务端/客户端。代理条目可以声明在任意节点的
配置中,监听端(listen)与后端(backend)分别用 local / peer 指定在哪一侧,
因此以下四种组合全部支持:
| listen 侧 | backend 侧 | 用途 |
|---|---|---|
| server | client | 经典 frp:把内网服务暴露到公网服务器端口 |
| client | server | 反向:把服务端网络里的服务映射到客户端本地端口 |
| server | server | 服务端本机端口转发(不占用隧道) |
| client | client | 客户端本机端口转发(不占用隧道) |
安装
要求 Python >= 3.11 与 uv。
uv sync # 开发环境(含测试依赖)
uv build # 构建 sdist + wheel
uv run wtunnel --version
也可以把 wheel 安装到任意环境:
uv pip install dist/websocket_tunnel-0.1.0-py3-none-any.whl
wtunnel --version
快速开始
1. 启动服务端
wtunnel server -c examples/server.toml
2. 启动客户端
wtunnel client -c examples/client.toml
客户端默认把本机 127.0.0.1:3000 暴露到服务端的 0.0.0.0:8080,访问
http://<server>:8080 即可到达客户端内网的服务。
CLI 参数
wtunnel server -c server.toml [--listen HOST:PORT] [--token TOKEN]
[--tls-cert PATH --tls-key PATH] [-v]
wtunnel client -c client.toml [--server HOST:PORT] [--token TOKEN]
[--tls] [--tls-skip-verify] [-v]
CLI 参数覆盖配置文件中的同名项;-v 输出 DEBUG 日志。
配置参考
server.toml:
listen = "0.0.0.0:7000" # 控制端口(ws/wss)
token = "secret" # 可选,共享认证 token
tls = { cert = "server.crt", key = "server.key" } # 可选,启用 wss
# 最大并发控制连接数(0 = 不限)
max_connections = 10
# 允许 client 请求本节点连接的 backend IP 范围(CIDR 列表,空 = 允许所有)
allow_peer_backends = ["127.0.0.1/32", "10.0.0.0/8"]
# 允许 client 请求本节点绑定的 listen IP 范围(空 = 允许所有)
allow_peer_listens = ["0.0.0.0/0", "::/0"]
[[proxies]]
name = "web"
listen = "0.0.0.0:8080"
listen_side = "local" # "local" | "peer"
backend = "127.0.0.1:3000"
backend_side = "peer"
client.toml:
server = "127.0.0.1:7000" # 服务端地址
token = "secret"
tls = false # true 时使用 wss
tls_skip_verify = false # 自签证书时设为 true
# 允许服务端请求本节点连接的 backend IP 范围(CIDR 列表,空 = 允许所有)
allow_peer_backends = ["127.0.0.1/32"]
# 允许服务端请求本节点绑定的 listen IP 范围(空 = 允许所有)
allow_peer_listens = ["127.0.0.1/32"]
[[proxies]]
name = "web"
listen = "0.0.0.0:8080"
listen_side = "peer"
backend = "127.0.0.1:3000"
backend_side = "local"
listen / backend 均为 host:port,IPv6 使用 [::1]:8080 形式。allow_peer_*
白名单中的地址必须使用 IP(不支持主机名),CIDR 掩码可省略(如 "10.0.0.1"
等同于 "10.0.0.1/32")。
传输与协议概要
- 每对节点一条 WebSocket 长连接(client 主动连接 server),控制消息与所有数据流 在其上多路复用;每条 TCP 流分配独立 stream id。
- 二进制帧:首字节为消息类型;控制消息为 JSON,数据帧为
stream_id(4 字节大端) + 数据块(默认 32 KiB)。 - 支持半关闭:任一方向 EOF 只关闭对应方向,保证 HTTP/1.0 与 keep-alive 响应完整。
- 握手时校验共享 token(失败即断开);服务端可选 wss,客户端可跳过证书校验。
- client 断线自动重连(指数退避 1s→30s),重连后双方重新注册代理并重新绑定监听。
开发与测试
uv run pytest # 单元 + 集成测试
uv build # 构建发布产物
发布到 PyPI
打上 v 开头的 tag 并推送即触发 GitHub Actions 发布:
git tag v0.1.0
git push origin v0.1.0
工作流(.github/workflows/release.yml)会校验 tag 与包版本一致、运行测试、
uv build 构建后通过 trusted publishing(OIDC)发布到 PyPI。首次使用前需要在
PyPI 项目页配置 Trusted Publisher:仓库 8DE4732A/websocket-tunnel、
工作流名 Publish to PyPI。若改用 API token,删除 workflow 中 id-token: write
权限,并配置 PYPI_TOKEN secret 传给 uv publish。
安全说明
连接数限制:服务端 max_connections 防止恶意客户端通过大量控制连接耗尽资源。
建议生产部署时设置一个合理上限(如 10)。
后端 / 监听白名单:默认配置下,持有 token 的对端可请求本节点连接任意 IP 或
绑定任意端口,这在可信局域网内往往是期望行为。若部署于半信任网络,应配置
allow_peer_backends 将出站连接限定为必要的内网 CIDR,并用 allow_peer_listens
约束监听 IP,以防内网探测(SSRF)与端口滥用。
传输加密:token 在握手时以明文 JSON 传输。公网部署请务必启用 wss(配置
tls.cert / tls.key);tls_skip_verify = true 仅适用于受控的自签证书环境,
生产环境应使用受信任 CA 签发的证书。
v1 暂不提供 mTLS、证书固定与配置热加载。
Release files for websocket-tunnel 0.3.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| websocket_tunnel-0.3.2.tar.gz | 52.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| websocket_tunnel-0.3.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 72.7 kB
Release files / websocket_tunnel-0.3.2.tar.gz
| Download URL | websocket_tunnel-0.3.2.tar.gz |
|---|---|
| Size | 52.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c4093a6cd9b23b50d1743be8dd68cd5197c333b267139ae791f1b33b6e8dd9b5
|
|
BLAKE2b-256 checksum How to use checksums |
7cc9237fa31b7d7cc5989fb5acccd40b62d0b3eb6600da16011cda6c1eca4cbb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / websocket_tunnel-0.3.2-py3-none-any.whl
| Download URL | websocket_tunnel-0.3.2-py3-none-any.whl |
|---|---|
| Size | 20.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
411c6c1c026f921b1e6b7020d6bc54519464fe9b4fbce64b74683a7d7d32ff7e
|
|
BLAKE2b-256 checksum How to use checksums |
9a1eba43341053057df8e1e4057044b4547e74bf84b6cdcbcc55db21a0076ba2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|