#!/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