# Edgeone Pages Deploy Cn

> 用 edgeone CLI 把 Next.js（或任意前端框架）项目部署到腾讯云 EdgeOne Pages，并做国内可访问的免备案配置。适用于「要部署到 EdgeOne」「国内打不开 edgeone.dev 链接报 401」「要绑自定义域名但没备案」等场景。

- Skill: `paloma333/edgeone-pages-deploy-cn` (Agent Skill)
- Install (CLI): `npx skillmds@latest add paloma333/edgeone-pages-deploy-cn`
- Raw SKILL.md: https://api.skillmd.com/api/skills/paloma333/edgeone-pages-deploy-cn/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: Paloma333 (https://skillmd.com/u/paloma333)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/paloma333/edgeone-pages-deploy-cn

---


# EdgeOne Pages 部署（国内免备案）

## 核心认知（先确认，别走弯路）

### 1. 加速区域决定一切
CLI `-a/--area` 只有两个取值，语义**容易搞反**：

| 取值 | 含义 | 绑自定义域名 | 预设域名（项目/部署域名） |
|---|---|---|---|
| `global`（默认） | 全球可用区（**含**中国大陆） | **需 ICP 备案** | 国内访问必须带 **3 小时**有效的 `eo_token`/`eo_time`，超时 401 |
| `overseas` | 全球可用区（**不含**中国大陆） | **免备案** ✅ | 国内网络访问返回 401（非国内可直连） |

**结论**：没备案 + 要给国内用户用 → 必须 `-a overseas`。
而且**两种区域的预设域名都不可靠**，唯一稳定通道是**绑定自定义域名**。

### 2. 预设域名（`*.edgeone.dev`）的 401 是设计使然，不是 bug
- 「含中国大陆」区域：预览链接仅 3 小时有效；且**成功部署记录超过 3 条时旧部署会失效**返回 401；
  控制台「项目概览」右上角「预览」按钮可刷新链接。
- 所以「重新部署拿新链接」只能撑 3 小时，属治标。别在这条路上反复试。

### 3. 中国站 vs 国际站是两套账号体系
- 中国站 API base：`https://pages-api.cloud.tencent.com/v1`
- 国际站 API base：`https://pages-api.edgeone.ai/v1`
- Token 绑定站点。用错 base 会返回 `Code 109 The Token usage region is incorrect`。
- `edgeone login -t <token>` 的输出里 `Site:` 字段会告诉你这个 token 属于哪一站（传 `-s global` 也不一定改得动，以输出为准）。

### 4. CLI 能力边界（实测）
**支持**：`login` / `whoami` / `makers link` / `makers env set|ls|pull|rm` / `makers deploy`
**不支持绑域名**——CLI 无任何 domain 子命令，pages-api 也没有对应 Action
（`CreatePagesDomain`/`BindPagesDomain`/`DescribePagesDomains` 等全部返回 `107 Action has not found`）。
→ **自定义域名只能在控制台加：**
`https://console.cloud.tencent.com/edgeone/pages/project/<ProjectId>` → 域名管理 → 添加自定义域名

已知可用的 pages-api Action（全走 `POST <base>` + `Authorization: Bearer <token>`）：
`DescribePagesProjects` / `CreatePagesProject` / `DeletePagesProject` / `CreatePagesDeployment` /
`DescribePagesDeployments` / `DescribePagesProjectEnvs` / `DescribePagesCosTempToken` / `DescribePagesEncipherToken`

### 5. 框架支持
CLI 内置 `@edgeone/framework-detect`，框架表含：
`Next`（matchPackage "next" → OutputDir `.next`）、`Next SSG`（`output:'export'` → `out`）、
Nuxt / Astro / Remix / Gatsby / Vite / Vue / React / Svelte / Angular / Hono / Hexo / Eleventy / Docusaurus / VitePress / Qwik。
**Next.js 全栈（SSR + API Routes + middleware）可直接部署**，项目里不需要任何 EdgeOne 适配器或配置文件。

---

## 标准流程

### Step 0 · 安装 CLI（隔离目录，别污染项目）
项目 node_modules 常有残留导致 `ENOTEMPTY`，`--prefix` 锁死安装位置最稳：
```bash
mkdir -p ~/.workbuddy/binaries/node/eo-cli
cd ~/.workbuddy/binaries/node/eo-cli && echo '{"name":"eo-cli","private":true}' > package.json
npm install edgeone@latest --prefix ~/.workbuddy/binaries/node/eo-cli --no-audit --no-fund
export PATH="$HOME/.workbuddy/binaries/node/eo-cli/node_modules/.bin:$PATH"
```

