fix: 保留 Sub2API 重装时的凭证配置

- 生成持久化 .env 文件,用于保存数据库凭证、密钥、时区和初始管理员账户
- 优先复用已有 .env,并尽量迁移旧 compose 中的明文 Postgres 凭证
- 更新 docker-compose.yml,改为环境变量驱动初始化,并加入健康检查和 AUTO_SETUP
- 调整重装/更新提示,明确保留现有数据与凭证配置
This commit is contained in:
eddy
2026-07-05 04:48:31 +08:00
parent 82b0e53d85
commit 6b7a786ddf
+103 -20
View File
@@ -9,6 +9,7 @@ port80=8230
# 安装目录与更新脚本路径 # 安装目录与更新脚本路径
install_dir=/root/data/docker_data/Sub2API install_dir=/root/data/docker_data/Sub2API
update_script="$install_dir/auto-update.sh" update_script="$install_dir/auto-update.sh"
env_file="$install_dir/.env"
# 交互:已有安装时默认只更新,避免覆盖数据库账号、密码和连接配置 # 交互:已有安装时默认只更新,避免覆盖数据库账号、密码和连接配置
existing_install=0 existing_install=0
@@ -19,7 +20,7 @@ fi
echo "请选择操作:" echo "请选择操作:"
if [ "$existing_install" -eq 1 ]; then if [ "$existing_install" -eq 1 ]; then
echo " 1) 已安装,仅更新 Sub2API app 镜像(默认,安全,不覆盖配置/数据库)" echo " 1) 已安装,仅更新 Sub2API app 镜像(默认,安全,不覆盖配置/数据库)"
echo " 2) 强制重装 Sub2API危险,会重写 docker-compose.yml" echo " 2) 强制重装 Sub2API(重写 docker-compose.yml,保留 .env 与数据目录"
else else
echo " 1) 安装 Sub2API(默认)" echo " 1) 安装 Sub2API(默认)"
echo " 2) 不安装,立即执行 Docker 更新" echo " 2) 不安装,立即执行 Docker 更新"
@@ -55,7 +56,7 @@ fi
if [ "$existing_install" -eq 1 ] && [ "$action_choice" = "2" ]; then if [ "$existing_install" -eq 1 ] && [ "$action_choice" = "2" ]; then
echo "检测到已有 Sub2API 安装:$install_dir/docker-compose.yml" echo "检测到已有 Sub2API 安装:$install_dir/docker-compose.yml"
echo "强制重装会覆盖 docker-compose.yml,可能导致数据库账号密码或连接配置被重置。" echo "强制重装会重写 docker-compose.yml.env 与 data/ 数据目录会保留,原管理员账号密码继续有效)。"
read -r -p "如确需重装,请输入 REINSTALL 确认:" reinstall_confirm read -r -p "如确需重装,请输入 REINSTALL 确认:" reinstall_confirm
if [ "$reinstall_confirm" != "REINSTALL" ]; then if [ "$reinstall_confirm" != "REINSTALL" ]; then
echo "未确认强制重装,已退出。原有配置未修改。" echo "未确认强制重装,已退出。原有配置未修改。"
@@ -70,10 +71,62 @@ apt update -y || true
apt upgrade -y || true #更新一下包 apt upgrade -y || true #更新一下包
# 2、创建安装目录 # 2、创建安装目录
mkdir -p /root/data/docker_data/Sub2API mkdir -p "$install_dir"
cd /root/data/docker_data/Sub2API || { echo "无法进入安装目录 /root/data/docker_data/Sub2API" >&2; exit 1; } cd "$install_dir" || { echo "无法进入安装目录 $install_dir" >&2; exit 1; }
# 3、填写docker-compose配置 # 3、生成 .env(仅首次生成,重装/更新不覆盖,避免密钥和数据库密码变化)
gen_secret() {
openssl rand -hex 32 2>/dev/null || head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \n'
}
if [ ! -f "$env_file" ]; then
# 兼容旧版安装:尝试从旧 docker-compose.yml 中提取已在用的数据库密码,
# 避免生成新密码后与已有 postgres 数据目录不一致导致连不上库
old_pg_password=""
old_pg_user=""
if [ -f docker-compose.yml ]; then
# grep -v '\$' 排除新版 compose 中的 ${VAR} 占位符,只取旧版明文值
old_pg_password=$(sed -n 's/.*POSTGRES_PASSWORD=\([^ #]*\).*/\1/p' docker-compose.yml | grep -v '\$' | head -n1 || true)
old_pg_user=$(sed -n 's/.*POSTGRES_USER=\([^ #]*\).*/\1/p' docker-compose.yml | grep -v '\$' | head -n1 || true)
fi
pg_password="${old_pg_password:-$(gen_secret)}"
pg_user="${old_pg_user:-postgres}"
# 交互:设置管理员账号密码(仅数据库首次初始化时生效;
# 如果数据库已有数据,登录仍用数据库里已存在的账号密码)
default_admin_email="admin@sub2api.local"
default_admin_password=$(gen_secret | cut -c1-16)
echo "配置管理员账户(仅数据库首次初始化时创建):"
read -r -p "管理员邮箱(默认 $default_admin_email):" admin_email
admin_email="${admin_email:-$default_admin_email}"
read -r -p "管理员密码(回车使用随机密码 $default_admin_password):" admin_password
admin_password="${admin_password:-$default_admin_password}"
cat <<EOF > "$env_file"
# Sub2API 环境配置(由安装脚本生成,请勿删除,否则需重新配置)
# 数据库
POSTGRES_USER=$pg_user
POSTGRES_PASSWORD=$pg_password
POSTGRES_DB=sub2api
# 固定密钥:保证容器重建/更新后登录态和 2FA 不失效
JWT_SECRET=$(gen_secret)
TOTP_ENCRYPTION_KEY=$(gen_secret)
# 管理员账户(仅首次启动时创建,之后修改无效)
ADMIN_EMAIL=$admin_email
ADMIN_PASSWORD=$admin_password
TZ=Asia/Shanghai
EOF
chmod 600 "$env_file"
echo "已生成 $env_file(包含数据库密码、密钥和管理员初始密码,请妥善保管)。"
else
echo "检测到已有 $env_file,沿用原有管理员账号密码与数据库配置,不再询问。"
fi
# 4、填写docker-compose配置
# AUTO_SETUP=true + 环境变量传入数据库/Redis 配置,容器重建后无需再走网页安装向导
cat <<EOF > docker-compose.yml cat <<EOF > docker-compose.yml
services: services:
db: db:
@@ -83,9 +136,15 @@ services:
volumes: volumes:
- ./data/postgres:/var/lib/postgresql/data - ./data/postgres:/var/lib/postgresql/data
environment: environment:
- POSTGRES_PASSWORD=changeme # 改成你自己的密码 - POSTGRES_USER=\${POSTGRES_USER:-postgres}
- POSTGRES_USER=postgres # 改成你自己的用户名 - POSTGRES_PASSWORD=\${POSTGRES_PASSWORD:?POSTGRES_PASSWORD 未配置,请检查 .env}
- POSTGRES_DB=sub2api - POSTGRES_DB=\${POSTGRES_DB:-sub2api}
- TZ=\${TZ:-Asia/Shanghai}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U \${POSTGRES_USER:-postgres} -d \${POSTGRES_DB:-sub2api}"]
interval: 10s
timeout: 5s
retries: 5
redis: redis:
image: redis:7-alpine image: redis:7-alpine
@@ -93,27 +152,50 @@ services:
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- ./data/redis:/data - ./data/redis:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
app: app:
image: weishaw/sub2api:latest image: weishaw/sub2api:latest
container_name: sub2api-app container_name: sub2api-app
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- ./data/app:/app/data # 持久化 app 配置/数据,避免更新后丢失需要重新配置 - ./data/app:/app/data # 持久化 app 配置/数据
ports: ports:
- "$port80:8080" # 左边的端口可以更换,右边不要动! - "$port80:8080" # 左边的端口可以更换,右边不要动!
depends_on: depends_on:
- db db:
- redis condition: service_healthy
redis:
condition: service_healthy
environment: environment:
# 自动初始化:跳过网页安装向导,配置全部来自环境变量(.env)
- AUTO_SETUP=true
- SERVER_HOST=0.0.0.0
- SERVER_PORT=8080 # 必须与 ports 右边的容器端口一致
- SERVER_MODE=release
# 主机用容器服务名 db / redis,不要写宿主机 IP # 主机用容器服务名 db / redis,不要写宿主机 IP
- DATABASE_URL=postgres://postgres:changeme@db:5432/sub2api?sslmode=disable # 用户名/密码/库名要与上面 db 对应! - DATABASE_HOST=db
- REDIS_URL=redis://redis:6379 - DATABASE_PORT=5432
- SERVER_PORT=8080 # 镜像用的是 SERVER_PORT,必须与 ports 右边的容器端口一致 - DATABASE_USER=\${POSTGRES_USER:-postgres}
- GIN_MODE=release - DATABASE_PASSWORD=\${POSTGRES_PASSWORD}
- DATABASE_DBNAME=\${POSTGRES_DB:-sub2api}
- DATABASE_SSLMODE=disable
- REDIS_HOST=redis
- REDIS_PORT=6379
# 固定密钥(来自 .env):更新/重启后登录态和 2FA 不失效
- JWT_SECRET=\${JWT_SECRET}
- TOTP_ENCRYPTION_KEY=\${TOTP_ENCRYPTION_KEY}
# 管理员账户仅首次启动时创建
- ADMIN_EMAIL=\${ADMIN_EMAIL:-admin@sub2api.local}
- ADMIN_PASSWORD=\${ADMIN_PASSWORD:-}
- TZ=\${TZ:-Asia/Shanghai}
EOF EOF
# 4、安装 # 5、安装
if ! command -v docker >/dev/null 2>&1; then if ! command -v docker >/dev/null 2>&1; then
echo "未检测到 docker,请先安装 Docker 后再运行本脚本。" >&2 echo "未检测到 docker,请先安装 Docker 后再运行本脚本。" >&2
exit 1 exit 1
@@ -128,7 +210,7 @@ else
exit 1 exit 1
fi fi
# 5、打开防火墙的端口 # 6、打开防火墙的端口
if command -v ufw >/dev/null 2>&1; then if command -v ufw >/dev/null 2>&1; then
ufw allow "$port80" ufw allow "$port80"
ufw status ufw status
@@ -136,7 +218,7 @@ else
echo "未检测到 ufw,跳过防火墙端口放行。" echo "未检测到 ufw,跳过防火墙端口放行。"
fi fi
# 6、配置每日自动更新 # 7、配置每日自动更新
cat <<'EOF' > "$update_script" cat <<'EOF' > "$update_script"
#!/bin/bash #!/bin/bash
set -euo pipefail set -euo pipefail
@@ -178,9 +260,10 @@ fi
echo "------------------------" echo "------------------------"
echo "访问链接:" echo "访问链接:"
echo "https://sub2api.ghuang.top" echo "https://sub2api.ghuang.top"
echo "User: admin@localhost" echo "管理员账户(首次安装时自动创建,凭证保存在 $env_file):"
echo "Password: admin" grep -E '^(ADMIN_EMAIL|ADMIN_PASSWORD)=' "$env_file" || true
echo "------------------------" echo "------------------------"
echo "已启用 AUTO_SETUP 自动初始化:更新/重建容器后无需重新走网页安装向导。"
echo "已开启定时自动更新:每天 04:00 仅拉取最新 app 镜像并重启(db / redis 不动)。" echo "已开启定时自动更新:每天 04:00 仅拉取最新 app 镜像并重启(db / redis 不动)。"
echo "手动更新可执行:$update_script" echo "手动更新可执行:$update_script"
echo "------------------------" echo "------------------------"