8.6 KiB
雷池 WAF + 1Panel:TPSchedule 反馈服务部署
适用环境:Ubuntu,雷池占用80/443;OpenResty为host网络模式,HTTP为10080、HTTPS为12443;雷池现有站点通过127.0.0.1回源。以下是按已知环境制定的操作步骤,尚未在你的服务器执行。
访问链路
手机APP:https://app.glowtps.cn/v1/feedback
↓ HTTPS,公网443
雷池WAF:证书和外部HTTPS跳转
↓ http://127.0.0.1:10080,Host仍为app.glowtps.cn
OpenResty:app.glowtps.cn站点
↓ http://127.0.0.1:18080
反馈服务容器:内部8000
↓ smtp.feishu.cn:465,SSL
authors@glowtps.cn → tps-david@glowtps.cn
该反馈站点在雷池终止HTTPS,后两段是同机内部HTTP。OpenResty已有12443端口及其他网站保持原设置。反馈容器使用现有Compose配置,宿主机仅发布127.0.0.1:18080,公网安全组无需增加该端口。
1. 上传、解压和确认目录
将TPSchedule-feedback-server.zip上传到1Panel文件管理并解压。压缩包内有feedback目录;将这个目录中的文件放到 /opt/app-feedback,确保 /opt/app-feedback/Dockerfile 和 /opt/app-feedback/docker-compose.yml 实际存在。不要形成多套嵌套目录后在错误目录启动。
在1Panel服务器终端查看目标端口是否已被占用:
ss -ltn '( sport = :18080 )'
若18080已有其他服务,不要停止它;告诉开发者占用情况后再协调新端口。以下步骤使用18080。
2. 填写服务器配置
在文件管理中将 .env.example 复制为 .env,保留模板其他参数,核对:
SMTP_HOST=smtp.feishu.cn
SMTP_PORT=465
SMTP_TLS=ssl
SMTP_USERNAME=authors@glowtps.cn
MAIL_FROM=authors@glowtps.cn
MAIL_TO=tps-david@glowtps.cn
DATABASE_PATH=/app/data/feedback.sqlite3
SMTP_PASSWORD填写飞书邮箱的第三方客户端授权密码,只在服务器编辑器里填写。IDEMPOTENCY_SECRET填写持久随机密钥,在服务器终端生成:
openssl rand -hex 32
将生成结果填回 .env 中的IDEMPOTENCY_SECRET。两个示例REPLACE_占位值均须替换,秘密值建议用英文单引号包住。不要将真实密码或密钥发到聊天里。
3. 启动服务并验证第一段
在1Panel服务器终端执行:
cd /opt/app-feedback
chmod 600 .env
docker compose up -d --build
docker compose ps
curl --fail --max-time 10 http://127.0.0.1:18080/healthz
最后返回 {"status":"ok"} 才继续。这一步不发送邮件,也不验证飞书密码;它验证容器和本机18080。首次构建需要服务器能下载镜像及Python依赖。启动失败可以查看 docker compose logs --tail 50 feedback,分享错误时不要附带.env或完整容器环境详情。
可以改用1Panel“容器→编排”启动,但构建目录须为上述目录,环境文件也在该目录;固定使用同一个Compose项目 app-feedback,避免创建多个副本。
4. 配置OpenResty的10080站点
在1Panel“网站”中找到或新建 app.glowtps.cn 站点。新建可选择反向代理,代理地址填 http://127.0.0.1:18080。网站域名绑定app.glowtps.cn,HTTP监听10080;如果主域名字段要求域名加端口,填 app.glowtps.cn:10080。最终配置应能看到 listen 10080; 和 server_name app.glowtps.cn;,以实际生成配置为准。
这个内部HTTP站点关闭“强制HTTPS/HTTP转HTTPS”。外部HTTPS由雷池负责,否则雷池每次HTTP回源都可能再次触发HTTPS重定向。无需给这个新反馈站点另开12443。
先保存该站点原配置。将同目录 openresty-safeline-http.conf.example 中的配置加入此站点的HTTP server { ... } 内。不要替换OpenResty总配置。若已经有同名精确location,修改原块,保持每个路径只有一个对应块;域名已有页面时保留其他路由。
该片段只信任127.0.0.1/::1传来的真实IP信息。雷池通过X-Forwarded-For透传源IP,经OpenResty校正后再发送给服务,以免所有学生被当成同一个IP、共享每小时10次的限制。不要将可信来源设置成0.0.0.0/0。若现有配置也在此层处理真实IP,先核对并合并,避免重复指令;如果雷池实际连接源地址不是回环地址,应仅补充那个确定的可信地址。
在1Panel执行配置检查,检查成功后重新加载OpenResty。然后在宿主机终端验证:
curl --fail --max-time 10 -H 'Host: app.glowtps.cn' http://127.0.0.1:10080/healthz
同样应返回 {"status":"ok"}。到这里已验证服务和OpenResty,雷池尚未参与。
5. 配置雷池站点
在雷池中找到或添加app.glowtps.cn防护站点,按以下设置:
| 配置项 | 值 |
|---|---|
| 域名 | app.glowtps.cn |
| 公网HTTP端口 | 80,保持现有入口 |
| 公网HTTPS端口 | 443 |
| 上游服务器 | http://127.0.0.1:10080 |
| 回源Host | app.glowtps.cn,保留原Host或明确填写 |
| HTTPS证书 | 能覆盖app.glowtps.cn的有效证书 |
| 外部HTTP跳转HTTPS | 在雷池设置 |
如果上游地址UI将协议/地址/端口拆开,分别选择HTTP、127.0.0.1、10080。保持路径 /v1/feedback 原样转发,不额外增加前缀;上游不要填公网上的app.glowtps.cn,以免请求转回雷池形成循环。证书可使用已有覆盖该域名的通配证书;申请新证书时可选DNS验证,避免绕行到内部站点的HTTP校验问题。
域名A记录应指向43.138.57.216;已有正确记录时沿用。所有公网入口继续经过雷池。
该接口来自原生APP HTTP客户端,无法执行网页JavaScript或拖动验证码。对这个API站点或精确路径 /v1/feedback、/healthz 避免开启浏览器人机验证、网页登录跳转、动态JS注入和等待室。根据版本提供的站点/路径配置范围操作,保留适用于API的攻击检测及频率限制;不要通过全站攻击白名单解决误拦。
图片、视频请求使用multipart/form-data。雷池此站点应允许约21MiB的HTTP请求体,回源等待时间设为至少60秒(如支持,可与OpenResty设置一致为180秒)。服务自己仍限制最多3个附件、单个8MiB、合计20MiB。雷池HTTP请求体限额不足时会在服务之前返回413;浏览器挑战可能返回HTML甚至200,APP会拒绝把它当作提交成功。
6. 验证整条链路及邮件
在服务器执行,或用手机浏览器访问这个完整健康检查地址:
curl --fail --max-time 15 https://app.glowtps.cn/healthz
应直接返回 {"status":"ok"}。curl默认校验证书,正常验证时不加 -k。根地址 / 不是健康检查页面,出现404不能据此判断反馈服务失败。
然后从TPSchedule的“我的→反馈与共建”提交一条“部署测试”,检查 tps-david@glowtps.cn 是否收到。若要同时验证重复提交保护,在服务器终端手动发送两次完全相同的测试请求:
feedback_test_id=$(openssl rand -hex 16)
curl --max-time 30 -i https://app.glowtps.cn/v1/feedback \
-F "submission_id=$feedback_test_id" \
-F 'type=problem' \
-F 'message=TPSchedule 部署测试,请忽略。'
保留feedback_test_id,在同一终端再次执行这条curl(不重新生成ID)。两次应确认相同ID的sent结果,邮箱只收到一封。success:true/status:sent表示SMTP接受并记入数据库,实际进入收件箱需你核对。
分层排查
| 哪一段失败 | 优先检查 |
|---|---|
| 本机18080/healthz失败 | Compose状态、构建、.env必填配置、容器日志 |
| 18080正常,10080加Host失败 | 站点监听10080、域名匹配、精确location、代理地址 |
| 两个本机地址正常,公网失败 | DNS、雷池证书/域名/上游/Host、人机验证、WAF记录 |
| healthz正常,POST被拦或返回HTML | 该接口的雷池挑战、攻击拦截、上传限制 |
| POST返回smtp_unavailable | 飞书客户端授权、账号、服务器出站465、发信权限 |
| POST返回429 | 测试频率、真实IP链路;服务默认每IP每小时10次/全局100次 |
| 返回delivery_uncertain | 先查邮件及投递状态,用原ID核对,不生成新ID强行重发 |
更新时保持.env、原IDEMPOTENCY_SECRET和SQLite数据卷,继续同一Compose项目。不要执行 docker compose down -v,它会移除重复提交记录。