DOCUMENTATION

开发文档

从本地运行到自托管部署,理解匿名身份、签名协议与节点接入方式。

快速开始

仓库是一个 monorepo:server/ 为 Go 控制面,admin-web/ 为 React 管理后台,website/ 为静态官网,shared-core/ 为 Rust 共享核心,clients/ 为五端骨架。

# 已内置便携工具链(Node 24 / Go 1.27)
./scripts/dev.sh          # 启动 API + 官网,http://localhost:8080
./scripts/dev-admin.sh    # 管理后台开发模式,http://localhost:5173
./scripts/build.sh        # 构建后台与 server 二进制
./scripts/test.sh         # Go 单测 + Node 模拟客户端端到端测试

管理后台路径为 /admin/,默认开发令牌为 dev-admin-token,通过环境变量 OPENLINK_ADMIN_TOKEN 修改。

服务端当前使用 JSON 文件持久化(server/data/state.json),生产环境建议切换 PostgreSQL,接口层已按可替换 Store 设计。

匿名身份

账号不是服务端"注册"出来的,而是由客户端本地密钥推导:

  • 身份密钥:Ed25519,首启本地生成,私钥永不出设备。
  • 账号 ID:usr_ + base32(sha256(identity_pubkey)[:5]),8 位小写字母数字。
  • 隧道密钥:WireGuard X25519,可随节点轮换,与账号身份解耦。
  • 设备指纹:客户端提交的随机设备标识,服务端加盐哈希后存储,仅用于防滥用。

建档接口是幂等的:同一个身份密钥重复请求会返回同一个账号,不会重复分配 IP 或扣减配额。

API 与签名

所有需要身份的操作都通过请求头传递签名,不使用 Cookie 或会话 Token:

X-Account-ID:   usr_xxxxxxxx
X-Identity-Key: <base64 Ed25519 public key>
X-Timestamp:    <unix seconds>
X-Nonce:        <随机串,≥8 字符>
X-Signature:    <base64 Ed25519 signature>

签名原文(| 分隔,严格匹配):

匿名建档:  openlink-anon-v1|{account_id}|{identity_key}|{wg_key}|{platform}|{device_fingerprint}|{timestamp}|{nonce}
获取配置:  openlink-config-v1|{account_id}|{timestamp}|{nonce}
账号状态:  openlink-me-v1|{account_id}|{timestamp}|{nonce}
轮换密钥:  openlink-keyrotate-v1|{account_id}|{new_wg_key}|{timestamp}|{nonce}

时间戳窗口为 ±5 分钟,Nonce 15 分钟内不可重复。服务端验签失败会累计风控指标。

接口一览

