@@ -1,91 +1,128 @@
#!/bin/bash
set -e
SCRIPT_DIR = " $( cd " $( dirname " $0 " ) " && pwd ) "
cd " $SCRIPT_DIR "
# CloudSearch 一键部署
# curl -sS https://gitea.timxx.cn/admin/CloudSearch/raw/branch/master/source_clean/deploy.sh | bash
#
# 环境变量(可选):
# CORS_ORIGIN - 域名 (默认自动检测公网IP)
# ADMIN_PASSWORD - 管理员密码 (留空自动生成)
# JWT_SECRET - JWT密钥 (留空自动生成)
# DEPLOY_DIR - 部署目录 (默认 /opt/cloudsearch)
# 如果 docker-compose.yml 不存在,自动下载
if [ ! -f docker-compose.yml ] ; then
echo "📥 下载 docker-compose.yml..."
wget -q https://gitea.timxx.cn/admin/CloudSearch/raw/branch/master/source_clean/docker-compose.yml || {
echo "❌ 下载失败,请检查网络"
exit 1
}
REPO_URL = "https://gitea.timxx.cn/admin/CloudSearch.git"
DEPLOY_DIR = " ${ DEPLOY_DIR :- /opt/cloudsearch } "
info( ) { echo " [INFO] $* " ; }
warn( ) { echo " [WARN] $* " ; }
err( ) { echo " [ERROR] $* " ; }
command -v docker & >/dev/null || { err "Docker未安装" ; exit 1; }
# -- CORS_ORIGIN --
if [ -z " $CORS_ORIGIN " ] ; then
PUBLIC_IP = $( curl -s --connect-timeout 3 ifconfig.me 2>/dev/null || curl -s --connect-timeout 3 ip.sb 2>/dev/null || echo "" )
if [ -n " $PUBLIC_IP " ] ; then
CORS_ORIGIN = " http:// ${ PUBLIC_IP } :9527 "
else
CORS_ORIGIN = "http://localhost:9527"
fi
warn " CORS_ORIGIN= $CORS_ORIGIN (自动检测) "
fi
echo "🔍 检测 Redis..."
EXISTING_REDIS = $( docker ps --format '{{.Names}}' | grep -i redis | head -1)
if [ -n " $EXISTING_REDIS " ] ; then
if docker network inspect cloudsearch-net --format '{{range .Containers}}{{.Name}} {{end}}' 2>/dev/null | grep -qw " $EXISTING_REDIS " ; then
echo " ✅ 已有 Redis: $EXISTING_REDIS (已加入 cloudsearch-net),跳过创建 "
else
echo " ✅ 已有 Redis: $EXISTING_REDIS ,正在加入网络... "
docker network connect cloudsearch-net " $EXISTING_REDIS " 2>/dev/null || true
echo " ✅ 已加入 cloudsearch-net"
fi
# 检测 Redis 密码 (多种来源)
REDIS_PASS = ""
# 方法1: 从命令行参数 --requirepass
PASS_FROM_CMD = $( docker inspect " $EXISTING_REDIS " --format '{{range .Config.Cmd}}{{println .}}{{end}}' 2>/dev/null | grep -A1 'requirepass' | tail -1 | tr -d '[:space:]' || true )
if [ -n " $PASS_FROM_CMD " ] && [ " $PASS_FROM_CMD " != "redis-server" ] && [ " $PASS_FROM_CMD " != "/etc/redis/redis.conf" ] ; then
REDIS_PASS = " $PASS_FROM_CMD "
echo " 🔑 从启动参数检测到 Redis 密码"
fi
# 方法2: 从 redis.conf 读取 (1Panel 常见配置方式)
if [ -z " $REDIS_PASS " ] ; then
PASS_FROM_CONF = $( docker exec " $EXISTING_REDIS " cat /etc/redis/redis.conf 2>/dev/null | grep '^requirepass ' | awk '{print $2}' | tr -d '"' || true )
if [ -n " $PASS_FROM_CONF " ] ; then
REDIS_PASS = " $PASS_FROM_CONF "
echo " 🔑 从 redis.conf 检测到 Redis 密码"
fi
fi
# 方法3: 尝试无密码连接测试
if [ -z " $REDIS_PASS " ] ; then
if docker exec " $EXISTING_REDIS " redis-cli ping 2>/dev/null | grep -q PONG; then
echo " ℹ ️ Redis 无密码(已通过连接测试验证)"
else
# 有密码但检测不到 — 尝试从 redis-cli 的错误消息中提取
AUTH_ERR = $( docker exec " $EXISTING_REDIS " redis-cli ping 2>& 1 || true )
if echo " $AUTH_ERR " | grep -q "NOAUTH\|AUTH" ; then
echo " ⚠️ Redis 需要密码但无法自动检测,请手动设置 REDIS_URL"
echo " 提示: 在 .env 中设置 REDIS_URL=redis://:密码@ ${ EXISTING_REDIS } :6379 "
fi
fi
fi
if [ -n " $REDIS_PASS " ] ; then
# 对密码中的特殊字符进行URL编码
ENCODED_PASS = $( python3 -c " import urllib.parse; print(urllib.parse.quote(' $REDIS_PASS ', safe='')) " 2>/dev/null || echo " $REDIS_PASS " )
REDIS_URL = " redis://: ${ ENCODED_PASS } @ ${ EXISTING_REDIS } :6379 "
else
REDIS_URL = " redis:// ${ EXISTING_REDIS } :6379 "
fi
PROFILE = ""
# -- 拉取仓库 --
info "拉取仓库..."
if [ -d " $DEPLOY_DIR /.git " ] ; then
cd " $DEPLOY_DIR " && git pull --ff-only origin master 2>/dev/null || true
else
echo "📦 未检测到 Redis, 将自动创建... "
REDIS_URL = "redis://CloudSearch_Redis:6379 "
PROFILE = "--profile full"
rm -rf " $DEPLOY_DIR "
git clone --depth 1 " $REPO_URL " " $DEPLOY_DIR "
fi
cd " $DEPLOY_DIR /source_clean "
# -- 切换镜像模式 --
if grep -q '^ build:' docker-compose.yml 2>/dev/null; then
info "切换镜像模式..."
sed -i 's/^ build:/ # build:/' docker-compose.yml
sed -i 's/^ context:/ # context:/' docker-compose.yml
sed -i 's/^ dockerfile:/ # dockerfile:/' docker-compose.yml
sed -i 's|^ # image: gitea.timxx.cn/admin/cloudsearch:latest| image: gitea.timxx.cn/admin/cloudsearch:latest|' docker-compose.yml
fi
# 生成 .env
cat > .env <<EOF
# -- 检测 Redis --
info "检测Redis..."
EXISTING_REDIS = $( docker ps --format '{{.Names}}' 2>/dev/null | grep -i redis | grep -v CloudSearch | head -1)
if [ -n " $EXISTING_REDIS " ] ; then
REDIS_URL = " redis:// ${ EXISTING_REDIS } :6379 "
info " 复用已有Redis: $EXISTING_REDIS "
else
REDIS_URL = "redis://redis:6379"
info "使用Compose自带Redis"
fi
# -- 生成密钥 --
JWT_SECRET = " ${ JWT_SECRET :- $( openssl rand -hex 32) } "
ADMIN_PASSWORD = " ${ ADMIN_PASSWORD :- $( openssl rand -base64 12 | tr -d '=+/' | head -c 16) } "
# -- 生成 .env --
cat > .env <<ENVEOF
CORS_ORIGIN=${CORS_ORIGIN}
JWT_SECRET=${JWT_SECRET}
ADMIN_PASSWORD=${ADMIN_PASSWORD}
REDIS_URL=${REDIS_URL}
CORS_ORIGIN=https://zy.hk.timxx.cn
JWT_SECRET=cloudsearch-jwt-secret-2024
ADMIN_PASSWORD=0nL5kLhMIJ1121PYmQb25A
LOG_LEVEL=info
EOF
LOG_LEVEL=${LOG_LEVEL:-info}
ENVEOF
echo " "
echo "🚀 启动服务..."
docker compose $PROFILE up -d
info " 管理员: admin / ${ ADMIN_PASSWORD } "
echo ""
echo "✅ 部署完成 "
docker compose ps
# -- 部署 --
info "拉取镜像... "
docker compose pull app 2>/dev/null || true
info "停止旧服务..."
docker compose down --remove-orphans 2>/dev/null || true
info "启动服务..."
docker compose up -d
# -- 等待就绪 --
info "等待服务就绪..."
for i in $( seq 1 20) ; do
if curl -s -o /dev/null -w '%{http_code}' http://localhost:9527/health 2>/dev/null | grep -q '200' ; then
break
fi
sleep 2
done
# -- 强制写入管理员密码 --
info "同步管理员密码..."
sleep 3
docker exec CloudSearch_App node -e '
var bcrypt = require("bcryptjs");
var Database = require("better-sqlite3");
var db = new Database("/data/database.sqlite");
var hash = bcrypt.hashSync("' " ${ ADMIN_PASSWORD } " '", 10);
var existing = db.prepare("SELECT id FROM admins WHERE username = ?").get("admin");
if (existing) {
db.prepare("UPDATE admins SET password_hash = ? WHERE username = ?").run(hash, "admin");
} else {
db.prepare("INSERT INTO admins (username, password_hash) VALUES (?, ?)").run("admin", hash);
}
db.close();
' 2>/dev/null && info "密码已同步" || warn "密码同步失败,请稍后重试"
# -- 验证 --
if docker compose ps 2>/dev/null | grep -q 'Up' ; then
echo ""
echo "=============================================="
echo " CloudSearch 部署完成"
echo "=============================================="
docker compose ps
echo ""
echo " 管理后台: ${ CORS_ORIGIN } /admin/login "
echo " 用户名: admin"
echo " 密码: ${ ADMIN_PASSWORD } "
else
err "启动失败: docker compose logs"
exit 1
fi