245 lines
10 KiB
Bash
245 lines
10 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
REPO="ssomvk/sso-service"
|
|
BRANCH="main"
|
|
INSTALL_DIR="${INSTALL_DIR:-$HOME/sso-service}"
|
|
SKIP_PREREQS="${SKIP_PREREQS:-false}"
|
|
|
|
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
|
|
info() { echo -e "${GREEN}✔${NC} $1"; }
|
|
warn() { echo -e "${YELLOW}⚠${NC} $1"; }
|
|
error() { echo -e "${RED}✘${NC} $1"; exit 1; }
|
|
step() { echo -e "\n${CYAN}━━━ $1 ━━━${NC}"; }
|
|
|
|
echo -e "${CYAN}"
|
|
echo " ╔══════════════════════════════════════════════╗"
|
|
echo " ║ SSO Service — Auto Installer ║"
|
|
echo " ║ https://github.com/${REPO} ║"
|
|
echo " ╚══════════════════════════════════════════════╝"
|
|
echo -e "${NC}"
|
|
|
|
# ─── Проверка root ──────────────────────────────────────────────
|
|
if [ "$(id -u)" -eq 0 ]; then
|
|
SUDO=""
|
|
else
|
|
SUDO="sudo"
|
|
fi
|
|
|
|
# ─── Detecting OS ────────────────────────────────────────────────
|
|
step "Detecting operating system"
|
|
OS=""
|
|
if [ -f /etc/os-release ]; then
|
|
. /etc/os-release
|
|
OS="$ID"
|
|
elif command -v lsb_release &>/dev/null; then
|
|
OS="$(lsb_release -si | tr '[:upper:]' '[:lower:]')"
|
|
else
|
|
OS="$(uname -s)"
|
|
fi
|
|
info "Detected: ${OS} ($(uname -m))"
|
|
|
|
# ─── 1. Docker ──────────────────────────────────────────────────
|
|
install_docker() {
|
|
step "1/8 Installing Docker"
|
|
if command -v docker &>/dev/null; then
|
|
info "Docker already installed ($(docker --version))"
|
|
else
|
|
warn "Docker not found — installing..."
|
|
if command -v apt-get &>/dev/null; then
|
|
curl -fsSL https://get.docker.com | $SUDO sh
|
|
elif command -v yum &>/dev/null; then
|
|
curl -fsSL https://get.docker.com | $SUDO sh
|
|
elif command -v dnf &>/dev/null; then
|
|
curl -fsSL https://get.docker.com | $SUDO sh
|
|
else
|
|
error "Unsupported package manager. Install Docker manually: https://docs.docker.com/engine/install/"
|
|
fi
|
|
$SUDO usermod -aG docker "$USER" 2>/dev/null || true
|
|
info "Docker installed."
|
|
fi
|
|
|
|
# Ensure Docker daemon is running
|
|
if ! docker info &>/dev/null; then
|
|
warn "Starting Docker daemon..."
|
|
$SUDO systemctl enable --now docker 2>/dev/null || $SUDO dockerd &>/dev/null &
|
|
sleep 3
|
|
fi
|
|
info "Docker daemon is running"
|
|
|
|
if ! docker compose version &>/dev/null; then
|
|
warn "Docker Compose not found — installing plugin..."
|
|
$SUDO mkdir -p /usr/local/lib/docker/cli-plugins
|
|
$SUDO curl -fsSL "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/lib/docker/cli-plugins/docker-compose
|
|
$SUDO chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
|
|
fi
|
|
info "Docker Compose: $(docker compose version 2>&1)"
|
|
}
|
|
|
|
# ─── 2. Node.js ─────────────────────────────────────────────────
|
|
install_node() {
|
|
step "2/8 Installing Node.js"
|
|
if command -v node &>/dev/null; then
|
|
NODE_MAJOR=$(node -v | sed 's/v//' | cut -d. -f1)
|
|
if [ "$NODE_MAJOR" -lt 22 ]; then
|
|
warn "Node.js $(node -v) is too old — upgrading to v22..."
|
|
else
|
|
info "Node.js $(node -v) detected"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
if ! command -v node &>/dev/null || [ "$NODE_MAJOR" -lt 22 ]; then
|
|
warn "Installing Node.js 22 LTS..."
|
|
if command -v apt-get &>/dev/null; then
|
|
curl -fsSL https://deb.nodesource.com/setup_22.x | $SUDO bash -
|
|
$SUDO apt-get install -y nodejs
|
|
elif command -v dnf &>/dev/null; then
|
|
curl -fsSL https://rpm.nodesource.com/setup_22.x | $SUDO bash -
|
|
$SUDO dnf install -y nodejs
|
|
elif command -v yum &>/dev/null; then
|
|
curl -fsSL https://rpm.nodesource.com/setup_22.x | $SUDO bash -
|
|
$SUDO yum install -y nodejs
|
|
else
|
|
warn "Package manager not recognised — trying nvm..."
|
|
curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
|
|
export NVM_DIR="$HOME/.nvm"
|
|
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
|
nvm install 22
|
|
nvm alias default 22
|
|
fi
|
|
fi
|
|
info "Node.js $(node -v) ready"
|
|
}
|
|
|
|
# ─── 3. Install prerequisites if needed ──────────────────────────
|
|
if [ "$SKIP_PREREQS" != "true" ]; then
|
|
install_docker
|
|
install_node
|
|
else
|
|
step "1-2/8 Skipping prerequisites (SKIP_PREREQS=true)"
|
|
fi
|
|
|
|
# ─── 4. Download project ─────────────────────────────────────────
|
|
step "3/8 Downloading SSO Service"
|
|
if [ -d "$INSTALL_DIR/.git" ]; then
|
|
cd "$INSTALL_DIR"
|
|
git pull --ff-only 2>/dev/null && info "Updated existing installation" || warn "Could not git pull, continuing"
|
|
else
|
|
mkdir -p "$INSTALL_DIR"
|
|
if command -v git &>/dev/null; then
|
|
git clone --depth 1 "https://github.com/$REPO.git" "$INSTALL_DIR" 2>&1
|
|
else
|
|
warn "git not found, downloading archive..."
|
|
curl -fsSL "https://github.com/$REPO/archive/refs/heads/$BRANCH.tar.gz" | tar xz --strip=1 -C "$INSTALL_DIR"
|
|
fi
|
|
info "Downloaded to $INSTALL_DIR"
|
|
fi
|
|
cd "$INSTALL_DIR"
|
|
|
|
# ─── 5. .env ─────────────────────────────────────────────────────
|
|
step "4/8 Configuring environment"
|
|
if [ ! -f .env ]; then
|
|
cp .env.example .env
|
|
# Генерация случайных JWT-секретов (32 байта hex = 64 символа)
|
|
JWT_ACCESS=$(openssl rand -hex 32 2>/dev/null || node -e "process.stdout.write(require('crypto').randomBytes(32).toString('hex'))")
|
|
JWT_REFRESH=$(openssl rand -hex 32 2>/dev/null || node -e "process.stdout.write(require('crypto').randomBytes(32).toString('hex'))")
|
|
if [ "$(uname -s)" = "Darwin" ]; then
|
|
sed -i '' "s/change-me-access-secret-at-least-32-chars/$JWT_ACCESS/" .env
|
|
sed -i '' "s/change-me-refresh-secret-at-least-32-chars/$JWT_REFRESH/" .env
|
|
else
|
|
sed -i "s/change-me-access-secret-at-least-32-chars/$JWT_ACCESS/" .env
|
|
sed -i "s/change-me-refresh-secret-at-least-32-chars/$JWT_REFRESH/" .env
|
|
fi
|
|
info "Created .env with random JWT secrets"
|
|
else
|
|
info ".env already exists, keeping it"
|
|
fi
|
|
|
|
set -a; source .env; set +a
|
|
|
|
# ─── 6. Docker infrastructure ────────────────────────────────────
|
|
step "5/8 Starting infrastructure (PostgreSQL, Redis, RabbitMQ)"
|
|
$SUDO docker compose up -d 2>&1
|
|
|
|
info "Waiting for PostgreSQL..."
|
|
for i in $(seq 1 30); do
|
|
if $SUDO docker compose exec -T postgres pg_isready -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" &>/dev/null; then
|
|
info "PostgreSQL is ready"
|
|
break
|
|
fi
|
|
[ "$i" -eq 30 ] && error "PostgreSQL did not start in time. Check: $SUDO docker compose logs postgres"
|
|
sleep 2
|
|
done
|
|
|
|
info "Waiting for Redis..."
|
|
for i in $(seq 1 15); do
|
|
if $SUDO docker compose exec -T redis redis-cli ping 2>/dev/null | grep -q PONG; then
|
|
info "Redis is ready"
|
|
break
|
|
fi
|
|
[ "$i" -eq 15 ] && warn "Redis may not be ready yet, continuing..."
|
|
sleep 2
|
|
done
|
|
|
|
# ─── 7. Dependencies & Prisma ────────────────────────────────────
|
|
step "6/8 Installing dependencies"
|
|
npm ci --no-audit --no-fund 2>&1 | tail -1
|
|
info "npm dependencies installed"
|
|
|
|
npx prisma generate 2>&1 | tail -1
|
|
info "Prisma client generated"
|
|
|
|
export DATABASE_URL
|
|
npx prisma db push --skip-generate 2>&1
|
|
info "Database schema applied"
|
|
|
|
# ─── 8. Seed ─────────────────────────────────────────────────────
|
|
step "7/8 Seeding database"
|
|
npx ts-node -P tsconfig.json prisma/seed.ts 2>&1
|
|
info "Seed data created"
|
|
|
|
# ─── 9. Build & Start ────────────────────────────────────────────
|
|
step "8/8 Building and starting SSO Service"
|
|
npm run build 2>&1 | tail -3
|
|
info "Application built"
|
|
|
|
if command -v pm2 &>/dev/null; then
|
|
pm2 delete sso-service 2>/dev/null || true
|
|
pm2 start npm --name "sso-service" -- run start:prod
|
|
pm2 save 2>/dev/null || true
|
|
info "Started with PM2"
|
|
else
|
|
PORT="${PORT:-3000}" nohup node dist/main > "$INSTALL_DIR/sso.log" 2>&1 &
|
|
echo $! > "$INSTALL_DIR/.sso.pid"
|
|
info "Started in background (PID $(cat "$INSTALL_DIR/.sso.pid")) — logs: $INSTALL_DIR/sso.log"
|
|
fi
|
|
|
|
sleep 3
|
|
if curl -sfo /dev/null "http://localhost:${PORT:-3000}/metrics" 2>/dev/null; then
|
|
info "Service is running on http://localhost:${PORT:-3000}"
|
|
else
|
|
warn "Service may still be starting... check: $INSTALL_DIR/sso.log"
|
|
fi
|
|
|
|
# ─── Done ────────────────────────────────────────────────────────
|
|
echo ""
|
|
echo -e "${GREEN}════════════════════════════════════════════════${NC}"
|
|
echo -e "${GREEN} SSO Service installed and running!${NC}"
|
|
echo -e "${GREEN}════════════════════════════════════════════════${NC}"
|
|
echo ""
|
|
echo -e " ${CYAN}Web panel:${NC} http://localhost:${PORT:-3000}"
|
|
echo -e " ${CYAN}Admin login:${NC} admin@sso.local / admin123!"
|
|
echo -e " ${CYAN}Metrics:${NC} http://localhost:${PORT:-3000}/metrics"
|
|
echo -e " ${CYAN}RabbitMQ UI:${NC} http://localhost:15672 (${RABBITMQ_USER:-sso} / ${RABBITMQ_PASSWORD:-sso_secret})"
|
|
echo ""
|
|
echo -e " ${YELLOW}Install dir:${NC} $INSTALL_DIR"
|
|
echo -e " ${YELLOW}Log file:${NC} $INSTALL_DIR/sso.log"
|
|
echo ""
|
|
echo -e " ${YELLOW}Stop:${NC} $(command -v pm2 &>/dev/null && echo 'pm2 stop sso-service' || echo "kill \$(cat $INSTALL_DIR/.sso.pid)")"
|
|
echo -e " ${YELLOW}Update:${NC} cd $INSTALL_DIR && git pull && npm ci && npm run build && npm run start:prod"
|
|
echo -e " ${YELLOW}Re-run:${NC} curl -fsSL https://github.com/${REPO}/raw/${BRANCH}/install.sh | bash"
|
|
echo ""
|
|
echo -e " ${GREEN}Open http://localhost:${PORT:-3000} in your browser${NC}"
|
|
echo ""
|