241 lines
8.7 KiB
Bash
241 lines
8.7 KiB
Bash
|
|
#!/usr/bin/env bash
|
||
|
|
# =============================================================================
|
||
|
|
# Falah OS — One-line installer
|
||
|
|
#
|
||
|
|
# curl -fsSL https://raw.githubusercontent.com/falah-consultancy-limited/falah-os-master/main/install.sh | bash
|
||
|
|
# — or —
|
||
|
|
# wget -qO- https://raw.githubusercontent.com/falah-consultancy-limited/falah-os-master/main/install.sh | bash
|
||
|
|
#
|
||
|
|
# What it does:
|
||
|
|
# 1. Checks prerequisites (git, docker, docker compose, openssl)
|
||
|
|
# 2. Clones the repo (or pulls if already cloned)
|
||
|
|
# 3. Generates all required secrets
|
||
|
|
# 4. Writes .env (skips any var already set by the environment)
|
||
|
|
# 5. Starts the stack with docker compose
|
||
|
|
# 6. Runs a health check
|
||
|
|
# =============================================================================
|
||
|
|
|
||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Colours & helpers
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
GREEN='\033[0;32m'
|
||
|
|
BLUE='\033[0;34m'
|
||
|
|
YELLOW='\033[1;33m'
|
||
|
|
RED='\033[0;31m'
|
||
|
|
BOLD='\033[1m'
|
||
|
|
NC='\033[0m'
|
||
|
|
|
||
|
|
info() { echo -e "${BLUE}[falah]${NC} $*"; }
|
||
|
|
success() { echo -e "${GREEN}[falah]${NC} $*"; }
|
||
|
|
warn() { echo -e "${YELLOW}[falah]${NC} $*"; }
|
||
|
|
fatal() { echo -e "${RED}[falah] ERROR:${NC} $*" >&2; exit 1; }
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Banner
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
echo ""
|
||
|
|
echo -e "${BOLD}${GREEN}╔═══════════════════════════════════════╗${NC}"
|
||
|
|
echo -e "${BOLD}${GREEN}║ Falah OS — Installer v1.3 ║${NC}"
|
||
|
|
echo -e "${BOLD}${GREEN}║ Shariah-compliant digital economy ║${NC}"
|
||
|
|
echo -e "${BOLD}${GREEN}╚═══════════════════════════════════════╝${NC}"
|
||
|
|
echo ""
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Prerequisite checks
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
info "Checking prerequisites..."
|
||
|
|
|
||
|
|
check_cmd() {
|
||
|
|
command -v "$1" >/dev/null 2>&1 || fatal "$1 is required but not installed. $2"
|
||
|
|
}
|
||
|
|
|
||
|
|
check_cmd git "Install via your package manager (apt/brew/dnf)."
|
||
|
|
check_cmd docker "Install Docker: https://docs.docker.com/get-docker/"
|
||
|
|
check_cmd openssl "Install via your package manager (apt/brew/dnf)."
|
||
|
|
|
||
|
|
# Docker Compose v2 (plugin) or v1 (standalone)
|
||
|
|
if docker compose version >/dev/null 2>&1; then
|
||
|
|
COMPOSE="docker compose"
|
||
|
|
elif command -v docker-compose >/dev/null 2>&1; then
|
||
|
|
COMPOSE="docker-compose"
|
||
|
|
else
|
||
|
|
fatal "Docker Compose is required. Install: https://docs.docker.com/compose/install/"
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Docker daemon running?
|
||
|
|
docker info >/dev/null 2>&1 || fatal "Docker daemon is not running. Start Docker and try again."
|
||
|
|
|
||
|
|
success "Prerequisites OK"
|
||
|
|
echo ""
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Clone or update
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
REPO_URL="https://github.com/falah-consultancy-limited/falah-os-master.git"
|
||
|
|
INSTALL_DIR="${FALAH_INSTALL_DIR:-$HOME/falah-os}"
|
||
|
|
|
||
|
|
if [ -d "$INSTALL_DIR/.git" ]; then
|
||
|
|
info "Found existing install at $INSTALL_DIR — pulling latest..."
|
||
|
|
git -C "$INSTALL_DIR" pull --ff-only origin main
|
||
|
|
else
|
||
|
|
info "Cloning Falah OS into $INSTALL_DIR..."
|
||
|
|
git clone --depth 1 "$REPO_URL" "$INSTALL_DIR"
|
||
|
|
fi
|
||
|
|
|
||
|
|
cd "$INSTALL_DIR"
|
||
|
|
success "Codebase ready at $INSTALL_DIR"
|
||
|
|
echo ""
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Generate secrets
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
gen_secret() {
|
||
|
|
openssl rand -base64 48 | tr -d '=+/' | cut -c1-48
|
||
|
|
}
|
||
|
|
|
||
|
|
info "Generating secrets..."
|
||
|
|
|
||
|
|
# Respect any secrets already exported in the environment
|
||
|
|
JWT_SECRET="${JWT_SECRET:-$(gen_secret)}"
|
||
|
|
ENCRYPTION_KEY="${ENCRYPTION_KEY:-$(gen_secret)}"
|
||
|
|
ADMIN_SECRET="${ADMIN_SECRET:-$(gen_secret)}"
|
||
|
|
POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-$(gen_secret)}"
|
||
|
|
REDIS_PASSWORD="${REDIS_PASSWORD:-$(gen_secret)}"
|
||
|
|
|
||
|
|
success "Secrets generated"
|
||
|
|
echo ""
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Write .env
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
if [ -f .env ]; then
|
||
|
|
warn ".env already exists — merging generated secrets for any blank values..."
|
||
|
|
# For each required var, only fill in if currently blank/missing in .env
|
||
|
|
fill_if_blank() {
|
||
|
|
local var="$1" val="$2"
|
||
|
|
if grep -qE "^${var}=\s*$" .env 2>/dev/null || ! grep -qE "^${var}=" .env 2>/dev/null; then
|
||
|
|
# Escape forward slashes in value for sed
|
||
|
|
local escaped_val
|
||
|
|
escaped_val=$(printf '%s\n' "$val" | sed 's/[\/&]/\\&/g')
|
||
|
|
if grep -qE "^${var}=" .env; then
|
||
|
|
sed -i "s|^${var}=.*|${var}=${escaped_val}|" .env
|
||
|
|
else
|
||
|
|
echo "${var}=${val}" >> .env
|
||
|
|
fi
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
fill_if_blank JWT_SECRET "$JWT_SECRET"
|
||
|
|
fill_if_blank ENCRYPTION_KEY "$ENCRYPTION_KEY"
|
||
|
|
fill_if_blank ADMIN_SECRET "$ADMIN_SECRET"
|
||
|
|
fill_if_blank POSTGRES_PASSWORD "$POSTGRES_PASSWORD"
|
||
|
|
fill_if_blank REDIS_PASSWORD "$REDIS_PASSWORD"
|
||
|
|
else
|
||
|
|
info "Writing .env..."
|
||
|
|
cp .env.example .env
|
||
|
|
|
||
|
|
# Replace blank values for required vars
|
||
|
|
sed -i "s|^JWT_SECRET=.*|JWT_SECRET=${JWT_SECRET}|" .env
|
||
|
|
sed -i "s|^ENCRYPTION_KEY=.*|ENCRYPTION_KEY=${ENCRYPTION_KEY}|" .env
|
||
|
|
sed -i "s|^ADMIN_SECRET=.*|ADMIN_SECRET=${ADMIN_SECRET}|" .env
|
||
|
|
sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=${POSTGRES_PASSWORD}|" .env
|
||
|
|
sed -i "s|^REDIS_PASSWORD=.*|REDIS_PASSWORD=${REDIS_PASSWORD}|" .env
|
||
|
|
fi
|
||
|
|
|
||
|
|
success ".env configured"
|
||
|
|
echo ""
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Verify .env before launch
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
info "Verifying environment..."
|
||
|
|
missing=0
|
||
|
|
for var in JWT_SECRET ENCRYPTION_KEY ADMIN_SECRET POSTGRES_PASSWORD REDIS_PASSWORD; do
|
||
|
|
val=$(grep -E "^${var}=.+" .env 2>/dev/null | cut -d= -f2- || true)
|
||
|
|
if [ -z "$val" ]; then
|
||
|
|
warn "Still missing: $var"
|
||
|
|
missing=1
|
||
|
|
fi
|
||
|
|
done
|
||
|
|
[ "$missing" -eq 0 ] || fatal "Cannot start with missing required env vars. Edit .env and re-run."
|
||
|
|
success "Environment OK"
|
||
|
|
echo ""
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Start the stack
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
info "Starting Falah OS stack..."
|
||
|
|
$COMPOSE pull --quiet
|
||
|
|
$COMPOSE up -d
|
||
|
|
|
||
|
|
echo ""
|
||
|
|
info "Waiting for services to become ready..."
|
||
|
|
sleep 10
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Health check (inline — no dependency on scripts/health-check.sh)
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
PASS=0
|
||
|
|
FAIL=0
|
||
|
|
|
||
|
|
check_http() {
|
||
|
|
local name="$1" url="$2"
|
||
|
|
printf " %-20s" "$name"
|
||
|
|
if curl -sf --max-time 5 "$url" >/dev/null 2>&1; then
|
||
|
|
echo -e "${GREEN}healthy${NC}"
|
||
|
|
PASS=$((PASS + 1))
|
||
|
|
else
|
||
|
|
echo -e "${RED}not responding${NC}"
|
||
|
|
FAIL=$((FAIL + 1))
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
echo -e "${BLUE}Service health:${NC}"
|
||
|
|
check_http "API Gateway" "http://localhost:3000/health"
|
||
|
|
check_http "Ummah ID" "http://localhost:3001/health"
|
||
|
|
check_http "Wallet" "http://localhost:3002/health"
|
||
|
|
check_http "RAMZ" "http://localhost:3003/health"
|
||
|
|
check_http "Mock-Net" "http://localhost:3004/health"
|
||
|
|
check_http "App" "http://localhost:3005/health"
|
||
|
|
check_http "falahd" "http://localhost:3006/health"
|
||
|
|
|
||
|
|
echo ""
|
||
|
|
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
# Done
|
||
|
|
# ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
if [ "$FAIL" -eq 0 ]; then
|
||
|
|
echo -e "${BOLD}${GREEN}╔═══════════════════════════════════════╗${NC}"
|
||
|
|
echo -e "${BOLD}${GREEN}║ Falah OS is running! ║${NC}"
|
||
|
|
echo -e "${BOLD}${GREEN}╚═══════════════════════════════════════╝${NC}"
|
||
|
|
echo ""
|
||
|
|
echo -e " Dashboard: ${BOLD}http://localhost:3005${NC}"
|
||
|
|
echo -e " API: ${BOLD}http://localhost:3000${NC}"
|
||
|
|
echo -e " Admin key: stored in ${BOLD}${INSTALL_DIR}/.env${NC}"
|
||
|
|
echo ""
|
||
|
|
echo -e " Useful commands:"
|
||
|
|
echo -e " cd ${INSTALL_DIR}"
|
||
|
|
echo -e " make logs # tail all service logs"
|
||
|
|
echo -e " make health # re-run health checks"
|
||
|
|
echo -e " make down # stop the stack"
|
||
|
|
echo ""
|
||
|
|
else
|
||
|
|
warn "${FAIL} service(s) did not respond. Check logs:"
|
||
|
|
echo ""
|
||
|
|
echo -e " cd ${INSTALL_DIR} && make logs"
|
||
|
|
echo ""
|
||
|
|
echo -e " The stack is running — services may still be starting up."
|
||
|
|
echo -e " Re-run health check in ~30 s: ${BOLD}make health${NC}"
|
||
|
|
fi
|