laylink/readme.md
2026-05-30 17:50:45 +08:00

469 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# LayLink
LayLink 是一个基于 PHP Workerman 的策略控制型四层反向访问网关。
它不是 VPN。客户端连接 Client Agent请求访问某个 TCP 目标Client Agent 使用 LayLink Frame 协议连接 POP ServerPOP Server 负责认证、策略判断、连接公网目标和审计。
## 当前节点类型
当前 MVP 分成 2 种核心类型:
1. `POP Server`
2. `Client Agent`
## 配置文件关系
`.env` 用来配置当前进程自己的运行参数。
`config/nodes.php` 用来声明 POP Server 认可哪些 Agent 节点,以及 Agent 的本地 allowlist。
`config/policies.php` 用来声明客户端访问策略。POP Server 根据这个文件决定某个用户是否允许访问某个目标,以及是否由 POP Server 直接连接公网目标。
`.env.example` 是示例模板。实际部署时建议复制为 `.env`,再按当前进程类型修改:
```bash
cp .env.example .env
```
`.env.example` 中的 `[config]`、`[kcp]`、`[client-agent]`、`[pop-server]` 是阅读分组标题,当前加载器会忽略这些标题,只读取 `KEY=value` 配置行。
Agent 与 POP Server 之间的 LayLink Frame 支持加密:
```env
LAYLINK_FRAME_ENCRYPTION=none
LAYLINK_FRAME_ENCRYPTION_KEY=
```
可选值:
| 值 | 作用 |
| --- | --- |
| `none` | 不加密,开发调试默认值。 |
| `chacha20` | 使用 libsodium XChaCha20 stream 对 Frame body 加密。 |
启用 `chacha20`POP Server 和 Client Agent 必须配置完全相同的加密方式和密钥:
```env
LAYLINK_FRAME_ENCRYPTION=chacha20
LAYLINK_FRAME_ENCRYPTION_KEY=change-this-long-random-secret
```
密钥支持普通口令,也支持 `hex:``base64:` 前缀的 32 字节原始密钥。
## POP Server
POP Server 是控制面和转发入口。
它负责:
* 监听 Agent 长连接。
* 校验 Agent 的 `NODE_ID``NODE_TOKEN`
* 校验客户端访问请求。
* 根据 `config/policies.php` 选择路由。
* 向 Agent 下发 `OPEN` 指令。
* 记录审计日志。
启动入口:
```bash
php bin/pop-server.php start
```
POP Server 需要配置这些 `.env`
```env
APP_ENV=dev
POP_AGENT_LISTEN=0.0.0.0:9001
POP_ALLOWED_AGENT_TRANSPORTS=tcp,kcp
POP_AGENT_TCP_WORKERS=1
POP_AGENT_KCP_WORKERS=1
AUDIT_LOG=runtime/audit.log
LOG_LEVEL=debug
```
配置说明:
| 变量 | 作用 | 常见值 |
| --- | --- | --- |
| `APP_ENV` | 当前运行环境。开发时使用 `dev`,生产可使用 `prod`。 | `dev`、`test`、`prod` |
| `LAYLINK_FRAME_ENCRYPTION` | Agent 与 POP Server 之间 Frame 加密方式,两端必须一致。 | `none`、`chacha20` |
| `LAYLINK_FRAME_ENCRYPTION_KEY` | Frame 加密密钥,启用 `chacha20` 时必填。 | 普通口令、`hex:...`、`base64:...` |
| `POP_AGENT_LISTEN` | POP Server 给 Client Agent 连接的监听地址。Agent 的 `POP_SERVER_ADDRESS` 应指向这里。 | `0.0.0.0:9001`、`127.0.0.1:9001` |
| `POP_ALLOWED_AGENT_TRANSPORTS` | POP Server 允许 Agent 使用的底层传输协议。支持逗号数组,也支持 JSON 数组。Agent 认证时会上报自己的选择,不在列表内会被拒绝。 | `tcp`、`tcp,kcp`、`["tcp","kcp"]` |
| `POP_AGENT_TCP_WORKERS` | POP TCP Agent listener 的 worker 数。TCP 模式可按 CPU 和并发提高。 | `1`、`2`、`4`、`8` |
| `POP_AGENT_KCP_WORKERS` | POP KCP/UDP Agent listener 的 worker 数。当前必须保持 `1`。 | `1` |
| `AUDIT_LOG` | 审计日志路径。MVP 使用 JSON Lines 追加写入。 | `runtime/audit.log` |
| `LOG_LEVEL` | 日志级别预留配置。当前 MVP 主要为后续日志工厂使用。 | `debug`、`info`、`warning`、`error` |
POP Server 通常不需要配置 `NODE_ID`、`NODE_TYPE`、`NODE_TOKEN`、`POP_SERVER_ADDRESS`。这些是 Agent 进程使用的。
## Client Agent
Client Agent 部署在客户端侧,作为本机或局域网入口。
它负责:
* 主动出站连接 POP Server。
* 使用 `NODE_ID`、`NODE_TYPE`、`NODE_TOKEN` 向 POP Server 认证。
* 维持心跳。
* 接收本地客户端连接。
* 将客户端请求和数据封装为 LayLink Frame。
* 通过选定的底层传输协议把 Frame 发送给 POP Server。
* 接收 POP Server 返回的目标数据并转发回本地客户端。
启动入口:
```bash
php bin/client-agent.php start
```
Client Agent 需要配置这些 `.env`
```env
APP_ENV=dev
NODE_ID=client-01
NODE_TYPE=client
NODE_TOKEN=CHANGE_ME
AGENT_TRANSPORT_PROTOCOL=tcp
CLIENT_AGENT_POP_CONNECTIONS=1
CLIENT_AGENT_AUTH_TOKEN=dev-token
CLIENT_AGENT_USER_ID=admin
CLIENT_AGENT_SOCKS5_ENABLED=true
CLIENT_AGENT_SOCKS5_LISTEN_IP=127.0.0.1
CLIENT_AGENT_SOCKS5_LISTEN_PORT=1080
CLIENT_AGENT_SOCKS5_UDP_LISTEN_IP=127.0.0.1
CLIENT_AGENT_SOCKS5_UDP_LISTEN_PORT=1081
CLIENT_AGENT_SOCKS5_UDP_ADVERTISE_IP=127.0.0.1
CLIENT_AGENT_SOCKS5_AUTH_MODE=no-auth
CLIENT_AGENT_SOCKS5_USERNAME=
CLIENT_AGENT_SOCKS5_PASSWORD=
CLIENT_AGENT_HTTP_PROXY_ENABLED=false
CLIENT_AGENT_HTTP_PROXY_LISTEN_IP=127.0.0.1
CLIENT_AGENT_HTTP_PROXY_LISTEN_PORT=8080
CLIENT_AGENT_RAW_JSON_ENABLED=false
CLIENT_AGENT_RAW_JSON_LISTEN_IP=127.0.0.1
CLIENT_AGENT_RAW_JSON_LISTEN_PORT=9000
POP_SERVER_ADDRESS=tcp://10.1.0.2:9001
LOG_LEVEL=debug
```
配置说明:
| 变量 | 作用 | 常见值 |
| --- | --- | --- |
| `APP_ENV` | 当前运行环境。 | `dev`、`test`、`prod` |
| `NODE_ID` | 当前 Client Agent 的节点 ID。必须存在于 `config/nodes.php`。 | `client-01` |
| `NODE_TYPE` | 当前节点类型。Client Agent 必须配置为 `client`。 | `client` |
| `NODE_TOKEN` | 当前节点认证密钥。必须和 `config/nodes.php` 中同一 `NODE_ID``token` 一致。 | 强随机字符串,开发时可临时用 `CHANGE_ME` |
| `AGENT_TRANSPORT_PROTOCOL` | 当前 Agent 到 POP Server 使用的底层传输协议。必须被 POP Server 的 `POP_ALLOWED_AGENT_TRANSPORTS` 允许。 | `tcp`、`udp`、`kcp` |
| `CLIENT_AGENT_POP_CONNECTIONS` | Client Agent 到 POP Server 的并行长连接数量。新 TCP 会话会在已认证连接间轮询分配,适合多并发请求或多线程测速。 | `1`、`2`、`4` |
| `CLIENT_AGENT_AUTH_TOKEN` | SOCKS5/HTTP 代理入口生成 `OPEN` 帧时使用的客户端认证 token。 | `dev-token`,生产应替换 |
| `CLIENT_AGENT_USER_ID` | SOCKS5/HTTP 代理入口生成 `OPEN` 帧时使用的默认用户 ID。 | `admin`、`normal-user` |
| `CLIENT_AGENT_SOCKS5_ENABLED` | 是否启用 SOCKS5 本地入口。 | `true`、`false` |
| `CLIENT_AGENT_SOCKS5_LISTEN_IP` | SOCKS5 本地入口监听 IP默认只允许本机访问。 | `127.0.0.1`、`0.0.0.0` |
| `CLIENT_AGENT_SOCKS5_LISTEN_PORT` | SOCKS5 本地入口监听端口。 | `1080` |
| `CLIENT_AGENT_SOCKS5_UDP_LISTEN_IP` | SOCKS5 UDP ASSOCIATE 本地 UDP relay 监听 IP。 | `127.0.0.1`、`0.0.0.0` |
| `CLIENT_AGENT_SOCKS5_UDP_LISTEN_PORT` | SOCKS5 UDP ASSOCIATE 本地 UDP relay 监听端口。 | `1081` |
| `CLIENT_AGENT_SOCKS5_UDP_ADVERTISE_IP` | UDP ASSOCIATE 回复给应用的 UDP relay IP。 | `127.0.0.1`、Client Agent 局域网 IP |
| `CLIENT_AGENT_SOCKS5_AUTH_MODE` | SOCKS5 认证模式。`no-auth` 使用无认证,`userpass` 使用 RFC1929 用户名/密码认证。 | `no-auth`、`userpass` |
| `CLIENT_AGENT_SOCKS5_USERNAME` | SOCKS5 用户名,仅 `userpass` 模式使用。 | 自定义用户名 |
| `CLIENT_AGENT_SOCKS5_PASSWORD` | SOCKS5 密码,仅 `userpass` 模式使用。 | 强随机密码 |
| `CLIENT_AGENT_HTTP_PROXY_ENABLED` | 是否启用 HTTP 代理本地入口,支持 `CONNECT` 和普通 HTTP 绝对 URL 请求。 | `true`、`false` |
| `CLIENT_AGENT_HTTP_PROXY_LISTEN_IP` | HTTP 代理本地入口监听 IP默认只允许本机访问。 | `127.0.0.1`、`0.0.0.0` |
| `CLIENT_AGENT_HTTP_PROXY_LISTEN_PORT` | HTTP 代理本地入口监听端口。 | `8080`、`7890` |
| `CLIENT_AGENT_RAW_JSON_ENABLED` | 是否启用 raw-json 调试入口。 | `true`、`false` |
| `CLIENT_AGENT_RAW_JSON_LISTEN_IP` | raw-json 调试入口监听 IP。 | `127.0.0.1` |
| `CLIENT_AGENT_RAW_JSON_LISTEN_PORT` | raw-json 调试入口监听端口。 | `9000` |
| `POP_SERVER_ADDRESS` | POP Server 的 Agent 监听地址。必须带 `tcp://`。 | `tcp://10.1.0.2:9001`、`tcp://127.0.0.1:9001` |
| `LOG_LEVEL` | 日志级别预留配置。 | `debug`、`info`、`warning`、`error` |
Client Agent 的节点身份不是只写在 `.env`POP Server 侧还必须在 `config/nodes.php` 中声明同名节点:
```php
'client-01' => [
'node_type' => 'client',
'token' => 'CHANGE_ME',
'allowed_cidrs' => [
'192.168.0.0/16',
'10.10.0.0/16',
],
'allowed_ports' => [22, 80, 443, '8080-10080', 3306, 5432],
'enabled' => true,
],
```
当前 `allowed_cidrs``allowed_ports` 仍保留给后续 Agent 侧直连目标能力;新的最小路径会优先让 POP Server 直连公网目标。
当前 MVP 提供三种本地入口:
| 入口 | 默认状态 | 默认监听 | 适用场景 |
| --- | --- | --- | --- |
| SOCKS5 | 开启 | `127.0.0.1:1080` | 只能配置 SOCKS5 代理的应用。 |
| HTTP 代理 | 关闭 | `127.0.0.1:8080` | 支持 HTTP proxy 或 HTTP CONNECT 的应用。 |
| raw-json | 关闭 | `127.0.0.1:9000` | 开发调试,手工发送一行 JSON。 |
只能用 SOCKS5 的应用可直接配置:
```text
SOCKS5 Host: 127.0.0.1
SOCKS5 Port: 1080
```
SOCKS5 当前支持:
| 能力 | 状态 |
| --- | --- |
| 方法协商 | 支持 |
| 无认证 `0x00` | 支持 |
| 用户名/密码 `0x02`RFC1929 | 支持 |
| IPv4 地址 | 支持 |
| 域名地址 | 支持 |
| IPv6 地址 | 支持 |
| `CONNECT` | 支持 |
| `BIND` | 按协议返回 command not supported |
| `UDP ASSOCIATE` | 支持,经 LayLink `UDP_DATA` Frame 转发到 POP Server |
SOCKS5 UDP 转发路径:
```text
App UDP
-> Client Agent UDP relay
-> UDP_DATA Frame over Agent transport
-> POP Server
-> Public UDP target
```
UDP 访问仍然由 POP Server 的 `config/policies.php` 控制。默认示例允许 `53`、`123`、`443`
```php
[
'policy_id' => 'public-udp-egress',
'users' => ['normal-user', 'admin', 'devops'],
'target_hosts' => ['*'],
'target_ports' => [53, 123, 443],
'protocol' => 'udp',
'route_type' => 'direct',
'enabled' => true,
],
```
启用 SOCKS5 用户名密码认证:
```env
CLIENT_AGENT_SOCKS5_AUTH_MODE=userpass
CLIENT_AGENT_SOCKS5_USERNAME=alice
CLIENT_AGENT_SOCKS5_PASSWORD=change-this-password
```
如果启用 raw-json客户端连接 raw-json 端口并发送一行 JSON
```json
{"auth_token":"dev-token","user_id":"admin","target_host":"example.com","target_port":443,"protocol":"tcp"}
```
字段说明:
| 字段 | 作用 | 常见值 |
| --- | --- | --- |
| `auth_token` | 客户端认证 token。当前 MVP 固定为 `dev-token`。 | `dev-token` |
| `user_id` | 用户身份。POP Server 会用它匹配 `config/policies.php`。 | `admin`、`devops`、`normal-user` |
| `target_host` | 目标主机。 | `192.168.10.20`、`example.com` |
| `target_port` | 目标端口。 | `22`、`80`、`443`、`8080`、`5432` |
| `protocol` | 目标协议。当前只支持 TCP。 | `tcp` |
| `route_hint` | 预留字段。新的最小路径由 POP Server 直连公网目标,通常不需要填写。 | `null` |
## 策略如何配置
客户端访问是否允许,由 `config/policies.php` 决定。
示例:
```php
[
'policy_id' => 'public-web-egress',
'users' => ['normal-user', 'admin', 'devops'],
'target_hosts' => ['*'],
'target_ports' => [80, 443, '8080-10080'],
'protocol' => 'tcp',
'route_type' => 'direct',
'enabled' => true,
],
```
这条策略表示:
* `normal-user`、`admin` 和 `devops` 可以访问任意主机的 `80`、`443`,以及 `8080``10080` 端口。
* Client Agent 只负责把请求封装成 Frame 发到 POP Server。
* POP Server 校验策略后直接连接公网目标。
`target_ports``allowed_ports` 都支持两种写法:
* 单端口:`80`
* 端口范围:`'8080-10080'`
路由类型:
| `route_type` | 作用 |
| --- | --- |
| `direct` | POP Server 直接连接目标,适合公共互联网出口。 |
| `reject` | 拒绝访问。默认行为就是拒绝。 |
## 本地开发示例
一个最小本地开发 `.env` 可以这样写:
```env
APP_ENV=dev
POP_AGENT_LISTEN=127.0.0.1:9001
POP_ALLOWED_AGENT_TRANSPORTS=tcp,kcp
NODE_ID=client-01
NODE_TYPE=client
NODE_TOKEN=CHANGE_ME
AGENT_TRANSPORT_PROTOCOL=tcp
CLIENT_AGENT_AUTH_TOKEN=dev-token
CLIENT_AGENT_USER_ID=admin
CLIENT_AGENT_SOCKS5_ENABLED=true
CLIENT_AGENT_SOCKS5_LISTEN_IP=127.0.0.1
CLIENT_AGENT_SOCKS5_LISTEN_PORT=1080
CLIENT_AGENT_SOCKS5_UDP_LISTEN_IP=127.0.0.1
CLIENT_AGENT_SOCKS5_UDP_LISTEN_PORT=1081
CLIENT_AGENT_SOCKS5_UDP_ADVERTISE_IP=127.0.0.1
CLIENT_AGENT_SOCKS5_AUTH_MODE=no-auth
CLIENT_AGENT_SOCKS5_USERNAME=
CLIENT_AGENT_SOCKS5_PASSWORD=
CLIENT_AGENT_HTTP_PROXY_ENABLED=false
CLIENT_AGENT_HTTP_PROXY_LISTEN_IP=127.0.0.1
CLIENT_AGENT_HTTP_PROXY_LISTEN_PORT=8080
CLIENT_AGENT_RAW_JSON_ENABLED=false
CLIENT_AGENT_RAW_JSON_LISTEN_IP=127.0.0.1
CLIENT_AGENT_RAW_JSON_LISTEN_PORT=9000
POP_SERVER_ADDRESS=tcp://127.0.0.1:9001
AUDIT_LOG=runtime/audit.log
LOG_LEVEL=debug
```
## Agent 到 POP 的传输协议
Agent 到 POP Server 的业务数据始终使用 LayLink 自定义 Frame 协议封装。`AGENT_TRANSPORT_PROTOCOL` 只决定这些 Frame 运行在哪种底层传输上。
当前规划的传输类型:
| 值 | 含义 | 当前状态 |
| --- | --- | --- |
| `tcp` | Frame over TCP最容易部署和调试。 | 已实现 |
| `udp` | Frame over UDP需要额外处理可靠性、顺序和丢包。 | 已预留,未实现 |
| `kcp` | Frame over KCP/UDP默认通过 FFI 调用 native `ikcp.c`。 | 已实现,需构建动态库 |
POP Server 用 `POP_ALLOWED_AGENT_TRANSPORTS` 控制允许哪些传输协议。例如:
```env
POP_ALLOWED_AGENT_TRANSPORTS=tcp,kcp
# 也可以写成:
POP_ALLOWED_AGENT_TRANSPORTS=["tcp","kcp"]
```
Client Agent 用 `AGENT_TRANSPORT_PROTOCOL` 选择自己实际使用哪种协议。例如:
```env
AGENT_TRANSPORT_PROTOCOL=kcp
```
如果 Agent 选择的协议不在 POP 允许列表中POP 会在认证阶段返回 `AUTH_FAIL`,原因是 `transport_not_allowed`
`kcp` 默认使用 FFI 调用 native `ikcp.c`。首次使用前需要构建动态库:
```bash
scripts/build-kcp-ffi.sh
```
然后两端配置:
```env
LAYLINK_KCP_BACKEND=ffi
LAYLINK_KCP_FFI_LIB=native/kcp/liblaylink_kcp.so
```
使用 `kcp`POP Server 会在 `POP_AGENT_LISTEN` 的同一 host:port 上监听 UDPClient Agent 的 `POP_SERVER_ADDRESS` 仍填写同一地址即可。服务器防火墙需要放行同端口 UDP。
如果运行环境暂时不能启用 FFI可以配置 `LAYLINK_KCP_BACKEND=php` 使用调试回退实现;该实现不适合作为生产高吞吐路径。
KCP 可调参数:
| 变量 | 作用 | 建议 |
| --- | --- | --- |
| `LAYLINK_KCP_NODELAY` | KCP nodelay 开关。 | 默认 `1` |
| `LAYLINK_KCP_INTERVAL_MS` | KCP update 间隔,越小越低延迟但发包/CPU 更高。 | `10`、`20`、`30` |
| `LAYLINK_KCP_FAST_RESEND` | 快速重传阈值。 | `2`,拥堵时试 `3`、`4` |
| `LAYLINK_KCP_NO_CONGESTION_CONTROL` | 是否关闭 KCP 拥塞控制。 | 公网建议 `0`,内网压测可试 `1` |
| `LAYLINK_KCP_SEND_WINDOW` | KCP 发送窗口。 | `128`、`256`、`512` |
| `LAYLINK_KCP_RECV_WINDOW` | KCP 接收窗口。 | `256`、`512`、`1024` |
| `LAYLINK_KCP_MTU_BYTES` | KCP MTU。 | 公网建议 `1200`,内网可试 `1350` |
| `LAYLINK_KCP_TICK_MS` | PHP transport tick 间隔。 | 通常等于 `LAYLINK_KCP_INTERVAL_MS` |
| `LAYLINK_KCP_UDP_SEND_QUEUE_BYTES` | UDP 发送遇到 EAGAIN 时的本地排队上限。 | `16777216`、`33554432` |
| `LAYLINK_KCP_UDP_FLUSH_PACKETS` | 每次 tick 最多刷出的 UDP packet 数。 | 拥堵时 `64`/`128`,吞吐压测 `256`/`512` |
| `LAYLINK_KCP_OUTPUT_DRAIN_PACKETS` | 每次从 native KCP 输出队列搬到 UDP 发送队列的最大 packet 数。 | 延迟敏感用 `64`/`128`,吞吐压测用 `256`/`512` |
如果出现 `stream_socket_sendto(): Resource temporarily unavailable`,说明 UDP socket 发送缓冲暂时满了。LayLink 会把 KCP packet 放入本地发送队列并在后续 tick 重试;同时建议把 `LAYLINK_KCP_NO_CONGESTION_CONTROL` 保持为 `0`,必要时降低 `LAYLINK_KCP_SEND_WINDOW`、`LAYLINK_KCP_UDP_FLUSH_PACKETS` 或调大 `LAYLINK_KCP_INTERVAL_MS`
KCP/UDP 目前不要把 `POP_AGENT_KCP_WORKERS` 调大。KCP 会话状态存在单个 worker 进程里UDP 多 worker 会让同一个会话的数据包分散到不同进程,导致找不到会话、重传增加甚至断流。要横向扩展 KCP当前推荐启动多个 POP 端口或多个 POP 实例,由 Client Agent 配置多 POP/多进程策略;后续可以做 `SO_REUSEPORT` 五元组哈希、外部 session 表或每 conv 固定 worker 分发。
单 worker 并不等于一个大下载会同步阻塞其他请求目标连接、UDP socket 和本地客户端都是非阻塞 I/O。但大文件会带来大量 KCP 分片和加密/解密/FFI 调用,可能短时间占用事件循环 CPU。延迟敏感场景可降低 `LAYLINK_DATA_CHUNK_BYTES`、`LAYLINK_KCP_OUTPUT_DRAIN_PACKETS` 和 `LAYLINK_KCP_UDP_FLUSH_PACKETS`,让一个大流量会话每次 tick 少占一点时间,换取更好的多会话公平性。
如果 Agent 配置为 `udp`,进程会启动失败并明确提示该传输尚未实现。
启动 POP Server
```bash
php bin/pop-server.php start
```
另一个终端启动 Client Agent
```bash
php bin/client-agent.php start
```
然后把应用的代理设置为 SOCKS5 `127.0.0.1:1080`。Client Agent 会解析 SOCKS5 `CONNECT`,封装成 `OPEN` 帧发给 POP ServerPOP Server 校验通过后直连公网目标,随后通过 `DATA` 帧转发原始 TCP 数据。
TCP 大流量 `DATA` 帧使用二进制帧编码;`AUTH`、`OPEN`、`CLOSE`、`ERROR` 等控制帧仍使用 JSON 编码。启用 `chacha20` 时,二进制和 JSON Frame body 都会被加密。
吞吐相关参数由两端共用POP Server 和 Client Agent 建议保持一致:
```env
LAYLINK_DATA_CHUNK_BYTES=1048576
LAYLINK_MAX_SEND_BUFFER_BYTES=67108864
LAYLINK_BACKPRESSURE_HIGH_WATERMARK_BYTES=33554432
```
`LAYLINK_DATA_CHUNK_BYTES` 越大,每 MB 需要处理的 Frame 越少,单连接下载通常越快;如果多会话公平性变差,可以降到 `262144``524288`。`LAYLINK_BACKPRESSURE_HIGH_WATERMARK_BYTES` 必须小于 `LAYLINK_MAX_SEND_BUFFER_BYTES`
大文件下载时LayLink 会使用 Workerman 的 `pauseRecv()` / `resumeRecv()` 做背压:当下游发送缓冲区过高时暂停上游读取,缓冲排空后继续读取。这可以避免单个慢连接无限堆积内存或因为发送缓冲区满而断联。
当 POP 收到目标站关闭连接时Client Agent 会先等待本地客户端发送缓冲区排空,再关闭本地 socket避免大文件尾部数据还在缓冲区里时被提前截断。TCP `DATA` 默认按 1 MiB 分片发送,以减少帧开销;可通过 `LAYLINK_DATA_CHUNK_BYTES` 调整。
Client Agent 默认使用 1 条 Agent-to-POP TCP 长连接。可通过 `CLIENT_AGENT_POP_CONNECTIONS` 增加并行长连接数,新 TCP 会话会在已认证 POP 连接之间轮询分配,并在会话生命周期内固定使用同一条连接。它主要改善多并发请求、多线程下载或测速场景;单个 TCP 下载是否变快取决于客户端和目标站是否本身使用多连接。背压可以保护进程不堵死,但单条会话仍受单 TCP 流限制KCP、per-session window 和更细粒度 TCP 调优仍是后续性能优化方向。
验证 SOCKS5 HTTPS 联通性和出口 IP
```bash
scripts/verify-socks5.sh
```
默认使用 `127.0.0.1:1080`。如果启用了 SOCKS5 用户名密码:
```bash
SOCKS5_USER=alice SOCKS5_PASSWORD=change-this-password scripts/verify-socks5.sh
```
## 部署检查清单
部署前至少确认:
* `NODE_TOKEN` 已替换为强随机密钥。
* `config/nodes.php` 中的 `token` 和 Agent `.env` 中的 `NODE_TOKEN` 一致。
* `NODE_TYPE``config/nodes.php` 中的 `node_type` 一致。
* Agent 的 `allowed_cidrs``allowed_ports` 足够窄。
* `config/policies.php` 不存在过宽的 `target_hosts``target_ports`
* 生产环境不要继续使用固定的 `dev-token` 客户端认证。
* 生产环境应补充 TLS、JWT 或 mTLS、限流和更完整的审计存储。