chore(deploy): 健康检查发正确 Host、list 型配置改 JSON、Host 校验收窄

- backend 健康检查改为发送正确的 Host 头(而非放宽 ALLOWED_HOSTS);
  配合 ALLOW_LOCALHOST_HOSTS=false,Host: localhost 现在返回 400,容器自检仍 exit 0
- OAUTH_ALLOWED_HOSTS / CORS_STRICT_STARTUP / SCHEDULER_ALLOW_CODE_EXEC 接入 compose 注入
- ⚠️ OAUTH_ALLOWED_HOSTS 是 list[str],必须写 JSON 数组:本次部署曾因写成逗号分隔字符串
  导致启动期 SettingsError、容器重启、网关 502(已修复,并在 compose 默认值中固化 JSON 形态)
- DEPLOYMENT.md 新增「配置取值格式」章节记录该坑与排查方法
- AUDIT-REPORT.md 更新修复进展(含复核 t12 驳回与 t13/t14 通过、残余项)

线上验证:四端 200;Host=localhost → 400;健康检查 exit 0;公网 docs/.DS_Store → 403
This commit is contained in:
zhangtao
2026-10-04 05:12:37 +08:00
parent 07fa789d2e
commit c73daa7eae
4 changed files with 85 additions and 2 deletions
+13
View File
@@ -45,6 +45,19 @@ PROD_CORS_ORIGINS=https://service.fastapiadmin.com
FORWARDED_ALLOW_IPS=10.255.178.0/24
# 演示模式:true 时禁止写操作;生产需要可写请改为 false
DEMO_ENABLE=true
# Host 头校验范围:false 时 ALLOWED_HOSTS 只保留生产域名(不并入 localhost)。
# 容器健康检查已配置为发送正确的 Host,因此生产建议 false;
# 若你的健康检查/探针确实以 Host: localhost 访问容器,再设为 true。
ALLOW_LOCALHOST_HOSTS=false
# OAuth 回调与换取令牌允许的 Host。
# ⚠️ 该字段在应用里是 list[str]:必须写 **JSON 数组**,写成逗号分隔字符串会让服务启动失败
# (pydantic-settings 解析报 SettingsError,容器会不断重启)。
# 逗号分隔只适用于 str 类型字段,例如上面的 PROD_CORS_ORIGINS。
OAUTH_ALLOWED_HOSTS=["service.fastapiadmin.com","*.fastapiadmin.com"]
# 生产未配置 PROD_CORS_ORIGINS 时是否直接启动失败:false=仅告警(默认),true=严格
CORS_STRICT_STARTUP=false
# 定时任务是否允许执行用户提交的代码块(等同 RCE 能力,生产保持 false)
SCHEDULER_ALLOW_CODE_EXEC=false
# ---------- Nginx ----------
HTTP_PORT=80
+15 -1
View File
@@ -128,6 +128,17 @@ services:
PROD_CORS_ORIGINS: "${PROD_CORS_ORIGINS:-}"
# 演示模式:为 true 时禁止写操作。当前线上为 true,如需可写请设为 false
DEMO_ENABLE: "${DEMO_ENABLE:-true}"
# Host 头校验范围:false 时 ALLOWED_HOSTS 收敛为仅生产域名(推荐)。
# 容器健康检查已改为发送正确 Host,因此这里可以为 false。
ALLOW_LOCALHOST_HOSTS: "${ALLOW_LOCALHOST_HOSTS:-true}"
# OAuth 回调/换取令牌允许的 Host。
# 注意:应用里该字段是 list[str],pydantic-settings 要求 **JSON 数组**字面量,
# 写成逗号分隔字符串会导致启动期 SettingsError(已踩过,服务会起不来)。
OAUTH_ALLOWED_HOSTS: '${OAUTH_ALLOWED_HOSTS:-["service.fastapiadmin.com","*.fastapiadmin.com"]}'
# 生产未配置 PROD_CORS_ORIGINS 时是否直接启动失败(默认 false:仅告警并按空列表处理)
CORS_STRICT_STARTUP: "${CORS_STRICT_STARTUP:-false}"
# 定时任务是否允许执行用户提交的代码块(等同 RCE 能力,生产保持 false)
SCHEDULER_ALLOW_CODE_EXEC: "${SCHEDULER_ALLOW_CODE_EXEC:-false}"
ports:
# 仅绑定本机:数据面不对公网开放,容器之间经 app_network 互联
- "127.0.0.1:${BACKEND_PORT:-8001}:8001"
@@ -147,11 +158,14 @@ services:
condition: service_healthy
networks:
- app_network
# 健康检查必须带正确的 Host 头:应用启用了 TrustedHostMiddleware,
# Host 为 localhost 会被判 400;这里用「发正确 Host」而不是「放宽 ALLOWED_HOSTS」,
# 避免为了容器自检而降低对外 Host 校验强度。
healthcheck:
test:
[
"CMD-SHELL",
"python -c 'import urllib.request; req = urllib.request.Request(\"http://localhost:8001/api/v1/monitor/health/check\", headers={\"X-Forwarded-Proto\": \"https\"}); urllib.request.urlopen(req, timeout=5)' || exit 1",
"python -c 'import urllib.request; req = urllib.request.Request(\"http://localhost:8001/api/v1/monitor/health/check\", headers={\"Host\": \"service.fastapiadmin.com\", \"X-Forwarded-Proto\": \"https\"}); urllib.request.urlopen(req, timeout=5)' || exit 1",
]
interval: 15s
timeout: 10s