Files
TPSchedule/server/updates/README.md
T

160 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TPSchedule 更新服务
独立于反馈服务,管理员在 `https://app.glowtps.cn/update` 发布安卓版本;APP查询 `https://app.glowtps.cn/v1/updates/android`。无需接入第三方推送SDK。APP冷启动进入首页后检查一次,后台无版本或网络失败时安静结束;“我的→检查更新”提供手动查询。有新版时用户可稍后处理,或打开浏览器下载。
## Ubuntu、1Panel、雷池部署步骤
按已说明的环境配置:雷池占用80/443,OpenResty使用host网络、HTTP10080/HTTPS12443。即使1Panel中尚无网站,也可以按下方第4步新建转发站点。新增更新容器仅监听 `127.0.0.1:18081`,反馈容器继续使用18080;新站点分别转发这两个服务,不需要修改反馈代码、SMTP或雷池证书。本工程没有访问服务器或执行部署。
### 1. 上传服务文件
把 `TPSchedule-update-server.zip` 上传到1Panel文件管理器并解压,将 `updates` 目录内的文件放到 `/opt/tpschedule-updates`。确认该目录直接包含 `Dockerfile`、`docker-compose.yml`、`main.py`、`update_service.py` 等文件。
在1Panel终端确认18081没有其他服务占用:
```sh
ss -ltn '( sport = :18081 )'
cd /opt/tpschedule-updates
cp .env.example .env
chmod 600 .env
docker compose build
```
如果18081已占用,选择未使用的本机端口并同时修改Compose与下方OpenResty示例;不要停止其他服务。首次构建需要服务器访问镜像源及Python依赖源。
### 2. 设置更新后台登录
执行:
```sh
docker compose run --rm --no-deps updates python manage.py
```
按提示输入至少12位后台密码并再次确认。工具会输出 `ADMIN_PASSWORD_HASH='…'` 和 `SESSION_SECRET='…'` 两行。只在服务器将这两行填入 `.env` 的对应位置,保留单引号,避免Docker把密码哈希中的 `$` 当作变量。不要把输出或密码发到聊天中。
`.env`其他项目:
```dotenv
PUBLIC_ORIGIN=https://app.glowtps.cn
ADMIN_USERNAME=admin
DATA_DIR=/app/data
```
`PUBLIC_ORIGIN`不加结尾斜杠或路径,必须使用浏览器实际访问的HTTPS域名。可以自行修改ADMIN_USERNAME。密码以scrypt哈希保存;明文密码不写入APP或源码。SESSION_SECRET是更新后台自己的会话密钥,与APK签名密钥和反馈服务密钥无关。日后改密码时可重新运行工具并替换上述两行,重建服务使原登录失效。
### 3. 启动并检查容器
```sh
docker compose up -d
docker compose ps
curl --fail --max-time 10 http://127.0.0.1:18081/healthz
curl --fail --max-time 10 http://127.0.0.1:18081/v1/updates/android
```
健康检查返回 `{"status":"ok"}`;首次没有发布记录,公开接口返回:
```json
{"schema_version":1,"application_id":"com.tpschedule.app","latest":null}
```
`.env`、Compose项目名`tpschedule-updates`及`update-data`数据卷要长期保留;正常重建不会清空版本。不要执行带 `-v` 的删除数据卷命令。服务配置错误时检查 `docker compose logs --tail 30 updates`,分享错误前不要附带.env或秘密值。
### 4. 创建或配置OpenResty转发站点
没有在1Panel建过网站也可以,创建一个反向代理站点即可,不需要上传网页、安装PHP或创建数据库。
**4.1 如果尚无站点**
确认1Panel已安装OpenResty。若没有,在应用商店安装,HTTP端口使用10080、HTTPS端口使用12443,继续使用host网络;80/443留给雷池。若已经安装且是上述配置,不需要重装。
1Panel“网站”→“创建网站”→“反向代理”,填写:
| 项目 | 内容 |
| --- | --- |
| 主域名 | `app.glowtps.cn:10080`;如果界面有单独端口栏,域名填`app.glowtps.cn`、端口填`10080` |
| 代理地址 | `http://127.0.0.1:18081` |
| 代号/备注 | `tpschedule-app`/TPSchedule更新与反馈 |
| 启用HTTPS | 不勾选;外部证书由雷池提供 |
| 强制HTTPS跳转 | 关闭,避免雷池HTTP回源循环跳转 |
创建后,在站点配置中确认`listen 10080;`和`server_name app.glowtps.cn;`。`server_name`不带`:10080`。具体菜单名称可能因1Panel版本略有不同。
**4.2 配置路径和保留反馈接口**
打开1Panel“网站”→`app.glowtps.cn`→配置文件,在`server { … }`内添加`openresty-safeline.conf.example`中的三个location。如果已有站点则直接从这里开始。新建的反向代理站点通常已有`location /`,保留它;新增的精确路径规则与它并存。不要把location嵌套在另一个location里,不要重复定义同名路径。
如果当前反馈服务已经运行在18080,还要加入下面的精确路由,否则把整个域名改为回源新服务会使原反馈接口失效:
```nginx
location = /v1/feedback {
client_max_body_size 24m;
client_body_timeout 60s;
proxy_request_buffering off;
proxy_buffering off;
proxy_http_version 1.1;
proxy_pass http://127.0.0.1:18080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Connection "";
proxy_connect_timeout 5s;
proxy_send_timeout 180s;
proxy_read_timeout 180s;
proxy_next_upstream off;
access_log off;
}
```
反馈服务还没部署时可以暂不添加这一条,更新后台不依赖反馈服务。若新站点需要还原真实客户端IP,在server层配置`set_real_ip_from 127.0.0.1;`、`set_real_ip_from ::1;`、`real_ip_header X-Forwarded-For;`和`real_ip_recursive on;`,已有相同设置时不重复添加。它们信任的是同机雷池回源,不是任意公网来源。
验证配置并重载OpenResty。先在服务器终端检查内部转发,不要立即改雷池现有上游:
```sh
curl --fail --max-time 10 -H 'Host: app.glowtps.cn' http://127.0.0.1:10080/v1/updates/android
```
应返回版本JSON(首次latest为null)。若返回404、502或其他站点页面,先检查站点监听端口、Host和18081容器,不需要关闭或修改雷池其他站点。
**4.3 配置雷池回源**
内部检查通过后,在雷池编辑`app.glowtps.cn`这一个站点:域名仍为`app.glowtps.cn`,公网HTTPS端口443和证书保持,上游协议HTTP、地址`127.0.0.1:10080`;若上游栏要求完整URL,填`http://127.0.0.1:10080`。如果原先直接回源18080,此时才切换到10080;其他域名和雷池管理设置不改。
最终链路是:浏览器/APP→雷池443→OpenResty10080→更新服务18081或反馈服务18080。无需开放18080/18081公网端口,也不需要为1Panel再申请一份网站证书。
如果雷池启用了必须由浏览器完成的人机验证,仅对APP查询路径`/v1/updates/android`关闭交互挑战;保留网站其他保护。此API是公开、只读的版本信息,不能要求管理员登录或返回HTML挑战页面。后台`/update`保持正常防护,登录和发布使用POST,不能缓存这些路径。
浏览器打开 `https://app.glowtps.cn/update`,应看到蓝色登录页面。后台使用Secure Cookie,必须通过外部HTTPS访问,直接用服务器IP或HTTP测试登录会失败。随后访问公开JSON接口核对转发。
### 5. 发布版本
先把APK放到你现有的公开HTTPS下载位置,例如腾讯云COS或1Panel站点中已经可以下载的目录。本服务只管理版本信息,不存放APK;后台不会代表你访问下载链接。请用手机浏览器确认链接能打开,无登录要求且能下载正确文件。
安装包仍需使用原来的 `com.tpschedule.app` 包名、原签名,并递增构建号。当前本版是 **0.7.6+24**;其中版本号填写 `0.7.6`,版本序号(构建号)填写 `24`。下一次发布的确切数字以交付时提供的版本为准,不要仅修改后台数字而不重新构建APK。
登录后台填写:版本号、构建号、更新说明、公开HTTPS下载链接,点“保存并发布”。第一次可发布0.7.6/24,使公开信息与当前交付一致;已安装本版的用户不会收到同版更新提示。以后发布比24大的构建号时,已接入更新模块的APP启动或手动检查就会弹出更新说明。
同一版本号、同一构建号允许修改说明和下载链接;新增安装包应增加构建号。后台禁止降低构建号和版本号,并检测另一个页面修改,避免旧表单误覆盖。保存失败时原版本保留。新版本号应遵循 `数字.数字.数字`,不带V或+构建号。
更新提示是启动/手动联网检查,并非APP关闭后的系统通知,也不静默安装。用户点击立即更新后通过浏览器下载并按Android提示安装,APP不申请“安装未知应用”权限。需要允许浏览器安装来源时由Android和浏览器处理。
创建反向代理网站及主域名/端口设置依据1Panel官方文档:https://docs.fit2cloud.com/1panel/user_manual/websites/website-create/ 。上文端口与转发规则按本工程和用户已说明的雷池同机环境制定,尚未在实际服务器执行。
### 6. 第一次如何让同学接入
0.7.5及之前的APP没有检查更新代码,服务器无法给它们凭空补上。第一次仍需手动分发、覆盖安装0.7.6;之后这些用户才能收到你在后台发布的后续版本。**不要卸载旧版**,原包名、签名一致时覆盖安装保留本机课表。
## 维护和备份
正常更新服务代码:保留.env和数据卷,在原目录执行 `docker compose up -d --build`。更新后台密码和版本文件不要放进Git或聊天;备份现有数据卷时保持原Compose归属。磁盘或JSON损坏会返回503,不会伪装成没有更新或自动清空。后台会话8小时有效,登录有尝试次数限制;退出清除当前浏览器的登录Cookie。
## API约定
已发布时返回200及以下JSON,响应禁止缓存。APP只在build_number大于自身构建号时提示,版本文本用于显示;跨应用、格式错误、HTTP错误、重定向或超过64KiB的响应都不会被当作更新成功。
```json
{"schema_version":1,"application_id":"com.tpschedule.app","latest":{"version":"0.7.6","build_number":24,"notes":"新增启动与手动检查更新。","download_url":"https://example.com/TPSchedule-0.7.6.apk","published_at":"2026-10-24T00:00:00+00:00"}}
```
未部署/断网时自动检查不提示错误,手动检查显示失败原因;不影响已有课表或登录。下载链接只能用HTTPS,不能包含用户名/密码。发布信息中的更新说明在后台转义显示,APP按纯文本呈现。