15 KiB
Nexus 宝塔一键登录 2 小时掉线阶段诊断报告(2026-07-07)
1. 本轮结论
针对服务器 42.193.182.190(Nexus server_id 约为 395)排查后,目前结论是:
- Nexus 生成的一键登录临时 token TTL 是 24 小时,不是 2 小时。
- 目标宝塔最近生成的
temp_login记录ttl_seconds为86399/86400秒。 - 宝塔面板登录超时配置文件
/www/server/panel/data/session_timeout.pl缺失,按宝塔源码public.get_session_timeout()默认应为86400秒。 - 宝塔
task.py已经是按public.get_session_timeout()清理 session,不再是旧的硬编码 3600 秒清理。 - 目标宝塔未开启面板 SSL:
/www/server/panel/data/ssl.pl缺失。 - 未开启 SSL 时,宝塔源码
public.check_client_hash()会启用客户端 HASH 校验;一旦客户端 HASH 变化,宝塔会清空 session 并要求重新登录。这个更符合“同时打开 10 个宝塔,过一段时间刷新陆续掉线”的现象。
2. 已验证证据
2.1 最新 temp_login TTL
实际表位置:
/www/server/panel/data/db/default.db
最新记录示例:
id=108
state=0
add_local=2026-07-07 13:56:57
expire_local=2026-07-08 13:56:56
ttl_seconds=86399
seconds_left≈86377
说明 Nexus 生成的临时登录有效期约等于 24 小时。
2.2 宝塔登录超时配置
目标机:
/www/server/panel/data/session_timeout.pl = missing
宝塔源码逻辑:文件缺失时默认:
86400 seconds = 24 hours
2.3 宝塔 task.py session 清理
目标机 /www/server/panel/task.py 已存在:
session_cleanup_timeout = 86400
try:
session_cleanup_timeout = int(public.get_session_timeout() or 86400)
except Exception:
pass
if f_time > session_cleanup_timeout:
os.remove(filename)
所以当前不是旧版每 1 小时清理 session 的问题。
2.4 宝塔 SSL/client_hash 风险
目标机:
missing ssl.pl
宝塔源码中:
def is_ssl():
return os.path.exists(get_panel_path() + '/data/ssl.pl')
def check_client_hash():
if is_ssl(): return True
...
if session[skey] != client_hash:
WriteLog('用户登录', '客户端HASH验证失败,已强制退出登录...建议开启面板SSL或关闭IP-HASH验证!')
return False
推断:如果浏览器/代理/出口 IP/UA/客户端特征变化,或者多个宝塔窗口处于不同访问链路,刷新时可能触发 client_hash 校验失败,被宝塔强制退出。
3. 本轮已修 Nexus 问题
发现当前 POST /api/btpanel/servers/395/login-url 曾返回 502:
ModuleNotFoundError: No module named 'public'
根因:Nexus SSH fallback 用系统 Python 或未完整设置宝塔源码路径执行临时登录脚本。
已修改文件:
/opt/nexus-dev-current/server/infrastructure/btpanel/ssh_login.py
提交:
fa44439 fix btpanel ssh temp login python env
改动要点:
- Python 优先级调整为:
/www/server/panel/pyenv/bin/python3/www/server/panel/pyenv/bin/pythonpython3
- 临时登录脚本执行前:
os.chdir('/www/server/panel')- 加入
/www/server/panel - 加入
/www/server/panel/class
- 已热更新到运行中容器并重启。
- 验证:
tests/test_btpanel_login_url.py:6 passed- 一键登录接口再次返回
200 OK
注意:当前容器是单文件热更新;源码已提交。如果后续重新创建容器但不 rebuild 镜像,热更新会丢失。建议下一次部署时执行正式 build。
4. 为什么仍可能“2 小时后刷新掉线”
目前不是以下原因:
- 不是 Nexus temp token 只有 2 小时。
- 不是
public.get_session_timeout()配置成 2 小时。 - 不是
task.py仍按 3600 秒删除 session。
更可能是:
- 宝塔未开启面板 SSL,
check_client_hash()生效。 - 多个宝塔窗口、代理链路、出口 IP、浏览器 UA 或客户端指纹发生变化。
- 宝塔刷新请求时发现当前 session 内保存的 client_hash 与本次请求不同,于是清 session。
- 宝塔日志里这类错误通常是“客户端 HASH 验证失败,已强制退出登录”。
5. 下一步修复方案(待选择)
方案 A:开启宝塔面板 SSL(推荐优先验证)
- 原理:宝塔源码
if is_ssl(): return True,开启 SSL 后跳过 client_hash 校验。 - 好处:遵循宝塔自身逻辑,不改源码。
- 风险:需要处理证书、访问协议、端口和浏览器信任问题。
- 影响:可能需要 reload/restart 宝塔。
方案 B:Nexus 增加宝塔登录诊断提示
- 内容:一键登录返回/审计中记录
ttl_seconds、panel_ssl、client_hash_risk等非敏感信息。 - 好处:以后看到某台机器掉线,可直接确认风险点。
- 风险:要严格避免返回 token/cookie/API key。
- 影响:小改动。
方案 C:只对临时登录 session 放宽 client_hash
- 内容:patch 宝塔源码,若
session['tmp_login'] == True则跳过或降低 client_hash 校验。 - 好处:针对 Nexus 一键登录最直接。
- 风险:改宝塔源码,升级可能覆盖;安全性低于开启 SSL。
- 影响:需要 reload/restart 宝塔。
方案 D:关闭宝塔 IP-HASH/client_hash 校验
- 好处:最直接。
- 风险:全局安全性下降,不建议默认。
- 影响:所有宝塔登录会话受影响。
方案 E:Nexus 自动定期生成新临时登录 URL
- 内容:掉线时重新点一键登录;或前端提供刷新登录入口。
- 好处:不改宝塔。
- 风险:不能解决当前会话刷新被踢,只是降低恢复成本。
- 影响:小到中。
方案 F:前端/代理层保活
- 内容:定时请求宝塔保持 session 活跃。
- 好处:对 session_timeout 问题有帮助。
- 风险:对 client_hash 失败基本无效;跨域限制多。
- 影响:不推荐作为主方案。
方案 G:Nexus 代理式宝塔访问
- 内容:Nexus 托管/代理宝塔访问链路,减少客户端 HASH 变化。
- 好处:长期可控。
- 风险:大改;安全边界复杂。
- 影响:开发量最大。
6. 当前推荐
推荐顺序:
- 先选 方案 A:开启宝塔面板 SSL,验证多开 10 个宝塔 2 小时后刷新是否仍掉线。
- 同时做 方案 B:Nexus 诊断提示,以后每台宝塔能直接看 TTL/SSL/client_hash 风险。
- 如果 A 不方便或仍失败,再考虑 方案 C:仅对临时登录放宽 client_hash。
7. 待办
- 用户确认选 A/B/C/D/E/F/G 哪个方向。
- 若选 A:在测试机上开启面板 SSL 并记录回滚方式。
- 若选 B:实现 Nexus 只读诊断,不返回敏感 token/cookie。
- 若选 C/D:先备份宝塔源码,再 patch,并保留一键回滚脚本。
- 正式重建 Nexus Docker 镜像,让
fa44439固化进镜像。
8. 补充:get_client_hash 精确逻辑
后续只读查看 /www/server/panel/class/public.py 后确认:
def get_client_hash():
is_tmp_login = session.get('tmp_login')
is_session_safe_mode = session.get('session_safe_mode')
if is_tmp_login or is_session_safe_mode:
client_hash = md5(request.remote_addr)
else:
...
因此对 Nexus 一键登录这种 tmp_login=True 的会话,宝塔主要绑定的是:
request.remote_addr
也就是宝塔看到的客户端来源 IP。
这进一步解释了“同时打开多个宝塔,约 2 小时后刷新陆续掉线”:如果浏览器代理、网络出口、反代、CDN、VPN 或宝塔前面的转发链路导致 request.remote_addr 变化,宝塔刷新时会认为客户端 HASH 不一致,然后清空 session。
所以最优先验证项变为:
- 开启宝塔面板 SSL,让
check_client_hash()直接返回 True。 - 或保证访问宝塔时来源 IP 固定。
- 或只对 Nexus 临时登录会话放宽
tmp_login的 IP 绑定。
2026-07-07 诊断字段落地与验证
本次代码改动
已在 Nexus 后端增加宝塔一键登录的非敏感诊断字段 diagnostics:
temp_login_ttl_seconds:Nexus 申请宝塔临时登录链接的 TTL,当前为86400秒。session_cleanup_ttl_ok:宝塔task.py会话清理阈值巡检/修复是否成功。session_cleanup_ttl_patched:本次/最近一次 SSH bootstrap 是否修补过会话清理阈值。session_cleanup_ttl_checked_at:最近一次巡检时间。session_cleanup_ttl_last_error:最近一次巡检错误码,非敏感。panel_ssl:宝塔面板是否启用面板 SSL(检测/www/server/panel/data/ssl.pl),与 Nexus 的verify_ssl不是一个概念。client_hash_risk:当panel_ssl=false时为true,表示宝塔临时登录 session 仍有来源 IP 变化后被check_client_hash()清掉的风险。
改动文件
远端测试部署机 /opt/nexus-dev-current:
server/application/services/btpanel_service.pyserver/infrastructure/btpanel/bootstrap_state.pyserver/infrastructure/btpanel/ssh_bootstrap.pytests/test_btpanel_login_url.py
安全边界
- 没有返回或记录
api_key、cookie、tmp_token、宝塔密码、SSH 密钥等敏感值。 diagnostics只包含 TTL、布尔状态、时间、短错误码。- 审计日志里新增的也是同一份非敏感
diagnostics。 - 没有直接修改宝塔 SSL 开关或宝塔源码;只是把已知风险显式化。
测试结果
在 Nexus 测试部署机执行:
python -m py_compile server/infrastructure/btpanel/ssh_bootstrap.py \
server/infrastructure/btpanel/bootstrap_state.py \
server/application/services/btpanel_service.py \
tests/test_btpanel_login_url.py \
tests/test_btpanel_ssh_bootstrap.py
pytest tests/test_btpanel_login_url.py tests/test_btpanel_login_url_route.py tests/test_btpanel_ssh_bootstrap.py -q
# 24 passed
pytest -q
# 748 passed, 1 skipped
部署验证
已热更新 Nexus 测试容器:
docker cp server/application/services/btpanel_service.py nexus-nexus-1:/app/server/application/services/btpanel_service.py
docker cp server/infrastructure/btpanel/bootstrap_state.py nexus-nexus-1:/app/server/infrastructure/btpanel/bootstrap_state.py
docker cp server/infrastructure/btpanel/ssh_bootstrap.py nexus-nexus-1:/app/server/infrastructure/btpanel/ssh_bootstrap.py
docker restart nexus-nexus-1
curl http://127.0.0.1:18600/health
# ok
注意:当前是测试机容器热更新,正式固化仍建议 rebuild 镜像并按发布流程部署。
当前结论
代码层面已能区分:
- Nexus 一键登录 token TTL(24h)。
- 宝塔 session 清理阈值是否已修复到 24h。
- 宝塔面板 SSL 是否开启。
- 未开启面板 SSL 时,
tmp_login绑定来源 IP 导致“刷新后掉线”的风险。
下一步如果要彻底解决“多开 10 个宝塔,过 2 小时刷新陆续掉线”,优先建议在用户确认方案后处理宝塔侧:启用面板 SSL,或统一浏览器访问出口/反代来源 IP;不建议默认改宝塔 check_client_hash()。
宝塔官方文档补充
宝塔官方文档「面板基础设置」中说明:面板“超时时间”默认设置为 24 小时,可选 1小时、6小时、12小时、24小时、3天、7天;超过该时间未操作面板会自动退出登录。参考:https://docs.bt.cn/10.0/user-guide/config/panel-settings
这与目标机源码 public.get_session_timeout() 在缺少 session_timeout.pl 时默认 86400 秒的结果一致,因此目前“约 2 小时刷新掉线”的主因仍更像是未开启面板 SSL 时的 client_hash 来源 IP 绑定,而不是正常超时时间到了。
2026-07-07 正式环境 api.synaglobal.vip 最小热更新记录
部署方式
正式主机 /opt/nexus 当前工作树存在大量本地修改和未跟踪前端构建文件,因此没有执行 git pull、git reset 或整仓覆盖。
本次采用最小风险热更新:只把测试机已验证通过的 3 个后端 Python 文件复制进正式容器 nexus-prod-nexus-1:
/app/server/application/services/btpanel_service.py/app/server/infrastructure/btpanel/bootstrap_state.py/app/server/infrastructure/btpanel/ssh_bootstrap.py
正式容器旧文件已先备份到:
/tmp/nexus-bt-diag-backup-20260707-153452
部署校验
容器内 py_compile 通过,容器已重启,健康检查通过:
container: nexus-prod-nexus-1
health: ok
status: Up About a minute (healthy)
部署后 3 个文件在正式容器内的 SHA256:
eacf143745b14727fa66de99551e88e26c2f7ece3b4b0f82a071484da8b2dbd8 btpanel_service.py
3f84246b6b0635c3a8f74848fe606b23cac407e9a775feb729d9c0f9185ffb4a bootstrap_state.py
c4a2a1010392249dec8de68fc89def5935440df18c5c7c24a79be87763708806 ssh_bootstrap.py
正式接口验证
通过 https://api.synaglobal.vip 调用 POST /api/btpanel/servers/395/login-url 验证成功:
auth_status: HTTP/1.1 200 OK
login_url_status: HTTP/1.1 200 OK
method: api
bootstrapped: false
url_sanitized: https://42.193.182.190:31701/login?tmp_token=***
正式接口返回的非敏感诊断字段:
{
"client_hash_risk": false,
"panel_ssl": true,
"session_cleanup_ttl_checked_at": "2026-07-07T07:35:19Z",
"session_cleanup_ttl_last_error": null,
"session_cleanup_ttl_ok": true,
"session_cleanup_ttl_patched": false,
"temp_login_ttl_seconds": 86400
}
说明:
temp_login_ttl_seconds=86400:Nexus 一键登录临时链接仍是 24 小时。panel_ssl=true且client_hash_risk=false:当前正式记录里这台宝塔面板已检测到面板 SSL 开启,因此“未开启 SSL 导致 tmp_login 绑定来源 IP”的风险在这次返回里不成立。session_cleanup_ttl_ok=true:宝塔会话清理阈值检查成功。session_cleanup_ttl_patched=false:表示本次检查没有新改动task.py;不是失败。是否已经被旧补丁覆盖,要结合session_cleanup_ttl_ok和目标机源码再判断。
风险与后续
本次只是正式容器热更新,不是镜像固化发布。后续如果 1Panel/Docker 重新构建或重新拉镜像,这 3 个文件可能被镜像内容覆盖;建议下一步按正式发布流程把提交 b5aaf5a feat: add btpanel login diagnostics 合入正式镜像构建链路。
当前现网诊断结果显示 42.193.182.190 这台宝塔的 panel_ssl=true、client_hash_risk=false,如果用户仍复现“多开 10 个宝塔,约 2 小时后刷新陆续掉线”,下一步应优先抓以下现场:
- 掉线前后重新调用
login-url,比较diagnostics是否变化。 - 在宝塔机上检查 session 文件创建/删除时间和
request.remote_addr来源变化。 - 检查浏览器/代理/反代是否对不同标签页或不同时间切换出口。
- 检查宝塔自身是否还有其它 session 清理逻辑或安全插件清理逻辑。
- 检查 Nexus 返回的
method是否一直为api,是否在某些机器上触发 SSH bootstrap 或 fallback。