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没有其他服务占用:
ss -ltn '( sport = :18081 )'
cd /opt/tpschedule-updates
cp .env.example .env
chmod 600 .env
docker compose build
如果18081已占用,选择未使用的本机端口并同时修改Compose与下方OpenResty示例;不要停止其他服务。首次构建需要服务器访问镜像源及Python依赖源。
2. 设置更新后台登录
执行:
docker compose run --rm --no-deps updates python manage.py
按提示输入至少12位后台密码并再次确认。工具会输出 ADMIN_PASSWORD_HASH='…' 和 SESSION_SECRET='…' 两行。只在服务器将这两行填入 .env 的对应位置,保留单引号,避免Docker把密码哈希中的 $ 当作变量。不要把输出或密码发到聊天中。
.env其他项目:
PUBLIC_ORIGIN=https://app.glowtps.cn
ADMIN_USERNAME=admin
DATA_DIR=/app/data
PUBLIC_ORIGIN不加结尾斜杠或路径,必须使用浏览器实际访问的HTTPS域名。可以自行修改ADMIN_USERNAME。密码以scrypt哈希保存;明文密码不写入APP或源码。SESSION_SECRET是更新后台自己的会话密钥,与APK签名密钥和反馈服务密钥无关。日后改密码时可重新运行工具并替换上述两行,重建服务使原登录失效。
3. 启动并检查容器
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"};首次没有发布记录,公开接口返回:
{"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,还要加入下面的精确路由,否则把整个域名改为回源新服务会使原反馈接口失效:
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。先在服务器终端检查内部转发,不要立即改雷池现有上游:
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的响应都不会被当作更新成功。
{"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按纯文本呈现。