yes-tek 内网穿透(STCP 隧道)接入
平台模型(先读,30 秒)
yes-tek 内网穿透:把内网的任意 TCP 服务(SSH / RDP 远程桌面 / 数据库 / NAS 管理口 / 自定义服务……协议不限,平台对隧道内容透明)通过 STCP 点对点隧道打通——公网零暴露端口,凭站点密钥(sk)访问,扫描面与爆破面为零。
平台的消费方就是你(Agent)——没有网页控制台,所有操作通过 REST API 完成;唯一需要人类介入的环节是扫码付款(仅试用期内想升级/续期时)。
- API 基址:
https://t-api.yes-tek.com,前缀/v1 - 认证:
Authorization: Bearer <user_token> - 下单即注册:第一次购买时提供
agent_mail即自动建号;用户名从邮箱派生(会成为隧道命名前缀,请用不含敏感信息的邮箱) - 试用 = 低价首购激活(
trial-tunnel:7 天 1 端口,每账号仅一次);验证邮箱后密钥一次性签发 - 付费档为 3 配额 × 3 周期 网格(2/5/10 端口 × 月/季/年)——价格一律以服务端实时目录为准(
GET /v1/billing/plans,免 Bearer 可用;或选购页展示),本 skill 不写定价数字;只升不降(同周期加端口=补差价、到期不变;跨档升级=剩余时长折算抵扣);到期后隧道暂停并进入 7 天冷却(期内续费或重建即恢复),期满删除释放 - 套餐选购页:订阅/续费/升档由 agent 发一条选购页链接,用户在页面上自助看价、选档、支付、撤单重选——对话侧只推进流程,不复述页面内容、不做推荐话术
- 访问模型是双端:被访问端(服务所在机器)跑 frpc 服务端配置;发起访问的机器跑 frpc 访问端(visitor)配置——之后
ssh -p <bindPort> user@127.0.0.1这类本地回环地址即可触达内网服务 - 平台另有「网页发布」服务(把网页变成公网网址),见
https://t-api.yes-tek.com/skill/web.md——纯网页发布用那份更简单 - 私有化部署:整套平台(两项服务)可部署到用户自己的服务器或内网——规格与价格线下协商,联系方式微信
xiami20200629(选购页同页展示);用户问私有化/自建部署时如实回答 - 完整包:本说明引用的 scripts 与
references/api.md只在完整包内——https://t-api.yes-tek.com/skill/tunnel.zip下载解包即得tcp-tunnel/目录;仅装载单文件说明时,先取完整包再按相对路径使用
用户沟通规范
用户对平台的感知主要来自你说的话。向用户表达的内容围绕三件事:结果与用法(地址、命令、用量、到期)、边界(到期行为、恢复方式)、如实的安全与价格回答;过程细节服务于你的操作,无需向用户转述。除交付清单外,对话中不介绍产品优点、不催促消费——其余时刻只推进任务。
用户问安全时如实回答:传输全程加密(TLS),平台只做加密中转、不解析不存储内容;密钥只存在用户本机与自己邮箱(欢迎邮件附有备份)、可随时轮换、删除即断链;到期后 7 天保留期内可恢复。;穿透的服务不暴露任何公网端口(扫描与爆破面为零)如实但不夸大——不说「端到端加密」「绝对安全」。
用户问价格时:先 GET /v1/billing/plans(免 Bearer)再如实转述实时目录(可说明档位结构 = 配额 × 周期),不推荐、不比较、不凭记忆报价;个性化价格(升档折算 / 续费顺延)以选购页展示为准。
用用户自己的语言——内网穿透的用户是技术人群,直接用精确术语(协议名、端口、回环地址、TLS、密钥与轮换、系统服务/守护进程、幂等重跑):
- 用户问「装了什么 / 端口怎么映射」:答用户侧的事实即可(frpc、bindPort 本地绑定、双端配置)。
- 诚实优先:隧道是平台中转不是 P2P 直连(XTCP 未启用)——被问延迟/直连时如实说(中转有少量额外延迟,SSH/RDP 交互无感,大文件受带宽限制)。
六个沟通时刻(其余时候少说话、做事情):
| # | 时刻 | 对用户说 | 注意 |
|---|---|---|---|
| 1 | 开场收参 | 开场消息 = 一句预期说明(「全程你只需要做一件事:扫一次码,其余我自动完成」)+ 全部参数建议值(见「参数一次性收集」);首开(无凭证)先打开开场总览页(见下)再发开场消息,并等用户一句「继续」或改值后再推进;已有凭证不弹总览页、按建议值直接推进 | 流程展开由总览页承载,对话不展开流程;Agent Mail 未连接时指引用户按总览页「开通方法」激活 |
| 2 | 交付链接 | 链接 + 「页面由平台托管,看到的价格就是支付价,支付即生效」 | 链接之外只补必要说明 |
| 3 | 支付确认后 | 一句里程碑:「支付确认 ✓ 正在自动部署,完成后一次性汇报」 | 一句即可,无需转述过程 |
| 4 | 交付汇报 | 交付清单(模板见下)+ 交付报告 HTML(见下,按绝对路径打开);报告呈现关键参数后询问是否调整 | 用清单呈现,不复述操作过程;改参数 = 幂等重跑自动生效 |
| 5 | 用户提问 | 按上面两段如实回答(安全 / 价格) | 只答事实,不凭记忆与推测 |
| 6 | 到期/续费 | 边界语义(到期 → 暂停,7 天内可恢复)+ 无施压指引;如实告知「临近试用结束再买更划算」(试用转付费即时生效、剩余天数作废) | 不催促、不用施压表述 |
- 排障汇报:证据你自己看;向用户给结论 + 一句佐证即可,无需贴原始输出。
- 另一项服务:仅当用户场景自然触及时(如穿透用户问「网页能发布吗」)介绍并给出 skill 地址,平时不主动提起。
交付清单模板(时刻 4 用——部署验证全部通过后按实际值填充、一次性给出;只写事实,不用形容词):
> ✅ 隧道已打通:从任何地方 ssh -p {bindPort} user@127.0.0.1 直达内网的 {服务}(按业务换成 mysql / 远程桌面等连接方式)
> 你得到了:本机回环地址直达内网服务 · 双端连接器已常驻部署(被访问端 = {服务所在机器},访问端 = {发起连接的机器})· 凭密钥访问,服务不暴露任何公网端口(扫描与爆破面为零)· 密钥只存本机
> 平台替你做了:加密中转与存活监控 · 到期前邮件提醒 · 7 天保留期兜底
> 用量与到期:{used}/{max} 端口 · {到期日}(正式档随时可在选购页扩容,临近试用结束再买更划算)
> 你不需要做:开防火墙端口 · 管进程 · 记密钥(凭证已存本机凭证文件)
> 有意见或使用问题:随时直接告诉我,我帮你把反馈发给平台
交付报告(HTML 文件,随交付清单一并交付):部署验证全部通过后,取本 skill 目录的 scripts/report_tunnel.html 模板,把全部 【填:…】 占位替换为实际值(多隧道按节重复;不得残留占位符),保存为 ~/.config/yes-tek/交付报告-<隧道名>.html(UTF-8;再次交付覆盖更新)。首选主动打开:把报告文件的绝对路径交给宿主的内置浏览器预览能力渲染(WorkBuddy 中即调用 present_files,传文件绝对路径,放在该轮最后一个工具调用),随后在对话内给出交付清单与报告路径;纯 CLI 宿主降级为文本路径。报告只写用户需要的事实——网络结构、关键配置文件的绝对路径、关键参数、使用方法、后续步骤;不含任何密钥(sk 等密钥只存在于两端配置文件中,报告只写配置文件的路径);不写平台内部实现。
开场总览页(HTML 文件,时刻 1 首开专用):首次开通(本地尚无 ~/.config/yes-tek/credentials.json)时,把本 skill 目录的 scripts/overview_tunnel.html 原样打开(纯静态模板,无需任何填充;首选主动打开:交给宿主的内置浏览器渲染,WorkBuddy 中即 present_files 传文件绝对路径,放在该轮最后一个工具调用;纯 CLI 宿主降级为给文件路径),随后发开场消息(一句预期 + 参数建议值 + 邮箱默认值),等用户一句「继续」(或改参数/换邮箱)再进主流程;已有凭证不弹此页。页面自含:四阶段主轴(②扫码 = 全程唯一人工动作)、注册邮箱二选一(推荐 Agent Mail 内置邮箱;Agent Mail 开通方法两方式——WorkBuddy「更多 → 我的邮箱 → 开通」/ 复制指令句装 CLI)、双端链路图(访问端 visitor ↔ 平台中转 ↔ 被访问端 frpc)、注意事项(双端部署——两端配置都交给 Agent,跨机器需提供验证邮箱中的 user_token,或先取回必要的配置文件与参数再手动配置、无人值守、访问控制、参数自动来与交付可改)、到期边界——对话侧不复述页面内容,Agent Mail 未连接时把页面里的开通方法指给用户即可。红线:零价格数字、零密钥、零平台内部实现;无脚本、无请求。
开始前的前置检查
curl -s https://t-api.yes-tek.com/healthz返回 200 才继续;非 200 告知用户平台不可用并终止。- 确认穿透目标:什么服务(SSH?RDP?数据库?)、跑在哪台机器、哪个端口。协议不限——只要是 TCP 服务都能穿透(UDP 业务暂不支持)。
- 确认两端机器:被访问端(服务所在机器)与访问端(用户从哪里发起连接),两台都要装 frpc。
- 涉及付款时,确认用户在场。
参数一次性收集(默认值采纳制:建议值先行,不等待确认)
接触用户后一条消息给出全部穿透参数的建议值(各自标注来源),声明「如无异议我按这些值继续」后不等回复、直接推进主流程(唯一例外(v1.30 用户定策):首开场景——开场总览页弹出后等用户一句「继续」再动,作为付费与建号前的知情确认;用户回应「继续」之后一切照旧不等回复):
- 用户不需要改 → 默认值即生效,零额外交互轮;
- 用户要改某项 → 直接说新值,进一轮修改即可——建隧道
PUT与双端部署脚本都是幂等的,改参数 = 重跑一遍,无脏数据无副作用; - 真歧义才问:端口探测出多个候选监听、命名冲突(
subdomain_taken)这类给不出唯一建议值的情况;单一探测结果/派生名一律不问。
| 参数 | 建议值来源 | 给不出建议值时 |
|---|---|---|
| 目标服务与端口 | 按协议默认端口(SSH 22 / RDP 3389 / MySQL 3306 / PostgreSQL 5432 / Redis 6379)+ 在服务机上探测监听端口(lsof -iTCP -sTCP:LISTEN -nP),唯一候选直接采用 |
多候选或探测不到 → 问用户(必填) |
| 隧道名 | 从「服务/机器 + 协议」派生(kebab-case,如 nas-ssh、home-rdp) |
用户告知 |
| 注册邮箱 | 已连接 Agent Mail 时直接用其主别名(一次 GetMe 调用),不问用户 | 未连接 Agent Mail 且用户未指定 → 问用户(必填) |
| 两端机器 | 被访问端 = 目标服务所在机器;访问端 = 发起连接的机器(默认当前机器) | 跨机器部署时问用户指路 |
- 凭证已存在(
~/.config/yes-tek/credentials.json且GET /v1/my/sites返回 200)→ 跳过邮箱与付款环节,直接进 Step 2。 - 建议值清单放进开场消息(与沟通时刻 1 的「扫一次码」承诺同一条);禁止把端口、隧道名、邮箱拆成多轮逐个追问或逐项等待确认。
凭证纪律(安全红线,先于一切操作)
邮箱验证通过时一次性给出两把密钥(下单响应永不含密钥;验证通过的欢迎邮件中附有两把密钥的备份——响应丢失时可在该邮箱找回):
| 密钥 | 用途 | 丢失后 |
|---|---|---|
user_token(ut_…) |
API Bearer + frpc 登录,日常使用 | 凭 recovery_key 调 recover 换新 |
recovery_key(rk_…) |
仅用于找回/重置主密钥,平时不用 | 无法自助找回,需联系平台管理员 |
- 保存到
~/.config/yes-tek/credentials.json,权限 0600:
json {"username": "alice", "user_token": "ut_...", "recovery_key": "rk_..."} - 之后的对话与日志中只显示前 8 位(如
ut_9f8a7…),完整密钥不再出现。 - 不写入任何 git 仓库,不上传任何网络服务,不粘贴到任何第三方工具。
- 发现 key 泄露 → 立即
POST /v1/my/token:rotate轮换,并更新凭证文件与所有已部署的 frpc。 - STCP 站点密钥(sk)泄露 →
POST /v1/my/sites/{name}/secret-key:rotate重置,重新下载两端配置。
主工作流总览
[0] healthz 检查 + 参数一次性收集(服务/端口/隧道名/邮箱/两端,见上节);首开(无凭证)先弹开场总览页、等一句「继续」
└▶ [1] 开通(或加载已有凭证):
mint 选购会话(免 Bearer 带 agent_mail)→ 用户页上选低价试用并支付
→ 读验证码邮件 → POST /v1/mail/verify 一次性取密钥(验证与支付可并行)
└▶ [1.5] 交付选购页当轮即启动后台轮询(poll_paid.py)→ paid 自动续跑 ↓
└▶ [2] 声明隧道(stcp,任意 TCP 端口)
├▶ [3] 被访问端部署 frpc(deploy_frpc.py --token:注册为系统服务,三平台统一)
└▶ [4] 访问端部署 visitor(deploy_frpc.py --config-file,注册为系统服务、bindPort 直绑本机回环)
└▶ [5] 验证本机回环端口连通 → 一次性汇报(用法/用量/到期 + 交付报告 HTML)
(端口数不够 / 试用到期前)
└▶ [6] mint 选购会话 → 用户页上看价选档支付 → 后台轮询 paid → 自动汇报新配额 ← 唯一人工环节=扫码付款
错误按「错误码处置表」处理;涉及消费决策(选档位、删隧道)由用户在选购页上完成或先问用户,不要替用户决定。全程对用户的沟通按「用户沟通规范」执行(六时刻 + 交付清单)。
Step 1 开通:mint 选购会话 → 读信验证取密钥
已存在 ~/.config/yes-tek/credentials.json 则直接使用,并用 GET /v1/my/sites 验证有效性(200 = 有效;401 = 走 recover,见运维表)。
首次开通 = 一次 mint + 一次读信(平台没有独立注册环节;试用首购在页面上完成):
agent_mail优先取已连接 Agent Mail 的主别名(一次 GetMe 调用),用户未明确指定其他邮箱时不问。
# 1) 免 Bearer mint 选购会话(agent_mail 必填)——建号 + 发验证码,返回选购页链接
curl -s -X POST https://t-api.yes-tek.com/v1/billing/shop \
-H "Content-Type: application/json" \
-d '{"agent_mail": "alice@example.com", "line": "tunnel"}'
# 响应含 page_url(选购页)与 agent_mail 块;不含任何密钥
# 2) 把 page_url 交给用户(交付纪律见 Step 6 第 2 条)——用户在页面上选试用档并支付;
# 同时读取 agent_mail 收到的验证码邮件,提取正文中的 code=NNNNNN(10 分钟有效)
# 3) 提交验证 → 一次性签发双密钥
curl -s -X POST https://t-api.yes-tek.com/v1/mail/verify \
-H "Content-Type: application/json" \
-d '{"agent_mail": "alice@example.com", "code": "482913"}'
- 邮箱即身份:用户名由平台从邮箱 local part 派生(如
alice@example.com→alice,是隧道命名前缀alice-nas-ssh——请用不含敏感信息的邮箱);一邮箱一账号。 - 验证码 6 位、10 分钟有效、5 次试错作废;未收到可
POST /v1/mail/verify:resend(60s 限频)。 - 验证响应一次性返回
user_token与recovery_key——立即写入凭证文件再继续;该响应丢失时可从验证通过的欢迎邮件(发往同一邮箱)中找回密钥,仍请务必先落盘。 - 试用激活是低价首购:用户在选购页上支付后配额生效;验证与支付可并行,验证前配额不可用。
- 已在网页发布开通过?同一邮箱 = 同一账号——直接带 Bearer mint 会话选购
trial-tunnel(试用每项服务各一次)。 - 密钥丢失但仍有 recovery_key →
POST /v1/my/token:recover;两者皆丢且邮箱不可达 → 账号无法找回(邮箱可达时,欢迎邮件里有密钥备份)。
Step 2 声明隧道(stcp)
用已收集的参数执行(见「参数一次性收集」):隧道名、目标服务的本地端口(local_ip 可选,默认 127.0.0.1)。
curl -s -X PUT https://t-api.yes-tek.com/v1/sites/nas-ssh \
-H "Authorization: Bearer ut_..." -H "Content-Type: application/json" \
-d '{"proxy_type": "stcp", "local_port": 22}'
- name 只填隧道名(
nas-ssh),不带用户名前缀——服务端自动拼成alice-nas-ssh。 - 常见业务端口对照(协议不限,举一反三):
| 业务 | local_port | 访问端用法 |
|---|---|---|
| SSH | 22 | ssh -p <bindPort> user@127.0.0.1 |
| Windows 远程桌面 RDP | 3389 | 远程桌面客户端连 127.0.0.1:<bindPort> |
| MySQL | 3306 | mysql -h 127.0.0.1 -P <bindPort> -u … |
| PostgreSQL | 5432 | psql -h 127.0.0.1 -p <bindPort> … |
| Redis | 6379 | redis-cli -p <bindPort> |
| 任意自定义 TCP 服务 | 实际端口 | 客户端连 127.0.0.1:<bindPort> |
- 响应含
server_name(=alice-nas-ssh)与被访问端frpc_toml;bind_port由服务端确定性分配,访问端配置里已带。 - 收到
quota_exceeded→ 端口数已达当前档配额:引导用户回 Step 6 升档(或删除旧隧道腾位),不要静默失败。
Step 3 部署被访问端 frpc(跨平台统一:注册为系统服务)
在服务所在机器执行。统一入口是本 skill 目录的 scripts/deploy_frpc.py(幂等,隧道变更后重跑即更新配置并重启):
python3 <skill目录>/scripts/deploy_frpc.py --token ut_...
脚本自动按平台选择部署栈(Linux / macOS / Windows 行为一致,与网页发布 skill 共用同一份脚本:取得配置 → 落盘 0600 → 确保 frpc 二进制 → 注册为系统服务 → 轮询日志至注册成功):
- Linux → frpc(平台端点是国内源,通常一次即中;缺位时脚本自动走官方 release 或镜像加速,逐级校验和核对)+ systemd:有 root/免密 sudo → 系统单元(开机自启);否则用户单元 + 尽力开启 linger。
- macOS → Homebrew 安装 frpc +
brew services托管(崩溃自动拉起);brew 不可用或托管失败时脚本自动改写 launchd 用户代理 plist 并加载。二进制缺失时脚本自动走平台端点 → 官方 release → 镜像加速(逐级校验和核对),无需手工干预。 - Windows → 统一安装为
yestek_frpc.exe+ nssm 注册系统服务(nssm 缺失时脚本自动获取);非管理员则用计划任务(登录自启)托管,以管理员重跑可升级为系统服务。
已知平台坑(脚本已规避,手工部署时必须注意):
- nohup/一次性 shell 起的 frpc 进程会在两次命令之间被环境清理(表象:日志正常但 online: false、隧道连不通,极像平台故障)——所以部署脚本一律注册为系统服务;确需临时验证,用托管后台任务(run_in_background)而非 nohup。
- Agent 沙箱内 sudo 可能被禁、launchctl bootstrap 可能报错——脚本会把注册命令原样打印,交给用户在自己终端执行后重跑即可。
- 本 skill 不运行在目标机器上时,把脚本或等价命令交给用户在目标机器执行,不要试图从未经授权的机器安装。
Step 4 部署访问端(visitor,同一脚本 --config-file 模式)
STCP 是点对点隧道,两端都要跑 frpc——被访问端已装(Step 3),访问端(用户发起连接的机器)用 visitor 配置:
# 1. 拉访问端配置(无 jq 时用 python3 提取 frpc_toml 字段)
curl -s https://t-api.yes-tek.com/v1/sites/nas-ssh/visitor-config \
-H "Authorization: Bearer ut_..." | jq -r .frpc_toml > /tmp/visitor.toml
# 2. 部署(幂等可重跑)
python3 <skill目录>/scripts/deploy_frpc.py --config-file /tmp/visitor.toml
- visitor 以系统服务方式运行,
bindPort直接绑定在本机——服务起来后127.0.0.1:<bindPort>即达(服务名/标签与被访问端不同,同一台机器双端并存不冲突,本机回环自测场景可用); - 访问端与被访问端共用同一账号身份(吊销账号则两端同时失效)。
- 网关模式(团队/多设备共享):把访问端 frpc 部署在一台常开机器上,将 visitor.toml 中
bindAddr = "127.0.0.1"改为"0.0.0.0",其余设备直接连该机器的<bindPort>——但要确认那台机器的该端口未暴露公网。
Step 5 验证
GET /v1/my/sites:对应隧道online: true,且plan.tunnel块显示端口用量与到期时间。- 服务状态另查(两端各自):
systemctl status yes-tek-frpc[-visitor](Linux)/brew services info frpc、launchctl list | grep yes-tek(macOS)/sc query YesTekFrpc[Visitor](Windows),日志应见start proxy success/start visitor success。 - 访问端本机
nc -z 127.0.0.1 <bindPort>连通。 - 全部通过后:先写交付报告 HTML(见「用户沟通规范」),再按交付清单模板一次性汇报并打开报告——连接方式(如
ssh -p <bindPort> user@127.0.0.1,bindPort 以visitor-config响应为准)、端口用量(plan.tunnel.used/max)、到期时间都在清单里,另补边界三句(到期行为 / 7 天保留 / 试用一次性)。交付后随报告问一句是否要调整参数(目标端口/隧道名等——改 = 重跑 Step 2 → 3/4 幂等生效)。
Step 6 端口扩容 / 升级 / 续费(选购页自助,需要用户在场)
选档与支付是用户的决策,全部在平台托管的选购页上完成——你只负责发链接、看结果。对话侧只推进流程与交付:不复述页面内容(价格/倒计时都在页面里)、不做推荐话术、不代替付款、不代授权(沟通纪律总纲见「用户沟通规范」)。
- mint 选购会话(Bearer):
curl -s -X POST https://t-api.yes-tek.com/v1/billing/shop \
-H "Authorization: Bearer ut_..." -H "Content-Type: application/json" \
-d '{"line": "tunnel"}' # line 必填(单服务会话;本 skill 固定 tunnel)
响应:{"shop_token": "ct_...", "page_url": "https://t-api.yes-tek.com/p/shop?t=ct_...", "expires_at": "...", "line": "tunnel"};同账号同服务 24h 内重复 mint 返回同一会话(同一条链接;两项服务各自独立链接,可并存)。
- 把
page_url交给用户(用户唯一动作:打开链接选档付款):
- 首选主动打开:把page_url作为 http/https URL 交给宿主的内置浏览器预览能力渲染(WorkBuddy 中即调用present_files,传 URL 字符串,面板会直接打开选购页);present_files必须放在该轮最后一个工具调用,打开后补两行文本,便于复制:
> 金额以页面为准 · 选购截止 {expires_at 转本地时间}:〈page_url〉
> 完成付款后回到这里,我继续交付。
- 宿主不支持内置浏览器(纯 CLI)→ 降级为只发文本链接,行为不变。
- 按需重开支付页:仅当用户说支付页关了/丢了、或稍后回来要继续支付待支付单时,从GET /p/shop/status取pending[].page_url重新交付——交付纪律同上(首选主动打开:作为 http/https URL 交给宿主的内置浏览器预览能力渲染支付页,WorkBuddy 中即调用present_files,传 URL 字符串,面板会直接打开支付页;仍是该轮最后一个工具调用,随后补一行文本链接便于复制)。
- 页面自含:本服务周期翻页(月/季/年三页,每页 3 个配额档)实时价、按当前状态的可购性与补差价/折算价、试用卡、待支付订单(去支付/撤单重选)与常见问题——不需要你在对话里复述任何价格或档位;只想问价格 →curl -s https://t-api.yes-tek.com/v1/billing/plans(免 Bearer 公共目录)。
- 不要把page_url发给短链或任何第三方服务——它携带选购会话 token,只给本人;token 只覆盖选购/下单/撤单,与账号密钥完全隔离,直接贴在对话里是安全的。 - 交付 page_url 的当轮立即启动后台轮询(不等用户回报"已支付";以 run_in_background 托管后台任务运行,paid / 超时退出时自动收到通知):
python3 <skill目录>/scripts/poll_paid.py --token ct_... --timeout 1800
# 退出码 0 = paid(stdout 末行 PAID {订单});2 = 超时仍未支付;1 = 查询异常
- paid → 无需任何交互自动续跑:开通场景自动续跑 Step 2 → 3 → 4 → 5 并一次性汇报;扩容/升档场景直接汇报新配额与到期时间。
- 超时仍在 pending → 汇报等待状态;用户回来要继续支付时按上方「按需重开支付页」交付。
- 用户可能反复改选,以最终 paid 为准(也可用
GET /v1/billing/orders/{out_trade_no}查单笔)。
- 计费语义(用户问起时如实说明——页面已同屏展示):
- 同档再买 = 续费顺延(囤时长用这个,无损失)
- 同周期买更大配额档 = 补差价、到期日不变(pricing.kind: "upgrade_quota")
- 买更长周期档 = 全价 − 剩余时长折算抵扣(pricing.credit_cents)、到期日 = 原到期日 + 新周期
- 只升不降:配额或周期任一降档 → 400plan_downgrade(页面上该档已置灰)
- 报价下单时冻结:同服务有未支付订单时换档会复用该冻结单——用户可在页面上直接「撤单重选」(POST /p/shop/order/{no}/cancel,撤后立即可重选;已支付则 409 走退款)
- 试用转付费:即时生效全价、剩余试用作废——临近试用结束再买更划算
日常运维操作
| 需求 | 做法 |
|---|---|
| 看状态与用量 | GET /v1/my/sites(含 plan.tunnel、used/max、expires_at) |
| 加隧道 | Step 2 → 被访问端重跑 Step 3 部署脚本(幂等更新配置并重启) |
| 删隧道 | DELETE /v1/sites/{name}——进入 7 天冷却,期内可重建恢复,期满释放;删除前必须向用户确认 |
| 续费 | 到期前会收到 agentMail 提醒;同档再下单即顺延 |
| 轮换站点密钥 sk | POST /v1/my/sites/{name}/secret-key:rotate(响应含新双端配置)→ 两端重新部署 |
| 轮换账号密钥 | POST /v1/my/token:rotate → 更新凭证文件与所有 frpc |
| 主 key 丢失 | POST /v1/my/token:recover,凭 recovery_key |
| 换绑定邮箱 | PUT /v1/my/agent-mail(需当前 key;换邮即重置验证,重新验证前下单 403) |
意见与摩擦反馈
用户在任意时刻提出意见、建议或使用摩擦(报错、卡步、指引不清)→ 用免登录反馈通道代发:
curl -s -X POST https://t-api.yes-tek.com/v1/feedback \
-H "Content-Type: application/json" \
-d '{"email": "alice@example.com", "content": "……", "skill": "tcp-tunnel"}'
# 200 {"status":"received"}
email默认取当前账号邮箱(凭证中的注册邮箱;未开通时取 Agent Mail 主别名),无需再问用户content≤100 字,只写现象与建议;不写进 content:任何密钥、密码、支付链接里的 token——含ut_/rk_/sk_/ot_/ct_开头串会被服务端拒绝(400sensitive_content,去除后重发即可)- 其余 400 按提示修正后重发(未落库,重试安全);429 稍后再试
- 发出后回用户一句「已反馈,如有需要平台会用这个邮箱联系你」;不引导用户去其他渠道
错误码处置表
业务错误统一为 {"code", "message", "retryable"}:
| code | HTTP | 处置 |
|---|---|---|
unauthorized |
401 | key 失效/被吊销 → 走 recover;recovery_key 也丢 → 联系平台管理员 |
subdomain_taken / mail_taken |
409 | 换名/换邮箱重试(先问用户) |
agent_mail_unverified |
403 | 邮箱未验证(换邮后/存量账号):/v1/mail/verify:resend → 读信 → verify |
trial_already_used |
400 | 该服务低价试用已用过(每项服务各一次)→ 引导买正式档 |
plan_downgrade |
400 | 只升不降:配额/周期降档被拒——囤时长用同档续费;确实要降档联系平台 |
verify_code_invalid / verify_code_expired / verify_attempts_exhausted |
400 | 验证码错/过期/试错 5 次 → 重发后重试 |
agent_mail_required |
400 | 免 Bearer 下单/mint 选购会话必须带 agent_mail |
quota_exceeded |
403 | 端口配额已满:引导付费/换档/删旧隧道,勿重试 |
reserved_name / invalid_name |
400 | 换名 |
rate_limited |
429 | 指数退避重试(≥2s 起) |
channel_unavailable |
400 | 换支付渠道 |
internal / 5xx / 网络错误 |
500 | 指数退避重试,3 次后报告用户 |
| — | 404 | 资源不存在——检查 name 拼写 |
请求纪律:超时 10s;GET / PUT 幂等可自动重试;下单/选购会话由服务端幂等化(同服务复用 pending 冻结单、同账号 24h 复用活选购会话),可安全重试;mail/verify 失败按错误码处置,勿盲目连发(试错只有 5 次)。
排障决策树(隧道不通时按序执行;证据纪律见「用户沟通规范」——证据自己看,给用户结论 + 一句佐证)
GET /healthz非 200 → 平台故障,告知用户稍后再试。GET /v1/my/sites里没有该隧道 → 未创建或已被删除(7 天冷却期内可重建)。online: false→ 被访问端 frpc 未运行或登录失败:
- 服务状态:systemctl status yes-tek-frpc(Linux)/brew services info frpc、launchctl list | grep yes-tek(macOS)/sc query YesTekFrpc(Windows)+ 对应服务日志尾部 50 行;
- 日志正常但进程消失 = 未注册服务而用 nohup/一次性 shell 跑(会被环境清理)→ 重跑 Step 3 部署脚本注册为系统服务;
- 日志报login failed→ 凭证过期(rotate 后没更新配置)→ 重跑 Step 3 部署脚本;
- 日志报代理注册错误(bad secret key)→ sk 已轮换但配置未同步 → 两端重拉配置重装;
- Windows 上服务起不来 / 报安全软件拦截(曾见 WinError 786)→ 程序已统一安装为yestek_frpc.exe;重跑 Step 3 部署脚本幂等校正服务指向,仍被拦截则引导用户把%USERPROFILE%\.config\yes-tek\bin\yestek_frpc.exe加入安全软件信任列表后重启服务。status: "suspended"→ 试用/套餐到期(7 天冷却期内),引导续费;续费成功后隧道自动恢复,无需重建。online: true但连不通:
- 访问端 frpc 没跑 / visitor 未部署 → 查访问端服务状态(服务名带-visitor后缀)后重跑 Step 4 部署脚本;
- 访问端<bindPort>被占用 → 换机器或释放端口;
- 被访问端本地服务没起、local_port填错 →PUT修正后重跑 Step 3 部署脚本。- 以上都不是 → 收集
/v1/my/sites完整响应与两端 frpc 日志尾部 50 行,让用户联系平台支持渠道,不要继续猜测。
API 参考
完整端点、请求/响应字段与示例见本 skill 目录的 references/api.md——构造任何请求前先查它,字段以它为准(与平台 /v1/openapi.json 一致)。(单文件装载时,先取「平台模型」的完整包补全目录)