### Step 1 · 登录并确认站点
```bash
echo '<TOKEN>' > /tmp/eo_token.txt
edgeone login -t "$(cat /tmp/eo_token.txt)"     # 看输出的 Site: china / global
edgeone whoami
```

### Step 2 · 创建项目（**必须显式指定 area**）
`edgeone makers link -n <name>` 会自动建项目，但它**硬编码 `Area:"global"`**——想要免备案就别用它建。
改用 API 建：
```bash
curl -s -X POST "https://pages-api.cloud.tencent.com/v1" \
  -H "Content-Type: application/json" -H "Authorization: Bearer $(cat /tmp/eo_token.txt)" \
  -d '{"Action":"CreatePagesProject","Name":"<name>","Provider":"Upload","Channel":"Custom","Area":"overseas","Source":"cli","Region":"ap-guangzhou"}'
# → {"Code":0,"Data":{"Response":{"ProjectId":"makers-xxxx"}}}  记下 ProjectId
```

### Step 3 · 关联本地目录
```bash
cd <project-root> && edgeone makers link -n <name> -t "$(cat /tmp/eo_token.txt)"
# 生成 .edgeone/project.json（记得确认 .gitignore 含 .edgeone/*）
```

### Step 4 · 注入环境变量（**必须在 deploy 之前**）
`NEXT_PUBLIC_*` 是构建期内联的，漏设就得重新构建。Server 端 key 也要在这里设。
```bash
edgeone makers env set NEXT_PUBLIC_SUPABASE_URL "https://xxx.supabase.co" -e production -t "$(cat /tmp/eo_token.txt)"
# 依次设置其余变量（NEXT_PUBLIC_SUPABASE_ANON_KEY / SUPABASE_SERVICE_ROLE_KEY / DASHSCOPE_API_KEY ...）
edgeone makers env ls -e production
```

### Step 5 · 清理构建产物再部署
**坑**：CLI 打包目录时只排除 `node_modules` / `.cache` / `.git` / `.DS_Store` / `*.log` / `*.tmp`，
**不排除 `.next` / `.next-v*`**。历史残留构建目录会让上传体积爆炸（实测 16 个目录 170M+）。
```bash
mkdir -p /tmp/next-backup && for d in .next .next-*; do [ -e "$d" ] && mv "$d" /tmp/next-backup/; done
```
（`.env.local` 也会被上传。若不想上传，部署前临时挪走，部署后记得移回来。）

```bash
edgeone makers deploy . -n <name> -a overseas -e production --json
# 约 3~5 分钟；成功后输出 url / projectId / deploymentId / consoleUrl
```

### Step 6 · 验证
```bash
# 带 token 的预览链接
curl -sL -o /dev/null -w "%{http_code} %{url_effective}\n" "<deploy-url>"
# 健康表现：307 → /login → 200；服务端标识 Server: edgeone makers
curl -sI "<deploy-url>" | grep -i server
```

### Step 7 · 绑自定义域名（**用户手动，无法脚本化**）
1. 打开 `https://console.cloud.tencent.com/edgeone/pages/project/<ProjectId>`
2. **域名管理 → 添加自定义域名**，填域名
3. 确认加速区域是「全球可用区(不含中国大陆)」（免备案）
4. **归属权验证**（TXT）：控制台弹出「请验证域名 X 归属权」，给出
   - 解析内容（主机记录）：`edgeonereclaim`
   - 记录类型：`TXT`
   - 记录值：`reclaim-<随机串>`
   去域名解析服务商加这条 TXT，等 5~10 分钟再点「验证」。
   ⚠️ **主机记录只填 `edgeonereclaim`**，不要连域名后缀一起填（否则变成
   `edgeonereclaim.example.com.example.com`，永远验证不过）。
   ⚠️ **记录值不要加引号**，原样粘贴。
5. 通过后再加 CNAME（本步骤和上一步是两件事：先证归属，再指向 EdgeOne）。
   若域名已托管在腾讯云 DNSPod，可选 **DNSPod 托管接入**一键完成（无需归属权校验）
6. 验证：`dig @8.8.8.8 <domain> +short` 看 CNAME；`curl -sI https://<domain>` 看是否 200

