Expand deployment and usage documentation
This commit is contained in:
466
README.md
466
README.md
@@ -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
|
||||
WEBHOOK_TOKEN=换成一串随机密钥 PORT=8080 npm start
|
||||
node -v
|
||||
```
|
||||
|
||||
然后访问:
|
||||
### 2. 启动服务
|
||||
|
||||
```text
|
||||
http://服务器IP:8080
|
||||
```bash
|
||||
WEBHOOK_TOKEN=换成你自己的随机密钥 PORT=8080 npm start
|
||||
```
|
||||
|
||||
管理页:
|
||||
参数说明:
|
||||
|
||||
| 参数 | 说明 |
|
||||
| --- | --- |
|
||||
| `WEBHOOK_TOKEN` | 管理和 webhook 密钥,必须设置成随机字符串 |
|
||||
| `PORT` | 服务端口,默认 `8080` |
|
||||
|
||||
启动后访问:
|
||||
|
||||
```text
|
||||
http://服务器IP:8080/
|
||||
http://服务器IP:8080/admin
|
||||
```
|
||||
|
||||
打开管理页后填写 `WEBHOOK_TOKEN`,即可手动新增、修改、删除导航项,也可以修改浏览器标题、顶部标识、首页标题和副标题。密钥只保存在当前浏览器本地。
|
||||
### 3. 本地数据保存位置
|
||||
|
||||
## 部署到 EdgeOne Pages
|
||||
本地版本数据保存在:
|
||||
|
||||
项目已经包含 EdgeOne Pages 改造版本,见 `EDGEONE.md`。
|
||||
```text
|
||||
data/links.json
|
||||
```
|
||||
|
||||
核心变化:
|
||||
这个文件包含导航信息和页面设置,默认不会提交到 GitHub。
|
||||
|
||||
- 静态页面从 `public/` 部署
|
||||
- `/api/*` 由 `edge-functions/api/[[default]].js` 提供
|
||||
- 数据保存到 EdgeOne KV,绑定变量名需要设置为 `STUN_NAV_KV`
|
||||
- 管理密钥使用环境变量 `WEBHOOK_TOKEN`
|
||||
### 4. 反向代理建议
|
||||
|
||||
如果你用 Nginx、Caddy、Lucky Web 服务等反向代理,建议:
|
||||
|
||||
- 使用 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 发送 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
|
||||
URL: http://你的导航页地址:8080/api/webhook/alist?token=换成一串随机密钥
|
||||
Method: POST
|
||||
Content-Type: application/json
|
||||
Body:
|
||||
```
|
||||
|
||||
请求体:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "AList",
|
||||
"group": "文件",
|
||||
"name": "FNNAS",
|
||||
"group": "NAS",
|
||||
"url": "http://{STUN_你的STUN规则名_ADDR}",
|
||||
"note": "家中文件服务"
|
||||
"note": "家里 NAS"
|
||||
}
|
||||
```
|
||||
|
||||
也可以不用 JSON,直接用 URL 参数:
|
||||
### 方式三:拆分 host 和 port
|
||||
|
||||
```text
|
||||
http://你的导航页地址:8080/api/webhook/alist?token=换成一串随机密钥&name=AList&group=文件&url=http://{STUN_你的STUN规则名_ADDR}
|
||||
如果你想分别传 IP 和端口:
|
||||
|
||||
```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
|
||||
{STUN_规则名_ADDR}
|
||||
@@ -64,40 +293,169 @@ Lucky 的全局变量需要把 `规则名` 替换成 STUN 穿透规则列表里
|
||||
{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`。
|
||||
|
||||
## 删除导航
|
||||
|
||||
删除某个导航项时,用它的 `id` 调用删除接口。`id` 默认来自 `/api/webhook/:id` 里的那一段,例如 `/api/webhook/alist` 创建的导航,删除时就是:
|
||||
|
||||
```bash
|
||||
curl -X DELETE "http://你的导航页地址:8080/api/services/alist?token=换成一串随机密钥"
|
||||
```text
|
||||
STUN 规则名:fnnas
|
||||
完整地址:{STUN_fnnas_ADDR}
|
||||
IP:{STUN_fnnas_IP}
|
||||
端口:{STUN_fnnas_PORT}
|
||||
```
|
||||
|
||||
删除刚才测试的百度示例:
|
||||
如果你的规则名是:
|
||||
|
||||
```bash
|
||||
curl -X DELETE "http://你的导航页地址:8080/api/services/baidu?token=换成一串随机密钥"
|
||||
```text
|
||||
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`。
|
||||
- 不建议直接把导航页暴露到公网裸奔,最好放到 HTTPS 反代后面。
|
||||
- 如果导航页本身也通过 STUN 暴露,至少给入口加访问控制或复杂路径。
|
||||
- 不要使用简单密码当 `WEBHOOK_TOKEN`
|
||||
- 不要把 `WEBHOOK_TOKEN` 发给别人
|
||||
- 如果密钥泄露,立即在部署平台更换
|
||||
- 后台 `/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'
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user