Expand deployment and usage documentation

This commit is contained in:
zeer
2026-07-12 17:13:38 +08:00
parent c78c7eb00b
commit 5eaa7dcc94
2 changed files with 461 additions and 78 deletions

View File

@@ -1,63 +1,88 @@
# EdgeOne Pages 部署说明 # EdgeOne Pages 部署说明
这个项目已经包含 EdgeOne Pages 版本: 这是 STUN Nav 的 EdgeOne Pages 专用部署说明。完整使用文档见 `README.md`。
- 静态页面:`public/` ## 文件结构
- Edge Functions:`edge-functions/api/[[default]].js`
- EdgeOne 配置:`edgeone.json`
## 需要在 EdgeOne 配置的内容 ```text
public/ # 静态页面
edge-functions/api/[[default]].js # /api/* 接口
edgeone.json # EdgeOne 配置
```
1. 创建一个 EdgeOne Pages / Makers 项目,并导入这个仓库。 ## 部署步骤
2. 创建并绑定 KV Namespace。
3. 绑定 KV 时,变量名填写: 1. 在 EdgeOne Pages / Makers 中创建项目。
2. 导入 GitHub 仓库。
3. 确认构建输出目录为:
```text
public
```
4. 创建 KV Namespace。
5. 给项目绑定 KV,变量名填写:
```text ```text
STUN_NAV_KV STUN_NAV_KV
``` ```
4. 配置环境变量: 6. 添加环境变量:
```text ```text
WEBHOOK_TOKEN=换成你自己的随机密钥 WEBHOOK_TOKEN=换成你自己的随机密钥
``` ```
5. 部署后访问: 7. 部署项目。
## 访问地址
```text ```text
https://你的域名/ https://你的域名/
https://你的域名/admin https://你的域名/admin
``` ```
## Lucky Webhook 示例 ## Lucky Webhook
简单 URL 参数方式: GET 参数方式:
```text ```text
https://你的域名/api/webhook/alist?token=你的随机密钥&name=AList&group=文件&url=http://{STUN_你的STUN规则名_ADDR} https://你的域名/api/webhook/fnnas?token=你的随机密钥&name=FNNAS&group=NAS&url=http://{STUN_fnnas_ADDR}
``` ```
JSON 方式: POST JSON 方式:
```text ```text
URL: https://你的域名/api/webhook/alist?token=你的随机密钥 URL: https://你的域名/api/webhook/fnnas?token=你的随机密钥
Method: POST Method: POST
Content-Type: application/json Content-Type: application/json
Body: Body:
{ {
"name": "AList", "name": "FNNAS",
"group": "文件", "group": "NAS",
"url": "http://{STUN_你的STUN规则名_ADDR}", "url": "http://{STUN_fnnas_ADDR}",
"note": "家中文件服务" "note": "家里 NAS"
} }
``` ```
## 数据存储 ## 数据存储
EdgeOne 版本不再使用 `data/links.json`,所有数据会存到 KV 的 `stun_nav_store` 这个 key 里。 EdgeOne 版本的数据保存在 KV 的这个 key 中:
本地 Node 版本仍然保留,可以继续用: ```text
stun_nav_store
```bash
WEBHOOK_TOKEN=你的随机密钥 PORT=8080 npm start
``` ```
不会使用本地的 `data/links.json`。
## 故障排查
如果 `/api/services` 报 KV 错误,优先检查 KV 绑定变量名是不是:
```text
STUN_NAV_KV
```
如果 webhook 返回 `missing service url, addr, or host+port`,说明请求里没有传服务地址,需要增加 `url`、`addr`,或 `host + port`。
如果后台保存失败,检查输入的管理密钥是否和环境变量 `WEBHOOK_TOKEN` 一致。

466
README.md
View File

@@ -1,62 +1,291 @@
# STUN 导航页 # STUN Nav
一个给 Lucky STUN 使用的个人导航页。Lucky 的 STUN 地址变化后,通过 webhook 把最新地址推到这里;浏览器打开导航页时,按钮会跳转到最新地址。 一个给 Lucky STUN 使用的个人导航页。
## 启动 Lucky 的 STUN 外网地址变化后,通过 webhook 把最新地址推送到这个项目;导航页和后台会读取保存的最新地址,点击卡片即可跳转到当前可用入口。
项目支持两种部署方式:
- 本地 / 家中服务器部署:`server.mjs` + `data/links.json`
- EdgeOne Pages 部署:静态页面 + Edge Functions + KV
## 功能
- 自动接收 Lucky webhook,更新导航地址
- 首页按分组展示服务卡片
- 后台 `/admin` 手动新增、编辑、删除导航
- 后台修改页面标题、顶部标识、首页标题、首页副标题
- 支持 GET、POST JSON、表单等多种 webhook 方式
- 支持 EdgeOne Pages 无服务器部署
## 项目结构
```text
.
├── public/ # 前端页面
│ ├── index.html # 首页
│ ├── admin.html # 后台
│ ├── app.js
│ ├── admin.js
│ └── styles.css
├── server.mjs # 本地 Node 服务
├── data/links.json # 本地数据文件,已被 .gitignore 忽略
├── edge-functions/api/[[default]].js # EdgeOne API
├── edgeone.json # EdgeOne Pages 配置
├── EDGEONE.md # EdgeOne 部署说明
└── package.json
```
## 本地部署
适合部署在家中服务器、NAS、VPS、Docker 容器等环境。
### 1. 安装 Node.js
需要 Node.js 18 或更高版本。
检查版本:
```bash ```bash
WEBHOOK_TOKEN=换成一串随机密钥 PORT=8080 npm start node -v
``` ```
然后访问: ### 2. 启动服务
```text ```bash
http://服务器IP:8080 WEBHOOK_TOKEN=换成你自己的随机密钥 PORT=8080 npm start
``` ```
管理页: 参数说明:
| 参数 | 说明 |
| --- | --- |
| `WEBHOOK_TOKEN` | 管理和 webhook 密钥,必须设置成随机字符串 |
| `PORT` | 服务端口,默认 `8080` |
启动后访问:
```text ```text
http://服务器IP:8080/
http://服务器IP:8080/admin http://服务器IP:8080/admin
``` ```
打开管理页后填写 `WEBHOOK_TOKEN`,即可手动新增、修改、删除导航项,也可以修改浏览器标题、顶部标识、首页标题和副标题。密钥只保存在当前浏览器本地。 ### 3. 本地数据保存位置
## 部署到 EdgeOne Pages 本地版本数据保存在:
项目已经包含 EdgeOne Pages 改造版本,见 `EDGEONE.md`。 ```text
data/links.json
```
核心变化: 这个文件包含导航信息和页面设置,默认不会提交到 GitHub。
- 静态页面从 `public/` 部署 ### 4. 反向代理建议
- `/api/*` 由 `edge-functions/api/[[default]].js` 提供
- 数据保存到 EdgeOne KV,绑定变量名需要设置为 `STUN_NAV_KV` 如果你用 Nginx、Caddy、Lucky Web 服务等反向代理,建议:
- 管理密钥使用环境变量 `WEBHOOK_TOKEN`
- 使用 HTTPS
- 不要把后台裸露给陌生人
- `WEBHOOK_TOKEN` 使用足够长的随机字符串
## EdgeOne Pages 部署
适合让导航页本身拥有稳定公网入口,例如:
```text
https://dh.example.com/
https://dh.example.com/admin
```
### 1. 导入仓库
在 EdgeOne Pages / Makers 中创建项目,导入本仓库。
项目已经包含:
```text
edgeone.json
edge-functions/api/[[default]].js
```
`edgeone.json` 会把静态输出目录设置为:
```text
public
```
并把:
```text
/admin
```
重写到:
```text
/admin.html
```
### 2. 创建 KV
创建一个 KV Namespace,并绑定到 Pages 项目。
绑定变量名必须填写:
```text
STUN_NAV_KV
```
EdgeOne 版本会把所有数据保存到 KV 的这个 key:
```text
stun_nav_store
```
### 3. 配置环境变量
在 EdgeOne 项目的环境变量中配置:
```text
WEBHOOK_TOKEN=换成你自己的随机密钥
```
这个密钥用于:
- Lucky webhook 更新导航
- 后台保存页面设置
- 后台新增、编辑、删除导航
### 4. 部署后访问
```text
https://你的域名/
https://你的域名/admin
```
首次打开 `/admin`,填写 `WEBHOOK_TOKEN`,之后密钥只会保存在当前浏览器本地。
## 后台使用
后台地址:
```text
/admin
```
后台包含:
- `页面设置`:修改浏览器标题、顶部标识、首页标题、首页副标题
- `新增导航`:手动新增一个导航入口
- `导航列表`:查看、编辑、删除已有导航
字段说明:
| 字段 | 说明 |
| --- | --- |
| `ID` | 导航唯一标识,例如 `alist`、`fnnas` |
| `名称` | 首页显示名称 |
| `分组` | 首页卡片分组 |
| `地址` | 点击跳转地址 |
| `备注` | 可选说明 |
如果编辑时修改了 `ID`,系统会保存新 ID,并删除旧 ID 对应的记录。
## Lucky Webhook 配置 ## Lucky Webhook 配置
推荐让 Lucky 发送 JSON: Webhook 接口格式:
```text
/api/webhook/:id
```
例如:
```text
/api/webhook/alist
/api/webhook/fnnas
```
其中 `alist`、`fnnas` 就是导航项 ID。
### 方式一:GET URL 参数
这是最简单的方式。
接口地址:
```text
https://你的域名/api/webhook/fnnas?token=你的随机密钥&name=FNNAS&group=NAS&url=http://{STUN_你的STUN规则名_ADDR}
```
请求方法:
```text
GET
```
请求头:
```text
不用填
```
### 方式二:POST JSON
接口地址:
```text
https://你的域名/api/webhook/fnnas?token=你的随机密钥
```
请求方法:
```text
POST
```
请求头:
```text ```text
URL: http://你的导航页地址:8080/api/webhook/alist?token=换成一串随机密钥
Method: POST
Content-Type: application/json Content-Type: application/json
Body: ```
请求体:
```json
{ {
"name": "AList", "name": "FNNAS",
"group": "文件", "group": "NAS",
"url": "http://{STUN_你的STUN规则名_ADDR}", "url": "http://{STUN_你的STUN规则名_ADDR}",
"note": "家中文件服务" "note": "家里 NAS"
} }
``` ```
也可以不用 JSON,直接用 URL 参数: ### 方式三:拆分 host 和 port
```text 如果你想分别传 IP 和端口:
http://你的导航页地址:8080/api/webhook/alist?token=换成一串随机密钥&name=AList&group=文件&url=http://{STUN_你的STUN规则名_ADDR}
```json
{
"name": "FNNAS",
"group": "NAS",
"protocol": "http",
"host": "{STUN_你的STUN规则名_IP}",
"port": "{STUN_你的STUN规则名_PORT}"
}
``` ```
Lucky 的全局变量需要把 `规则名` 替换成 STUN 穿透规则列表里的真实规则名,不是导航页服务名,也不是环境变量。例如你的 STUN 规则名叫 `alist-web`,就写 `{STUN_alist-web_ADDR}`。 最终会拼成:
```text
http://IP:PORT
```
## Lucky STUN 变量说明
Lucky 的 STUN 全局变量不是系统环境变量,而是 Lucky webhook 中可用的占位符。
格式:
```text ```text
{STUN_规则名_ADDR} {STUN_规则名_ADDR}
@@ -64,40 +293,169 @@ Lucky 的全局变量需要把 `规则名` 替换成 STUN 穿透规则列表里
{STUN_规则名_PORT} {STUN_规则名_PORT}
``` ```
## Webhook 支持的字段 这里的 `规则名` 必须替换成 Lucky 里 STUN 穿透规则列表中的真实规则名。
| 字段 | 说明 | 例如:
| --- | --- |
| `id` | 服务唯一标识;也可以写在 `/api/webhook/:id` 里 |
| `name` | 页面显示名称 |
| `group` | 页面分组 |
| `url` | 完整跳转地址,例如 `http://1.2.3.4:12345` |
| `addr` | 地址加端口,例如 `1.2.3.4:12345` |
| `host` / `ip` + `port` | 分开发送主机和端口 |
| `protocol` / `scheme` | `http` 或 `https`,默认 `http` |
| `path` | 跳转路径,例如 `/admin` |
| `note` | 备注 |
收到的数据会保存在 `data/links.json`。 ```text
STUN 规则名:fnnas
## 删除导航 完整地址:{STUN_fnnas_ADDR}
IP:{STUN_fnnas_IP}
删除某个导航项时,用它的 `id` 调用删除接口。`id` 默认来自 `/api/webhook/:id` 里的那一段,例如 `/api/webhook/alist` 创建的导航,删除时就是: 端口:{STUN_fnnas_PORT}
```bash
curl -X DELETE "http://你的导航页地址:8080/api/services/alist?token=换成一串随机密钥"
``` ```
删除刚才测试的百度示例: 如果你的规则名是:
```bash ```text
curl -X DELETE "http://你的导航页地址:8080/api/services/baidu?token=换成一串随机密钥" AList-Web
``` ```
如果不想调用接口,也可以停掉服务后直接编辑 `data/links.json`,删除对应对象,再重新启动服务。 就写:
```text
{STUN_AList-Web_ADDR}
```
## Webhook 字段
| 字段 | 说明 | 示例 |
| --- | --- | --- |
| `id` | 服务唯一标识,也可写在 `/api/webhook/:id` | `fnnas` |
| `name` | 页面显示名称 | `FNNAS` |
| `group` | 页面分组 | `NAS` |
| `url` | 完整跳转地址 | `http://1.2.3.4:12345` |
| `addr` | 地址加端口 | `1.2.3.4:12345` |
| `host` / `ip` | 主机或 IP | `1.2.3.4` |
| `port` | 端口 | `12345` |
| `protocol` / `scheme` | 协议,默认 `http` | `https` |
| `path` | 跳转路径 | `/admin` |
| `note` | 备注 | `家里 NAS` |
如果同时提供多个地址字段,优先级是:
```text
url > addr > host/ip + port
```
## API 说明
### 获取导航列表
```bash
curl "https://你的域名/api/services"
```
返回页面设置和导航列表。
### 新增或更新导航
```bash
curl -X POST "https://你的域名/api/webhook/fnnas?token=你的随机密钥" \
-H "Content-Type: application/json" \
--data '{"name":"FNNAS","group":"NAS","url":"http://1.2.3.4:12345"}'
```
### 删除导航
```bash
curl -X DELETE "https://你的域名/api/services/fnnas?token=你的随机密钥"
```
### 修改页面设置
```bash
curl -X PUT "https://你的域名/api/settings?token=你的随机密钥" \
-H "Content-Type: application/json" \
--data '{"browserTitle":"导航","brand":"HOME","title":"家庭服务","subtitle":"我的服务入口"}'
```
## 常见问题
### 1. 只访问 `/api/webhook/fnnas?token=xxx` 为什么新增失败?
因为只传了 ID 和 token,没有传导航地址。
至少需要传 `url`、`addr`,或者 `host + port`。
正确示例:
```text
https://你的域名/api/webhook/fnnas?token=xxx&name=FNNAS&url=http://{STUN_fnnas_ADDR}
```
### 2. EdgeOne 上返回 KV 相关错误怎么办?
检查 KV 是否已绑定,绑定变量名必须是:
```text
STUN_NAV_KV
```
### 3. 后台提示 invalid webhook token 怎么办?
检查后台输入的密钥是否等于部署时设置的:
```text
WEBHOOK_TOKEN
```
### 4. Lucky 变量没有替换怎么办?
确认 Lucky webhook 配置位置支持全局变量,并确认 STUN 规则名完全一致。
例如规则名是 `fnnas`,就写:
```text
{STUN_fnnas_ADDR}
```
不要写成:
```text
{STUN_你的服务名_ADDR}
```
除非你的 STUN 规则名真的叫 `你的服务名`。
### 5. 页面看起来没有更新怎么办?
浏览器可能缓存了旧资源,可以尝试:
```text
https://你的域名/admin?fresh=1
```
或者强制刷新浏览器。
项目的静态资源已经加了版本号,并在 `edgeone.json` 中设置了 `Cache-Control: no-cache`。
## 安全建议 ## 安全建议
- 一定要设置 `WEBHOOK_TOKEN`。 - 不要使用简单密码当 `WEBHOOK_TOKEN`
- 不建议直接把导航页暴露到公网裸奔,最好放到 HTTPS 反代后面。 - 不要把 `WEBHOOK_TOKEN` 发给别人
- 如果导航页本身也通过 STUN 暴露,至少给入口加访问控制或复杂路径。 - 如果密钥泄露,立即在部署平台更换
- 后台 `/admin` 暴露在公网时,建议配合 EdgeOne 访问控制或其他鉴权
- 本地部署时不要把 `data/links.json` 提交到公开仓库
## 开发
本地启动:
```bash
npm start
```
开发模式:
```bash
npm run dev
```
语法检查:
```bash
node --check server.mjs
node --check public/app.js
node --check public/admin.js
node --check 'edge-functions/api/[[default]].js'
```