方法路径说明
POST/api/v1/account/anonymous幂等匿名建档,返回 WireGuard 配置
GET/api/v1/config签名获取当前最优节点配置
GET/api/v1/account/me签名查看账号、流量与限速
POST/api/v1/key/rotate轮换隧道公钥
GET/api/v1/nodes公开节点状态
GET/api/v1/announcement当前活动公告
POST/api/v1/feedback匿名反馈
POST/api/v1/node/traffic节点上报流量(X-Node-Token)
GET/api/v1/node/peers节点拉取 Peer 列表(X-Node-Token)
GET/api/v1/admin/*管理接口(X-Admin-Token)

最小签名示例(Node.js)

import { generateKeyPairSync, sign, createHash } from 'node:crypto';

const { publicKey, privateKey } = generateKeyPairSync('ed25519');
const der = publicKey.export({ type: 'spki', format: 'der' });
const raw = der.subarray(-32);
const idKey = raw.toString('base64');

const ALPHABET = 'abcdefghijklmnopqrstuvwxyz234567';
// base32(sha256(raw)[:5]) → accountId = 'usr_' + ...
const ts = Math.floor(Date.now() / 1000);
const nonce = crypto.randomUUID();
const message = `openlink-config-v1|${accountId}|${ts}|${nonce}`;
const signature = sign(null, Buffer.from(message), privateKey).toString('base64');

节点接入

每个节点部署 WireGuard 与 node-agent。控制面通过管理接口登记节点;node-agent 定时拉取 Peer 列表并按返回结果增删对账,同时采集增量流量上报。仓库内置 Go 版 agent(server/cmd/node-agent),支持 OPENLINK_DRY_RUN=1 预演:

cd server
go build -o ../dist/openlink-node-agent ./cmd/node-agent

OPENLINK_API_BASE=https://api.hlutharyea.com \
OPENLINK_NODE_ID=tokyo-1 \
OPENLINK_NODE_TOKEN=<节点令牌> \
OPENLINK_DRY_RUN=1 ../dist/openlink-node-agent

手工排查时可直接调用接口:

curl "http://control-plane:8080/api/v1/node/peers?node_id=tokyo-1" \
  -H "X-Node-Token: <节点令牌,后台可复制>"
# 返回 {"node": {...}, "peers": [{"wg_public_key": "...", "assigned_ip": "10.64.0.2"}]}
# 以此列表为准:新增缺失 Peer,删除已不在列表中的 Peer

wg show wg0 dump | awk '{print $1, $6, $7}'
# pubkey, rx_bytes, tx_bytes(需自行计算与上次的增量)

curl -X POST http://control-plane:8080/api/v1/node/traffic \
  -H "X-Node-Token: <节点令牌,后台可复制>" \
  -H "Content-Type: application/json" \
  -d '{
    "node_id": "tokyo-1",
    "online_peers": 42,
    "peers": [{"wg_public_key": "...", "rx_bytes": 1048576, "tx_bytes": 524288}]
  }'

流量统计只信任节点上报,不接受客户端自报。账号的日软上限、观察期限速由控制面计算并随配置下发。

每次上报同时充当节点心跳:超过 5 分钟没有上报的节点会被自动标记离线,其上账号迁移到其他在线节点;节点恢复上报后自动回到在线。可用 OPENLINK_NODE_STALE 调整阈值,设为 0 关闭巡检。

自托管部署

生产环境建议使用独立控制面与多地域节点:

  • 控制面:1 台 2C2G 云主机,运行 API + 官网;当前版本使用单实例 JSON 持久化,多实例前需替换为 PostgreSQL。
  • 节点:每地域 2 台以上,开启 IP 转发,NAT 出口使用 nftables。
  • 入口:Nginx 或 Cloudflare 终止 TLS,转发 /api 与 /admin,传递 X-Forwarded-For,并设置 OPENLINK_TRUSTED_PROXIES 只信任回源代理地址。
  • 环境变量:OPENLINK_ADMIN_TOKEN、OPENLINK_HASH_SALT、OPENLINK_DATA_DIR、OPENLINK_DEV=0。
# 示例:构建并启动
./scripts/build.sh
cd server
OPENLINK_DEV=0 \
OPENLINK_ADMIN_TOKEN="$(openssl rand -hex 24)" \
OPENLINK_HASH_SALT="$(openssl rand -hex 24)" \
../dist/openlink-server.exe

上线前务必:更换管理员令牌与哈希盐、启用 HTTPS、限制管理后台来源 IP、将节点令牌纳入密钥管理,并配置监控告警。

客户端开发

共享核心位于 shared-core/(Rust):负责身份生成、签名、配置构建。各端通过 FFI 或原生实现复用同一套签名规范。

  • clients/ios:SwiftUI + NetworkExtension,XcodeGen 工程描述。
  • clients/android:Kotlin + Compose + VpnService + WireGuard 库。
  • clients/harmonyos:ArkTS + Stage 模型 + @ohos.net.vpnManager。
  • clients/macos:SwiftUI + System Extension。
  • clients/windows:Tauri 2 + React + WireGuard NT。

各目录 README 包含构建前置条件、签名配置与当前完成度。

安全与合规

本项目是技术实现参考,不构成对任何地区网络接入服务的合规承诺。部署与分发前请自行确认当地法律、应用商店政策与运营商要求。

  • 不记录浏览目标、DNS 查询与连接明细。
  • 原始 IP 与设备标识仅以加盐哈希保存,且仅用于防滥用。
  • 管理员接口必须走 HTTPS,并限制访问来源。
  • 禁止将本项目用于攻击、欺诈或其他违法用途。