feat(install): per-host auto-generated secrets for Docker installs

Each fresh 1Panel/Docker install generates unique MYSQL and NEXUS keys
via scripts/generate_nexus_secrets.py; install wizard reuses compose env.
This commit is contained in:
Nexus Deploy
2026-06-06 00:25:57 +08:00
parent e613aecc8e
commit 83ce11f55c
14 changed files with 431 additions and 89 deletions
+74 -42
View File
@@ -50,6 +50,7 @@ step() { echo -e "${CYAN}[STEP]${NC} $*"; }
SKIP_CLONE=false
FRESH_INSTALL=false
REUSE_SECRETS=false
FROM_ENV="${NEXUS_FROM_ENV}"
NO_BACKUP=false
PRUNE_IMAGES=false
@@ -74,8 +75,9 @@ Nexus 1Panel 一键脚本
安装选项:
--skip-clone 已在 /opt/nexus,仅 pull
--fresh 全新安装(/app/install.html
--from-env PATH 从旧 .env 导入密钥
--fresh 全新安装(本机自动生成唯一密钥 + /app/install.html
--from-env PATH 从旧 .env 迁机导入密钥
--reuse-secrets 使用 secrets 文件中的 NEXUS 密钥(勿用于新机)
--domain NAME 覆盖域名
升级选项:
@@ -128,6 +130,10 @@ load_secrets() {
info "已加载 $NEXUS_DEPLOY_ENV"
fi
load_token_from_git_remote "$NEXUS_ROOT"
if [[ "$FRESH_INSTALL" == true ]]; then
unset NEXUS_SECRET_KEY NEXUS_API_KEY NEXUS_ENCRYPTION_KEY
info "全新安装:忽略 secrets 中的 NEXUS 密钥,将为本机自动生成"
fi
}
resolve_profile() {
@@ -443,15 +449,35 @@ clone_or_pull() {
git -C "$NEXUS_ROOT" checkout "$GIT_BRANCH" 2>/dev/null || true
}
write_temp_secrets_env() {
local f
f="$(mktemp /tmp/nexus-secrets-import.XXXXXX.env)"
{
printf 'MYSQL_ROOT_PASSWORD=%s\n' "${MYSQL_ROOT_PASSWORD:-$(rand_pass)}"
printf 'MYSQL_PASSWORD=%s\n' "${MYSQL_PASSWORD:-$(rand_pass)}"
printf 'NEXUS_SECRET_KEY=%s\n' "$NEXUS_SECRET_KEY"
printf 'NEXUS_API_KEY=%s\n' "$NEXUS_API_KEY"
printf 'NEXUS_ENCRYPTION_KEY=%s\n' "$NEXUS_ENCRYPTION_KEY"
} >"$f"
chmod 600 "$f"
echo "$f"
}
write_env_prod() {
local root="$1"
local env_file="$root/$ENV_PROD"
local example="$root/docker/.env.prod.example"
local gen="$root/scripts/generate_nexus_secrets.py"
local prof backup tmp
if [[ ! -f "$example" ]]; then
error "缺少 $example"
exit 1
fi
if [[ ! -f "$gen" ]]; then
error "缺少 $gen"
exit 1
fi
if [[ -f "$env_file" ]]; then
warn "$env_file 已存在,仅更新域名与连接池"
@@ -462,53 +488,58 @@ write_env_prod() {
return 0
fi
local mysql_root mysql_pass secret api enc
mysql_root="$(rand_pass)"
mysql_pass="$(rand_pass)"
prof="$(profile_env_file "$root")"
backup="/root/.nexus-install-secrets-$(date +%Y%m%d%H%M%S).env"
if [[ -n "$FROM_ENV" && -f "$FROM_ENV" ]]; then
info "$FROM_ENV 导入密钥..."
secret="$(read_env_val "$FROM_ENV" NEXUS_SECRET_KEY)"
api="$(read_env_val "$FROM_ENV" NEXUS_API_KEY)"
enc="$(read_env_val "$FROM_ENV" NEXUS_ENCRYPTION_KEY)"
local old_root old_pass dburl
old_root="$(read_env_val "$FROM_ENV" MYSQL_ROOT_PASSWORD)"
old_pass="$(read_env_val "$FROM_ENV" MYSQL_PASSWORD)"
[[ -n "$old_root" ]] && mysql_root="$old_root"
[[ -n "$old_pass" ]] && mysql_pass="$old_pass"
if [[ -z "$old_pass" ]]; then
dburl="$(read_env_val "$FROM_ENV" NEXUS_DATABASE_URL)"
if [[ "$dburl" =~ [Nn]exus:([^@]+)@ ]]; then
mysql_pass="${BASH_REMATCH[1]}"
fi
fi
info "迁机:$FROM_ENV 导入密钥..."
python3 "$gen" write-prod \
--template "$example" \
--output "$env_file" \
--domain "$NEXUS_DOMAIN" \
--profile-env "$prof" \
--from-env "$FROM_ENV" \
--backup "$backup"
elif [[ "$FRESH_INSTALL" == true ]]; then
secret=""
api=""
enc=""
info "全新安装:完成后访问 https://${NEXUS_DOMAIN}/app/install.html"
elif [[ -n "${NEXUS_SECRET_KEY:-}" ]]; then
secret="$NEXUS_SECRET_KEY"
api="${NEXUS_API_KEY:-}"
enc="${NEXUS_ENCRYPTION_KEY:-}"
info "使用 secrets 文件中的生产 NEXUS 密钥(Docker MySQL 密码为新生成)"
info "全新安装:为本机生成唯一 MYSQL / NEXUS 密钥..."
python3 "$gen" write-prod \
--template "$example" \
--output "$env_file" \
--domain "$NEXUS_DOMAIN" \
--profile-env "$prof" \
--fresh \
--wizard-pending \
--backup "$backup"
info "密钥备份: $backup(仅本机,勿复制到其他服务器)"
info "完成后访问 https://${NEXUS_DOMAIN}/app/install.html"
elif [[ "$REUSE_SECRETS" == true && -n "${NEXUS_SECRET_KEY:-}" && -n "${NEXUS_API_KEY:-}" && -n "${NEXUS_ENCRYPTION_KEY:-}" ]]; then
warn "使用 secrets 中的 NEXUS 密钥(仅迁机/复用,新机勿用 --reuse-secrets"
tmp="$(write_temp_secrets_env)"
python3 "$gen" write-prod \
--template "$example" \
--output "$env_file" \
--domain "$NEXUS_DOMAIN" \
--profile-env "$prof" \
--from-env "$tmp" \
--backup "$backup"
rm -f "$tmp"
else
secret="$(rand_secret)"
api="$(rand_secret)"
enc=""
warn "已生成随机 NEXUS 密钥(仅适合测试)"
info "未迁机导入:为本机生成唯一密钥..."
python3 "$gen" write-prod \
--template "$example" \
--output "$env_file" \
--domain "$NEXUS_DOMAIN" \
--profile-env "$prof" \
--fresh \
--wizard-pending \
--backup "$backup"
info "密钥备份: $backup"
if [[ "$FRESH_INSTALL" != true ]]; then
info "完成后访问 https://${NEXUS_DOMAIN}/app/install.html"
fi
fi
cp "$example" "$env_file"
chmod 600 "$env_file"
sed -i "s|^MYSQL_ROOT_PASSWORD=.*|MYSQL_ROOT_PASSWORD=${mysql_root}|" "$env_file"
sed -i "s|^MYSQL_PASSWORD=.*|MYSQL_PASSWORD=${mysql_pass}|" "$env_file"
sed -i "s|^NEXUS_SECRET_KEY=.*|NEXUS_SECRET_KEY=${secret}|" "$env_file"
sed -i "s|^NEXUS_API_KEY=.*|NEXUS_API_KEY=${api}|" "$env_file"
sed -i "s|^NEXUS_ENCRYPTION_KEY=.*|NEXUS_ENCRYPTION_KEY=${enc}|" "$env_file"
sed -i "s|^NEXUS_CORS_ORIGINS=.*|NEXUS_CORS_ORIGINS=https://${NEXUS_DOMAIN}|" "$env_file"
sed -i "s|^NEXUS_API_BASE_URL=.*|NEXUS_API_BASE_URL=https://${NEXUS_DOMAIN}|" "$env_file"
apply_pool_to_env_prod "$root" "$(profile_env_file "$root")"
info "已写入 $env_file"
}
@@ -715,6 +746,7 @@ parse_common_install() {
-h|--help) usage ;;
--skip-clone) SKIP_CLONE=true; shift ;;
--fresh) FRESH_INSTALL=true; shift ;;
--reuse-secrets) REUSE_SECRETS=true; shift ;;
--profile) NEXUS_PROFILE="$2"; shift 2 ;;
--cpus) CUSTOM_CPUS="$2"; shift 2 ;;
--mem-gb|--memory-gb) CUSTOM_MEM_GB="$2"; shift 2 ;;