13 KiB
EdgeSSH 部署与验收
先确定入口并选择一种登录方式
本项目只有一个管理员、一份主机资料库。AUTH_PROVIDER 决定唯一生效的认证方式,不同时维护两套登录状态。两种方式都部署到 Cloudflare Workers,但 GitHub 模式不需要 Zero Trust 或 Access 权限。
多数用户建议先准备自定义域名,例如 ssh.example.com。在 GitHub 设置(Settings)> 机密和变量(Secrets and variables)> Actions 配置:
| 名称 | 类型 | Cloudflare 模式 | GitHub 模式 |
|---|---|---|---|
AUTH_PROVIDER |
Variable | cloudflare(默认) |
github |
CLOUDFLARE_API_TOKEN |
Secret | 必填 | 必填 |
CUSTOM_DOMAIN |
Variable | 推荐填写实际主机名 | 推荐填写实际主机名 |
ADMIN_EMAIL |
Variable | 管理员邮箱 | 不需要 |
GITHUB_CLIENT_ID |
Variable | 不需要 | OAuth App 的 Client ID |
GITHUB_CLIENT_SECRET |
Secret | 不需要 | OAuth App 的 Client Secret |
GITHUB_ADMIN |
Variable | 不需要 | 允许登录的唯一 GitHub 用户名,不是邮箱或组织名 |
CUSTOM_DOMAIN 只填完整主机名,不带 https://、路径或通配符。域名必须由部署账户的 Cloudflare Zone 管理;Action 会自动绑定 Worker,Cloudflare 负责 DNS 与证书。需要使用免费 workers.dev 地址时将它留空,不能填写 *.workers.dev。
敏感值不要放 Variable。工作流只校验所选方式的配置,另一种方式的旧配置不会参与认证。
Cloudflare 模式准备
- 在 Cloudflare 启用 Zero Trust,完成团队域名与计划初始化。组织开通涉及账户确认,不由脚本代办。
- Fork 本仓库,启用 GitHub Actions,在 设置(Settings)> 机密和变量(Secrets and variables)> Actions 保存
CLOUDFLARE_API_TOKENSecret,并按上表保存CUSTOM_DOMAIN与AUTH_PROVIDERVariable。 - 在 Actions > Deploy > 运行工作流(Run workflow) 输入管理员邮箱,运行并等待摘要给出访问地址。可将邮箱保存为
ADMIN_EMAILVariable,省去重复输入。
无需手动创建 Access 应用、OTP、D1,也无需抄录 Account ID、Team Domain 或 AUD。填写 CUSTOM_DOMAIN 时使用自定义域名;留空才使用 https://edgessh.<账户子域>.workers.dev。
GitHub 模式准备
- 打开 GitHub 设置(Settings)> 开发者设置(Developer settings)> OAuth 应用(OAuth Apps)> 新建 OAuth 应用(New OAuth App)。
- **应用名称(Application name)**自定;**主页 URL(Homepage URL)**填 EdgeSSH 地址,**授权回调 URL(Authorization callback URL)**填
https://你的入口/auth/callback。 - 保存 Client ID,生成一个 Client Secret,按上表分别保存到 Actions Variable 和 Secret。
- 设置
AUTH_PROVIDER=github、CUSTOM_DOMAIN=你的主机名、GITHUB_ADMIN=你的GitHub用户名,保存 Cloudflare API Token,然后运行 Actions > Deploy。使用workers.dev时才省略CUSTOM_DOMAIN;邮箱输入框留空。 - 若首次部署前不知道入口,可先为 OAuth App 使用占位 URL;部署后将 Action 摘要中的正式入口与回调地址复制回 OAuth App 设置,再登录。
GitHub OAuth App 必须由用户在 GitHub 创建;普通 GitHub Token 没有官方“创建 OAuth App”的 REST 接口,工作流不会假装自动完成它。
登录时仅读取 GitHub 公开身份,不申请仓库、组织或私人邮箱权限。Action 将用户名解析为数字用户 ID,Worker 只给这个 ID 签发会话。管理员更改 GitHub 用户名后,应同步更新 GITHUB_ADMIN。
API Token 权限
在 Cloudflare 我的个人资料(My Profile)> API 令牌(API Tokens)> 创建令牌(Create Token),以 编辑 Cloudflare Workers(Edit Cloudflare Workers) 模板为起点,保留部署所需权限,并补齐以下账户权限。Cloudflare 中文界面可能仍显示部分英文;下表同时保留英文原名。控制台的编辑(Edit)/读取(Read)对应 API 文档的 Write/Read。
| 账户(Account)权限 | 级别 | 用途 |
|---|---|---|
| Workers 脚本(Workers Scripts) | 编辑(Edit) | Worker、Durable Object、Secret 和子域部署 |
| Workers KV 存储(Workers KV Storage) | 编辑(Edit) | 保留官方 Workers 模板的部署权限 |
| 账户设置(Account Settings) | 读取(Read) | 自动发现账户 |
| D1 | 编辑(Edit) | 查找/创建数据库、检查旧数据与执行迁移 |
| Access:应用和策略(Apps and Policies) | 编辑(Edit) | 仅 cloudflare 模式:查找/创建应用及邮箱策略 |
| Access:组织、身份提供程序和组(Organizations, Identity Providers, and Groups) | 编辑(Edit) | 仅 cloudflare 模式:获取团队域名、查找/创建 OTP |
账户资源只选择实际部署账户。若 Token 可访问多个账户,设置 Actions Variable CLOUDFLARE_ACCOUNT_ID,脚本不会猜测目标账户。
只用 workers.dev 不需要自定义域名的区域权限。使用 CUSTOM_DOMAIN 时,还需模板的 区域(Zone)> Workers 路由(Workers Routes):编辑(Edit)、区域(Zone):读取(Read),并将区域资源范围限定到该域名所在 Zone。域名必须已经由同账户的 Cloudflare 管理。
API Token 只存 GitHub Secret,不放普通变量、代码或命令行输入框。不要将 Token 填到 Run workflow 的邮箱字段。
自动执行顺序
- 校验本地配置,运行类型检查、测试、前端构建和 Wrangler dry-run。
- 自动发现唯一账户(显式账户 ID 优先),读取现有 Worker Secret 名称,不尝试读取密钥明文。
- 有
CUSTOM_DOMAIN时使用该入口;否则读取账户workers.dev子域,未注册时自动注册确定性名称。已有子域不改名,避免影响其他 Worker。 - 根据
AUTH_PROVIDER仅准备所选认证:Cloudflare 配置 Access/OTP/Allow,GitHub 验证指定管理员并准备 OAuth Secret。 - GitHub 模式不调用 Zero Trust API;Cloudflare 模式不需要 GitHub OAuth 参数。既有 Access 应用不重写人工 IdP 配置。
- 按 ID 或名称复用 D1,不存在才创建;指定 ID 不存在时直接失败,不用新空库替代。
- 已有
ENCRYPTION_KEY则保留;没有密钥且 D1 没有主机资料时,用安全随机数生成 32 字节密钥。 - 执行远程 migration,仅应用增量 schema,不清空数据。
- 自动沿用旧库唯一资料所有者 ID,新库使用固定
admin。新增 Secret 通过标准输入交给 Wrangler;部署后核对当前模式必需的 Secret,并输出入口和 GitHub 回调地址。
生产任务通过 concurrency 串行运行,失败可修正原因后重跑,已创建的资源会复用。请勿用多个仓库同时管理同一个 Worker。
设置自定义域名时关闭备用 workers.dev 入口,所有部署关闭 preview URL。Cloudflare 模式校验 Access JWT;GitHub 模式使用 state、PKCE 和签名 HttpOnly Cookie。缺少认证不降级为匿名 SSH。
其他可选配置
| 名称 | GitHub 位置 | 默认/示例 |
|---|---|---|
ADMIN_EMAIL |
Variable,兼容 Secret | you@example.com;Run workflow 输入优先 |
CLOUDFLARE_ACCOUNT_ID |
Variable,兼容 Secret | 仅多账户 Token 需要指定 |
WORKER_NAME |
Variable | edgessh |
D1_DATABASE_NAME |
Variable | <Worker 名>-accounts |
D1_DATABASE_ID |
Variable | 指定已有 D1 UUID,不填则按名称查找 |
ACCESS_IDP_IDS |
Variable | 新应用采用的 IdP UUID,多个用逗号分隔 |
ENCRYPTION_KEY |
Secret,仅恢复/迁移使用 | 仅 Worker 尚无密钥时使用;已有密钥不会覆盖 |
DB、SSH_SESSIONS、ASSETS 是资源绑定,不是需要用户创建的变量。CONNECT_TIMEOUT_MS 已有默认值 10000。
密钥生命周期与旧版升级
ENCRYPTION_KEY的持久化来源是 Cloudflare Worker Secrets。Cloudflare 模式自动取得并保存 Team Domain/AUD;GitHub Client Secret 由 GitHub Actions Secret 同步到 Worker。不要保存为 Variable 或明文配置。- 新部署不需要 GitHub 写 Secrets 权限或额外 GitHub Token。生成的值不写入文件、命令行参数或 Actions artifact。
- 重跑、推送新代码时保留原加密密钥。GitHub 中遗留的同名密钥不会替换 Worker 中的密钥。
- 已有 D1 主机资料但缺少密钥时停止部署。 必须恢复原密钥,不能生成新密钥假装修复。Cloudflare API 不提供 Secret 明文读回,自动生成的密钥也不会显示给用户;不要删除 Worker/Secret。需要独立灾备时,可在首次部署前自行生成并安全备份 32 字节 Base64 密钥,再保存为
ENCRYPTION_KEYGitHub Secret。 - 旧部署已有三个 Worker Secrets 时,无需重新输入邮箱即可部署,也不要求复制 Secret 回 GitHub;脚本保留既有 Access 配置。这兼容人工管理的 Zone 级 Access 应用。
- 若需要自动创建/管理 Access,或更换 hostname,请提供
ADMIN_EMAIL。自动管理使用账户级 Access API;原有 Zone 级应用请先核对,不要在同一 hostname 叠加应用。 - 切换认证方式不改变
ENCRYPTION_KEY、D1 和管理员资料所有者。不要通过更换密钥来切换登录方式。
切换登录方式,保留同一管理员资料
- 修改
AUTH_PROVIDER,补齐目标方式的配置,然后运行 Deploy。 - 保持 Worker、D1 和加密密钥不变。部署只读检查旧库唯一所有者并沿用其 ID,不搬迁、不重加密资料。
- 新库统一使用
admin。若旧库实际有多个资料所有者,脚本停止,不会猜测或合并原本隔离的数据。 - 从 Cloudflare 改 GitHub 时,先解除入口域名原有的 Access 网关保护,否则浏览器仍会先看到 Access。脚本发现这种情况会停止,不自动删除安全策略。仅解除登录网关,不要删除 Worker、D1 或 Secret。
- 反向切换时,Action 配置 Access,GitHub Cookie 不再被接受。旧 provider 的 Secret 即使暂时保留,也不是有效登录状态。
GitHub 会话使用 Secure、HttpOnly、SameSite=Lax Cookie,有效期 8 小时;退出清除本浏览器 Cookie,不注销 GitHub 网站账号。会话签名通过 HKDF 从原加密密钥派生独立用途的密钥,无需用户再管理 SESSION_SECRET。无需新增用户表或账号绑定流程。
Cloudflare 模式仍可用 ACCESS_IDP_IDS 为新 Access 应用选择现成 IdP;这属于 Access 模式,不是原生 AUTH_PROVIDER=github。
排障
- 403:检查 Token 权限及账户/Zone 范围,不是重新生成加密密钥。
- 找不到唯一账户:限定 Token 到一个账户,或配置
CLOUDFLARE_ACCOUNT_ID。 - 组织读取失败:先完成 Zero Trust 开通和团队域设置。
- 首次部署缺少邮箱:在 Run workflow 输入,或设置
ADMIN_EMAIL。 - 既有策略被人工修改:脚本不会覆盖额外 require/exclude 等条件;在控制台维护,或改名后重跑。
- 更换域名后无法登录:带邮箱重新运行以配置新 hostname 的应用;不要仅改路由而沿用旧 AUD。
- OTP 未收到:确认输入邮箱完全匹配 Allow 策略,检查垃圾邮件。GitHub 等其他 IdP 的账户邮箱同样必须匹配授权。
- GitHub 回调失败:检查 OAuth App 回调地址是否精确为
https://实际入口/auth/callback,Client ID/Secret 是否来自同一 OAuth App;重新从首页登录,不复用旧回调链接。 - GitHub 拒绝管理员:
GITHUB_ADMIN应填个人用户名,不是邮箱或组织;用该账号重新授权。 - 手工配置、截图与 Access JWT 排查见 Zero Trust 指南。
验收清单
npm run check:类型检查、测试、前端构建与部署 dry-run。- 空账户 bootstrap 与重复部署:只创建一次应用/OTP/D1,密钥不轮换,不覆盖 GitHub IdP。
- Cloudflare 模式未登录跳 Access;GitHub 模式点击首页「登录」前往 GitHub,未授权账号不可进入。
- 登录后
/api/auth/me与主机列表可用;无 JWT、伪造/过期 JWT 不可访问主机、票据或 WebSocket。 - 加密资料跨部署保持可解密;测试不得清空生产 D1。
- 真实 SSH、SFTP 与进程面板必须使用已获授权目标;未提供目标和登录会话时不声称验收完成。
- 文件管理浏览器回归:
npx playwright install chromium后运行npm run test:browser,覆盖桌面/375px 手机的入口、目录导航、上传/下载字节、新建/重命名/删除、主机切换、指纹确认与传输期间导航。测试只模拟 API 和 WebSocket,不替代真实服务器验收。 - 线上登录后,从左侧「文件管理」选择授权主机,在专用临时目录验证上传、下载、新建、重命名与删除空目录,再切换到终端确认同一会话仍可用。不得用既有生产文件验证删除或覆盖。