# 雷池 WAF + 1Panel:TPSchedule 反馈服务部署 适用环境:Ubuntu,雷池占用80/443;OpenResty为host网络模式,HTTP为10080、HTTPS为12443;雷池现有站点通过127.0.0.1回源。以下是按已知环境制定的操作步骤,尚未在你的服务器执行。 ## 访问链路 ```text 手机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服务器终端查看目标端口是否已被占用: ```sh ss -ltn '( sport = :18080 )' ``` 若18080已有其他服务,不要停止它;告诉开发者占用情况后再协调新端口。以下步骤使用18080。 ## 2. 填写服务器配置 在文件管理中将 `.env.example` 复制为 `.env`,保留模板其他参数,核对: ```dotenv 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填写持久随机密钥,在服务器终端生成: ```sh openssl rand -hex 32 ``` 将生成结果填回 `.env` 中的IDEMPOTENCY_SECRET。两个示例REPLACE_占位值均须替换,秘密值建议用英文单引号包住。不要将真实密码或密钥发到聊天里。 ## 3. 启动服务并验证第一段 在1Panel服务器终端执行: ```sh 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。然后在宿主机终端验证: ```sh 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。雷池此站点应允许至少24MiB的HTTP请求体,回源等待时间设为至少60秒(如支持,可与OpenResty设置一致为180秒)。服务自己仍限制最多3个附件、单个8MiB、合计20MiB。雷池HTTP请求体限额不足时会在服务之前返回413;浏览器挑战可能返回HTML甚至200,APP会拒绝把它当作提交成功。 ## 6. 验证整条链路及邮件 在服务器执行,或用手机浏览器访问这个完整健康检查地址: ```sh curl --fail --max-time 15 https://app.glowtps.cn/healthz ``` 应直接返回 `{"status":"ok"}`。curl默认校验证书,正常验证时不加 `-k`。根地址 `/` 不是健康检查页面,出现404不能据此判断反馈服务失败。 然后从TPSchedule的“我的→反馈与共建”提交一条“部署测试”,检查 `tps-david@glowtps.cn` 是否收到。若要同时验证重复提交保护,在服务器终端手动发送两次完全相同的测试请求: ```sh 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`,它会移除重复提交记录。 ## 官方参考 - [1Panel创建反向代理网站](https://docs.fit2cloud.com/1panel/user_manual/websites/website-create/) - [雷池常见问题:上游源IP透传](https://help.waf-ce.chaitin.cn/node/01975855-cd7d-78fb-a354-d2aa65a53cce) - [雷池人机验证使用浏览器环境](https://help.waf-ce.chaitin.cn/node/01973fc6-e1d8-7af4-b697-ab1312b8f9bd) - [Nginx真实IP模块及可信来源](https://nginx.org/en/docs/http/ngx_http_realip_module.html)