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 锁死安装位置最稳:
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 · 登录并确认站点
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 建:
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 · 关联本地目录
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 也要在这里设。
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+)。
mkdir -p /tmp/next-backup && for d in .next .next-*; do [ -e "$d" ] && mv "$d" /tmp/next-backup/; done
(.env.local 也会被上传。若不想上传,部署前临时挪走,部署后记得移回来。)
edgeone makers deploy . -n <name> -a overseas -e production --json
# 约 3~5 分钟;成功后输出 url / projectId / deploymentId / consoleUrl
Step 6 · 验证
# 带 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 · 绑自定义域名(用户手动,无法脚本化)
- 打开
https://console.cloud.tencent.com/edgeone/pages/project/<ProjectId> - 域名管理 → 添加自定义域名,填域名
- 确认加速区域是「全球可用区(不含中国大陆)」(免备案)
- 归属权验证(TXT):控制台弹出「请验证域名 X 归属权」,给出
- 解析内容(主机记录):
edgeonereclaim - 记录类型:
TXT - 记录值:
reclaim-<随机串>去域名解析服务商加这条 TXT,等 5~10 分钟再点「验证」。 ⚠️ 主机记录只填edgeonereclaim,不要连域名后缀一起填(否则变成edgeonereclaim.example.com.example.com,永远验证不过)。 ⚠️ 记录值不要加引号,原样粘贴。
- 解析内容(主机记录):
- 通过后再加 CNAME(本步骤和上一步是两件事:先证归属,再指向 EdgeOne)。 若域名已托管在腾讯云 DNSPod,可选 DNSPod 托管接入一键完成(无需归属权校验)
- 验证:
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 才可用。
自查命令(不用等用户截图):
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,脚本抓不到;最可靠的是让国内的人打开一次。
别让用户反复点「验证失败」——自己在外部查一次更快:
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 好用:
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'))
"