### Step 8 · 配 SSL 证书（**绑完域名必做，否则 HTTPS 用不了**）
控制台域名列表里「证书」列显示 **`未配置`** 时，HTTPS 是不通的。此时：
- `curl https://<domain>` 返回 **HTTP 000**（curl 因证书域名不匹配直接中断）
- 握手拿到的是腾讯云兜底证书：`CN=*.cdn.myqcloud.com`（不是你的域名，说明没配证书）
- 但 `curl http://<domain>` 正常（HTTP 能用，HTTPS 不能用）

→ 点域名行的 **`配置`** 按钮 → 选**免费证书**（腾讯云免费 DV，EdgeOne 自动申请+部署）
→ 等签发（一般几分钟，走自动验证）→ 状态变「已配置」后 HTTPS 才可用。

自查命令（不用等用户截图）：
```bash
echo | openssl s_client -connect <domain>:443 -servername <domain> 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates
# subject 是你的域名  → 正常
# subject=CN=*.cdn.myqcloud.com → 证书没配，回控制台点「配置」
```

> ✅ **实测结论（2026-09 已跑通）**：EdgeOne Pages（海外区）+ 自定义域名 + 免费证书，
> 经**国内网络实测确认可正常访问**，免备案成立。
> 关键认知：**预设域名对大陆返回 401 是设计使然，绑自定义域名才是官方指定的正解**——
> 别在「重新部署换新预览链接」上浪费时间（只能撑 3 小时）。
> 验证大陆可达性时注意：check-host.net **没有大陆节点**（只有境外），
> 站长工具/itdog 是 JS 渲染或 403，脚本抓不到；**最可靠的是让国内的人打开一次**。

**别让用户反复点「验证失败」**——自己在外部查一次更快：
```bash
dig @8.8.8.8 TXT edgeonereclaim.<domain> +short     # 有值=已生效，空=记录没加上/没传播
dig @8.8.8.8 NS <domain> +short                      # 确认 NS 委派正常
dig @8.8.8.8 <domain> +noall +answer +authority      # 只回 SOA = zone 存在但无该记录
```
权威 NS 能返回 zone 的 SOA、却不返回该 TXT → **记录确实没建**（不是缓存/传播问题）。
排查填错形态时可顺手试 `edgeonereclaim.<domain>` / `<domain>` / `www.<domain>` 几种。
另：用 `whois <domain> | grep -i status` 确认域名不是 `serverHold`（实名审核未过会导致整域不解
析，那是另一类问题）。

---

## 疑难排查

| 现象 | 原因 | 处理 |
|---|---|---|
| `Code 109 The Token usage region is incorrect` | Token 站点与 API base 不匹配 | 换 base：中国站 `.cloud.tencent.com`，国际站 `.edgeone.ai` |
| `Code 107 Action has not found` | 该 Action 不存在 | 别猜了，见上面「已知可用 Action」列表 |
| 域名预览链接国内 401 | 区域含中国大陆 + 3h 预览链接过期 | 治本方案是绑自定义域名；或去控制台点「预览」刷新 |
| `link -n X` 输出 `Creating new project...` | 该账号里**没有** X 项目 | 说明源部署在别的账号/是 `--anonymous` 孤儿部署，无法接管 |
| 控制台加域名一直「验证失败，请稍后重试」 | 归属权 TXT 记录没真正加上（最常见：主机记录多带了域名后缀） | 先 `dig @8.8.8.8 TXT edgeonereclaim.<domain> +short` 自查，别反复点验证 |
| `ENOTEMPTY` 装 CLI 失败 | 上层目录（如 `~/node_modules`）有残留 | 用 `--prefix` 锁目录；清 `~/node_modules/.*-[0-9a-zA-Z]*` |
| `npm search` 无输出 / SIGKILL | 沙箱/网络限制 | 换 WebSearch 查官方文档，或直接读 `node_modules/edgeone/edgeone-dist/cli.js` 逆向 |

## 逆向 CLI 的技巧（省时间）
`cli.js` 是单行压缩产物，用 node 定位比 grep 好用：
```bash
node -e "
const s=require('fs').readFileSync('cli.js','utf8');
const i=s.indexOf('关键词');
console.log(s.slice(Math.max(0,i-400), i+800).replace(/\n/g,' ⏎ '));
"
# 列出所有 API Action：
node -e "
const s=require('fs').readFileSync('cli.js','utf8');
console.log([...new Set([...s.matchAll(/action:\"([A-Za-z]+)\"/g)].map(m=>m[1]))].sort().join('\n'))
"
```

