#!/usr/bin/env bash set -euo pipefail # LOGGI Installer # # Open source (default): # curl -sSL https://get.loggi.dev/install | bash # # Licensed / commercial (optional): # curl -sSL https://get.loggi.dev/install | bash -s -- LOGGI_API_URL="${LOGGI_API_URL:-https://api.loggi.dev}" INSTALL_DIR="${LOGGI_INSTALL_DIR:-/opt/loggi}" REPO_URL="https://github.com/peyidev/LOGGI/archive/refs/heads/main.tar.gz" COMPOSE_URL="https://raw.githubusercontent.com/peyidev/LOGGI/main/deploy/docker-compose.customer.yml" CADDYFILE_URL="https://raw.githubusercontent.com/peyidev/LOGGI/main/deploy/Caddyfile.customer" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' NC='\033[0m' log() { echo -e "${GREEN}[LOGGI]${NC} $1"; } warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; } # --- Check prerequisites --- check_prereqs() { log "Checking prerequisites..." command -v docker >/dev/null 2>&1 || error "Docker is not installed. Install it first: https://docs.docker.com/engine/install/" command -v curl >/dev/null 2>&1 || error "curl is not installed." docker compose version >/dev/null 2>&1 || error "Docker Compose plugin is not installed." log "All prerequisites met." } prompt_admin_password() { if [ -n "${LOGGI_ADMIN_PASSWORD:-}" ]; then echo "$LOGGI_ADMIN_PASSWORD" return fi local admin_password echo "" echo -e "${CYAN}Choose an admin password for the LOGGI dashboard:${NC}" if [ -r /dev/tty ]; then read -rs -p "Admin password: " admin_password < /dev/tty echo "" >&2 else read -rs -p "Admin password: " admin_password echo "" fi if [ -z "$admin_password" ]; then admin_password=$(openssl rand -hex 12) warn "No password entered. Generated random password: ${admin_password}" fi echo "$admin_password" } prompt_domain() { if [ -n "${LOGGI_DOMAIN:-}" ]; then echo "${LOGGI_DOMAIN}" return fi local domain echo -e "${CYAN}Enter your domain (or press Enter for localhost):${NC}" if [ -r /dev/tty ]; then read -r -p "Domain: " domain < /dev/tty else read -r -p "Domain: " domain fi echo "${domain:-localhost}" } # --- Validate license key (commercial only) --- validate_license() { local key="$1" log "Validating license key..." local response response=$(curl -sf -X POST "${LOGGI_API_URL}/v1/license/validate" \ -H "Content-Type: application/json" \ -d "{\"license_key\": \"${key}\"}" 2>&1) || error "License validation failed. Check your key and try again." local status status=$(echo "$response" | grep -o '"status":"[^"]*"' | head -1 | cut -d'"' -f4) if [ "$status" = "expired" ] || [ "$status" = "revoked" ]; then error "License is ${status}. Please renew at https://loggi.dev/pricing" fi log "License validated successfully (status: ${status})." } # --- Docker login to ghcr.io (commercial only) --- docker_login() { local key="$1" log "Authenticating with container registry..." local response response=$(curl -sf -X POST "${LOGGI_API_URL}/v1/license/registry-token" \ -H "Content-Type: application/json" \ -d "{\"license_key\": \"${key}\"}" 2>&1) || error "Failed to get registry credentials. Is your license valid?" local token token=$(echo "$response" | grep -o '"token":"[^"]*"' | head -1 | cut -d'"' -f4) local username username=$(echo "$response" | grep -o '"username":"[^"]*"' | head -1 | cut -d'"' -f4) echo "$token" | docker login ghcr.io -u "$username" --password-stdin >/dev/null 2>&1 || error "Docker login to ghcr.io failed." log "Registry authentication successful." } setup_install_dir() { log "Setting up installation directory at ${INSTALL_DIR}..." if mkdir -p "$INSTALL_DIR" 2>/dev/null; then : elif [ "$(id -u)" -eq 0 ]; then mkdir -p "$INSTALL_DIR" elif sudo -n true 2>/dev/null; then sudo mkdir -p "$INSTALL_DIR" sudo chown "$(id -u):$(id -g)" "$INSTALL_DIR" else error "Cannot create ${INSTALL_DIR}. Run as root, configure passwordless sudo, or set LOGGI_INSTALL_DIR to a writable path." fi cd "$INSTALL_DIR" } download_oss_source() { log "Downloading LOGGI source from GitHub..." local tmpdir tmpdir=$(mktemp -d) curl -sfL "$REPO_URL" | tar xz -C "$tmpdir" || error "Failed to download LOGGI from GitHub (${REPO_URL})" cp -a "${tmpdir}/LOGGI-main/." "$INSTALL_DIR/" || error "Unexpected archive layout from GitHub (missing LOGGI-main/)" rm -rf "$tmpdir" log "Source downloaded." } download_commercial_compose() { log "Downloading configuration files..." curl -sf -o docker-compose.yml "$COMPOSE_URL" || error "Failed to download docker-compose.yml" curl -sf -o Caddyfile "$CADDYFILE_URL" || error "Failed to download Caddyfile" log "Configuration files downloaded." } write_env_file() { local license_key="${1:-}" local admin_password="$2" local domain="$3" local jwt_secret jwt_secret=$(openssl rand -hex 32) local origin cors_origin if [ "$domain" = "localhost" ]; then origin="http://localhost:3000" cors_origin="http://localhost:3000" else origin="https://${domain}" cors_origin="https://${domain}" fi if [ -n "$license_key" ]; then cat > .env << EOF # LOGGI Configuration - Generated by installer (licensed) LOGGI_LICENSE_KEY=${license_key} LOGGI_LICENSE_URL=${LOGGI_API_URL} LOGGI_JWT_SECRET=${jwt_secret} LOGGI_ADMIN_USERNAME=admin LOGGI_ADMIN_PASSWORD=${admin_password} LOGGI_CLICKHOUSE_ADDR=clickhouse:9000 LOGGI_DOMAIN=${domain} LOGGI_ORIGIN=${origin} LOGGI_CORS_ORIGIN=${cors_origin} EOF else cat > .env << EOF # LOGGI Configuration - Generated by installer (open source) LOGGI_JWT_SECRET=${jwt_secret} LOGGI_ADMIN_USERNAME=admin LOGGI_ADMIN_PASSWORD=${admin_password} LOGGI_DOMAIN=${domain} LOGGI_ORIGIN=${origin} LOGGI_CORS_ORIGIN=${cors_origin} EOF fi chmod 600 .env log "Configuration saved to ${INSTALL_DIR}/.env" } start_oss_loggi() { log "Building and starting LOGGI (open source)..." local domain domain=$(grep '^LOGGI_DOMAIN=' .env | cut -d'=' -f2) if [ "$domain" = "localhost" ]; then docker compose -f docker-compose.yml up -d --build else docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build fi log "Waiting for services to start..." sleep 8 } start_commercial_loggi() { log "Pulling LOGGI images..." docker compose pull log "Starting LOGGI..." docker compose up -d log "Waiting for services to start..." sleep 5 } print_success() { local domain domain=$(grep '^LOGGI_DOMAIN=' .env | cut -d'=' -f2) local admin_user admin_user=$(grep '^LOGGI_ADMIN_USERNAME=' .env | cut -d'=' -f2) local licensed=false grep -q '^LOGGI_LICENSE_KEY=' .env 2>/dev/null && licensed=true echo "" echo -e "${GREEN}============================================${NC}" echo -e "${GREEN} LOGGI installed successfully!${NC}" echo -e "${GREEN}============================================${NC}" echo "" if [ "$domain" = "localhost" ]; then echo -e " Dashboard: ${CYAN}http://localhost:3000${NC}" else echo -e " Dashboard: ${CYAN}https://${domain}${NC}" fi echo -e " Username: ${CYAN}${admin_user}${NC}" if [ "$licensed" = false ]; then echo -e " Edition: ${CYAN}Open Source (no license required)${NC}" fi echo "" echo -e " ${YELLOW}Next steps:${NC}" echo -e " 1. Log in to the dashboard" echo -e " 2. Create an API key in Settings" echo -e " 3. Install LOGGI agents on your servers" echo "" echo -e " Manage: cd ${INSTALL_DIR} && docker compose logs -f" echo -e " Stop: cd ${INSTALL_DIR} && docker compose down" if [ "$licensed" = true ]; then echo -e " Update: cd ${INSTALL_DIR} && docker compose pull && docker compose up -d" else echo -e " Update: cd ${INSTALL_DIR} && curl -sSL https://get.loggi.dev/install | bash" fi echo "" } install_oss() { echo "" echo -e "${GREEN}╔═══════════════════════════════════════╗${NC}" echo -e "${GREEN}║ LOGGI Open Source Installer v1.0 ║${NC}" echo -e "${GREEN}╚═══════════════════════════════════════╝${NC}" echo "" check_prereqs setup_install_dir if [ ! -f docker-compose.yml ]; then download_oss_source else warn "Existing installation found at ${INSTALL_DIR}; reusing files." fi local admin_password domain admin_password=$(prompt_admin_password) domain=$(prompt_domain) write_env_file "" "$admin_password" "$domain" start_oss_loggi print_success } install_commercial() { local license_key="$1" echo "" echo -e "${GREEN}╔═══════════════════════════════════════╗${NC}" echo -e "${GREEN}║ LOGGI Licensed Installer v1.0 ║${NC}" echo -e "${GREEN}╚═══════════════════════════════════════╝${NC}" echo "" check_prereqs validate_license "$license_key" docker_login "$license_key" setup_install_dir download_commercial_compose local admin_password domain admin_password=$(prompt_admin_password) domain=$(prompt_domain) write_env_file "$license_key" "$admin_password" "$domain" start_commercial_loggi print_success } main() { local license_key="${1:-}" if [ -n "$license_key" ]; then install_commercial "$license_key" else install_oss fi } main "$@"