fix(install): auto-resolve 1Panel Redis auth (:pass@ / default)

Stop prefilling root; probe multiple Redis URL formats on credential
check and persist the URL that works for init-db.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Nexus Deploy
2026-06-06 07:15:57 +08:00
parent 9d9fbc62f5
commit 3b2856f388
7 changed files with 126 additions and 26 deletions
+50 -11
View File
@@ -243,8 +243,9 @@ def _mysql_connect_error_detail(host: str, port: int) -> str:
def _redis_auth_error_detail() -> str:
if os.environ.get("NEXUS_DOCKER_WRITE_ENV") == "1":
return (
"Redis 认证失败。1Panel Redis:用户名填 root密码应用参数中的随机密码"
"主机为 1Panel-redis-xxxx(不是 127.0.0.1)。无 ACL 的旧版 Redis 用户名可留空"
"Redis 认证失败。1Panel:主机 1Panel-redis-xxxx密码应用参数;"
"用户名通常留空(自动尝试 :pass@)或填 default。勿填 root(多数实例不支持)"
"诊断: bash deploy/test-1panel-redis.sh"
)
return "Redis 密码错误或需要 AUTH;请核对用户名/密码(无密码则留空)。"
@@ -337,6 +338,42 @@ def _test_redis_url(redis_url: str) -> tuple[bool, str]:
return False, f"✗ Redis 连接失败: {e}"
def _redis_url_candidates(req: InitDbRequest) -> list[tuple[str, str]]:
"""Try order for 1Panel Redis (default user vs :pass@ vs explicit user)."""
password = (req.redis_pass or "").strip()
if not password:
return [("无密码", _build_redis_url(req))]
user = (req.redis_user or "").strip()
seen: set[str] = set()
out: list[tuple[str, str]] = []
def add(label: str, candidate: InitDbRequest) -> None:
url = _build_redis_url(candidate)
if url in seen:
return
seen.add(url)
out.append((label, url))
if user:
add(f"用户 {user}", req)
add("仅密码 (:pass@)", req.model_copy(update={"redis_user": ""}))
if user.lower() != "default":
add("用户 default", req.model_copy(update={"redis_user": "default"}))
return out
def _resolve_redis_url(req: InitDbRequest) -> tuple[bool, str, str | None]:
"""Pick first working Redis URL among 1Panel-compatible auth variants."""
last_msg = "✗ 未配置 Redis"
for label, url in _redis_url_candidates(req):
ok, msg = _test_redis_url(url)
last_msg = msg
if ok:
return True, f"✓ Redis 连接正常({label}", url
return False, last_msg, None
def _docker_wizard_defaults() -> dict[str, str] | None:
"""Prefill install step 3 when running inside docker-compose.prod.yml."""
if os.environ.get("NEXUS_DOCKER_WRITE_ENV") != "1":
@@ -351,7 +388,6 @@ def _docker_wizard_defaults() -> dict[str, str] | None:
"redis_host": redis_host,
"redis_port": "6379",
"redis_db": "0",
"redis_user": "root",
}
@@ -715,17 +751,16 @@ async def env_check():
return payload
async def _credential_checks(req: InitDbRequest) -> tuple[list[dict], bool]:
async def _credential_checks(req: InitDbRequest) -> tuple[list[dict], bool, str | None]:
"""Verify MySQL + Redis with credentials from install step 3 (TCP + AUTH)."""
db_url = _make_db_url(req)
redis_url = _build_redis_url(req)
mysql_ok, mysql_msg = await _test_mysql_url(db_url)
redis_ok, redis_msg = _test_redis_url(redis_url)
redis_ok, redis_msg, redis_url = _resolve_redis_url(req)
checks = [
{"name": "MySQL", "required": "可连接", "current": mysql_msg, "pass": mysql_ok},
{"name": "Redis", "required": "可连接", "current": redis_msg, "pass": redis_ok},
]
return checks, mysql_ok and redis_ok
return checks, mysql_ok and redis_ok, redis_url if redis_ok else None
@router.post("/test-credentials")
@@ -737,8 +772,11 @@ async def test_credentials(req: InitDbRequest):
400,
"系统已初始化,无法重复检测。请继续步骤 4 创建管理员,或修正 .env 后使用连接检测。",
)
checks, all_pass = await _credential_checks(req)
return {"checks": checks, "all_pass": all_pass}
checks, all_pass, redis_url = await _credential_checks(req)
payload: dict = {"checks": checks, "all_pass": all_pass}
if redis_url:
payload["resolved_redis_url"] = redis_url
return payload
@router.get("/connection-check")
@@ -768,16 +806,17 @@ async def init_db(req: InitDbRequest):
_reject_if_env_exists()
db_url = _make_db_url(req)
redis_url = _build_redis_url(req)
site_url = req.site_url.rstrip("/") if req.site_url else f"http://127.0.0.1:{req.api_port}"
checks, cred_ok = await _credential_checks(req)
checks, cred_ok, redis_url = await _credential_checks(req)
if not cred_ok:
failed = next((c for c in checks if not c["pass"]), checks[0])
raise HTTPException(
400,
failed.get("current") or "MySQL 或 Redis 连接未通过,请先检测账号密码",
)
if not redis_url:
redis_url = _build_redis_url(req)
try:
patch_aiomysql_do_ping()