Last active
June 5, 2026 08:19
-
-
Save askareija/7fef0a3ad91813e5efe1c343b821b144 to your computer and use it in GitHub Desktop.
LP Install script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # ============================================================================= | |
| # Legal Plus Enterprise — On-Premise Setup Script | |
| # ============================================================================= | |
| set -euo pipefail | |
| # ─── CONFIG ─────────────────────────────────────────────────────────────────── | |
| COMPOSE_URL="https://releases.cafstechnology.id/legalplus/docker-compose.yml" | |
| REGISTRY_HOST="registry.cafstechnology.id" | |
| APP_DIR="/opt/legalplus" | |
| IMAGE_TAG="dev-latest" | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m' | |
| CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m' | |
| log_info() { echo -e "${CYAN}[INFO]${NC} $*"; } | |
| log_ok() { echo -e "${GREEN}[OK]${NC} $*"; } | |
| log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } | |
| log_error() { echo -e "${RED}[ERROR]${NC} $*"; } | |
| log_section() { echo -e "\n${BOLD}━━━ $* ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"; } | |
| die() { log_error "$*"; exit 1; } | |
| confirm() { | |
| local answer | |
| read -rp "$(echo -e "${YELLOW}?${NC} $1 [y/N]: ")" answer | |
| [[ "${answer,,}" == "y" ]] | |
| } | |
| prompt_required() { | |
| local var="$1" label="$2" default="${3:-}" value="" | |
| while [[ -z "$value" ]]; do | |
| if [[ -n "$default" ]]; then | |
| read -rp "$(echo -e "${CYAN}›${NC} $label [${default}]: ")" value | |
| value="${value:-$default}" | |
| else | |
| read -rp "$(echo -e "${CYAN}›${NC} $label: ")" value | |
| fi | |
| [[ -z "$value" ]] && log_warn "Tidak boleh kosong." | |
| done | |
| printf -v "$var" '%s' "$value" | |
| } | |
| prompt_secret() { | |
| local var="$1" label="$2" value="" | |
| while [[ -z "$value" ]]; do | |
| read -rsp "$(echo -e "${CYAN}›${NC} $label: ")" value | |
| echo | |
| [[ -z "$value" ]] && log_warn "Tidak boleh kosong." | |
| done | |
| printf -v "$var" '%s' "$value" | |
| } | |
| generate_fingerprint() { | |
| local machine_id="" | |
| if [[ -f /etc/machine-id ]]; then | |
| machine_id=$(cat /etc/machine-id) | |
| elif [[ -f /var/lib/dbus/machine-id ]]; then | |
| machine_id=$(cat /var/lib/dbus/machine-id) | |
| else | |
| die "Tidak dapat menemukan machine-id." | |
| fi | |
| local mac="" | |
| mac=$(ip link show | awk '/^[0-9]+: /{iface=$2} /link\/ether/{print $2; exit}') | |
| echo -n "${machine_id}:${mac}:${CUSTOMER_ID}" | sha256sum | awk '{print $1}' | |
| } | |
| # ─── PREFLIGHT ──────────────────────────────────────────────────────────────── | |
| log_section "Preflight Check" | |
| [[ "$EUID" -ne 0 ]] && die "Jalankan script ini sebagai root: sudo $0" | |
| for cmd in curl grep awk openssl ip sha256sum; do | |
| command -v "$cmd" &>/dev/null || die "Dependency tidak ditemukan: $cmd" | |
| done | |
| log_ok "Dependency dasar OK" | |
| # ─── STEP 1: INSTALL DOCKER ─────────────────────────────────────────────────── | |
| log_section "Step 1: Install Docker" | |
| install_docker() { | |
| log_info "Mendeteksi OS..." | |
| [[ -f /etc/os-release ]] || die "Tidak dapat mendeteksi OS." | |
| # shellcheck source=/dev/null | |
| source /etc/os-release | |
| case "$ID" in | |
| ubuntu|debian) | |
| log_info "Menginstall Docker di $PRETTY_NAME..." | |
| apt-get update -qq | |
| apt-get install -y -qq ca-certificates curl gnupg lsb-release | |
| install -m 0755 -d /etc/apt/keyrings | |
| curl -fsSL "https://download.docker.com/linux/${ID}/gpg" \ | |
| | gpg --dearmor -o /etc/apt/keyrings/docker.gpg | |
| chmod a+r /etc/apt/keyrings/docker.gpg | |
| echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \ | |
| https://download.docker.com/linux/${ID} $(lsb_release -cs) stable" \ | |
| > /etc/apt/sources.list.d/docker.list | |
| apt-get update -qq | |
| apt-get install -y -qq docker-ce docker-ce-cli containerd.io \ | |
| docker-buildx-plugin docker-compose-plugin | |
| ;; | |
| centos|rhel|rocky|almalinux) | |
| log_info "Menginstall Docker di $PRETTY_NAME..." | |
| yum install -y -q yum-utils | |
| yum-config-manager --add-repo \ | |
| https://download.docker.com/linux/centos/docker-ce.repo | |
| yum install -y -q docker-ce docker-ce-cli containerd.io \ | |
| docker-buildx-plugin docker-compose-plugin | |
| ;; | |
| *) | |
| die "OS tidak didukung: $ID. Install Docker secara manual lalu jalankan ulang." | |
| ;; | |
| esac | |
| systemctl enable --now docker | |
| log_ok "Docker berhasil diinstall" | |
| } | |
| if command -v docker &>/dev/null; then | |
| log_ok "Docker sudah terinstall: $(docker --version)" | |
| if ! docker compose version &>/dev/null; then | |
| log_warn "Docker Compose plugin tidak ditemukan. Menginstall..." | |
| install_docker | |
| else | |
| log_ok "Docker Compose sudah terinstall: $(docker compose version)" | |
| fi | |
| else | |
| log_info "Docker belum terinstall." | |
| confirm "Install Docker sekarang?" || die "Docker diperlukan untuk melanjutkan." | |
| install_docker | |
| fi | |
| # ─── STEP 2: DOWNLOAD COMPOSE FILE ─────────────────────────────────────────── | |
| log_section "Step 2: Download Docker Compose File" | |
| mkdir -p "$APP_DIR" | |
| log_info "Mengunduh docker-compose.yml..." | |
| curl -fsSL "$COMPOSE_URL" -o "$APP_DIR/docker-compose.yml" \ | |
| || die "Gagal mengunduh docker-compose.yml." | |
| log_ok "docker-compose.yml disimpan di $APP_DIR/" | |
| # ─── STEP 3: KONFIGURASI ───────────────────────────────────────────────────── | |
| log_section "Step 3: Konfigurasi" | |
| setup_env=false | |
| if [[ -f "$APP_DIR/.env.backend" ]]; then | |
| log_warn "Konfigurasi sudah ada di $APP_DIR." | |
| confirm "Timpa konfigurasi yang ada?" && setup_env=true | |
| else | |
| setup_env=true | |
| fi | |
| if [[ "$setup_env" == "true" ]]; then | |
| echo | |
| log_info "Hanya beberapa input yang diperlukan — sisanya otomatis." | |
| echo | |
| # ── Input dari customer/admin | |
| prompt_required CUSTOMER_ID "Customer ID (dari tim kami)" | |
| prompt_required APP_URL "URL Aplikasi (contoh: https://app.perusahaan.com)" | |
| prompt_required APP_PORT "Port HTTP" "80" | |
| # ── Registry credentials | |
| prompt_required REGISTRY_USER "Registry Username" | |
| prompt_secret REGISTRY_PASS "Registry Password" | |
| # ── SMTP (opsional) | |
| SMTP_ENABLED=false | |
| SMTP_HOST=""; SMTP_PORT="587"; SMTP_USER=""; SMTP_PASS=""; SMTP_FROM="" | |
| if confirm "Konfigurasi SMTP untuk email?"; then | |
| prompt_required SMTP_HOST "SMTP Host" | |
| prompt_required SMTP_PORT "SMTP Port" "587" | |
| prompt_required SMTP_USER "SMTP Username" | |
| prompt_secret SMTP_PASS "SMTP Password" | |
| prompt_required SMTP_FROM "Email pengirim (From)" | |
| SMTP_ENABLED=true | |
| fi | |
| # ── Auto-generate semua infra secrets | |
| log_info "Generating secrets..." | |
| DB_USERNAME="lp_$(openssl rand -hex 6)" | |
| DB_PASSWORD=$(openssl rand -hex 24) | |
| DB_NAME="legalplus_${CUSTOMER_ID}" | |
| S3_ACCESS_KEY_ID="GK$(openssl rand -hex 16)" | |
| S3_ACCESS_KEY_SECRET=$(openssl rand -hex 32) | |
| S3_BUCKET_NAME="legalplus-${CUSTOMER_ID}" | |
| STORAGE_PASS=$(openssl rand -hex 16) | |
| JWT_ACCESS_SECRET=$(openssl rand -hex 32) | |
| RPC_SECRET=$(openssl rand -hex 32) | |
| ADMIN_TOKEN=$(openssl rand -base64 32) | |
| METRICS_TOKEN=$(openssl rand -base64 32) | |
| log_ok "Secrets berhasil di-generate" | |
| # ── garage.toml | |
| log_info "Membuat garage.toml..." | |
| cat > "$APP_DIR/garage.toml" <<EOF | |
| metadata_dir = "/var/lib/garage/meta" | |
| data_dir = "/var/lib/garage/data" | |
| db_engine = "sqlite" | |
| replication_factor = 1 | |
| rpc_bind_addr = "[::]:3901" | |
| rpc_public_addr = "127.0.0.1:3901" | |
| rpc_secret = "${RPC_SECRET}" | |
| [s3_api] | |
| s3_region = "garage" | |
| api_bind_addr = "[::]:3900" | |
| root_domain = ".s3.garage.localhost" | |
| [s3_web] | |
| bind_addr = "[::]:3902" | |
| root_domain = ".web.garage.localhost" | |
| index = "index.html" | |
| [admin] | |
| api_bind_addr = "[::]:3903" | |
| admin_token = "${ADMIN_TOKEN}" | |
| metrics_token = "${METRICS_TOKEN}" | |
| EOF | |
| chmod 600 "$APP_DIR/garage.toml" | |
| log_ok "garage.toml dibuat" | |
| # ── .env (compose-level: IMAGE_TAG, APP_PORT, TRAEFIK port) | |
| cat > "$APP_DIR/.env" <<EOF | |
| IMAGE_TAG=${IMAGE_TAG} | |
| APP_PORT=${APP_PORT} | |
| TRAEFIK_DASHBOARD_PORT=8080 | |
| EOF | |
| # ── .env.mongodb | |
| cat > "$APP_DIR/.env.mongodb" <<EOF | |
| MONGO_INITDB_ROOT_USERNAME=${DB_USERNAME} | |
| MONGO_INITDB_ROOT_PASSWORD=${DB_PASSWORD} | |
| MONGO_INITDB_DATABASE=${DB_NAME} | |
| EOF | |
| # ── .env.s3 | |
| cat > "$APP_DIR/.env.s3" <<EOF | |
| GARAGE_DEFAULT_ACCESS_KEY=${S3_ACCESS_KEY_ID} | |
| GARAGE_DEFAULT_SECRET_KEY=${S3_ACCESS_KEY_SECRET} | |
| GARAGE_DEFAULT_BUCKET=${S3_BUCKET_NAME} | |
| EOF | |
| # ── .env.backend | |
| cat > "$APP_DIR/.env.backend" <<EOF | |
| IMAGE_TAG=${IMAGE_TAG} | |
| TZ=Asia/Jakarta | |
| API_STATUS=production | |
| API_STORAGE=http://storage:4000/api | |
| API_WILAYAH=https://sipedas.pertanian.go.id/api/wilayah | |
| APP_PORT=4000 | |
| CRON_SCHEDULE=*/5 * * * * | |
| DB_HOST=database:27017 | |
| DB_NAME=${DB_NAME}?authSource=admin | |
| DB_NAME_TEST=${DB_NAME}?authSource=admin | |
| DB_USERNAME=${DB_USERNAME} | |
| DB_PASSWORD=${DB_PASSWORD} | |
| JWT_ACCESS_SECRET=${JWT_ACCESS_SECRET} | |
| MAIL_HOST=${SMTP_HOST} | |
| MAIL_PORT=${SMTP_PORT} | |
| MAIL_USER=${SMTP_USER} | |
| MAIL_PASSWORD=${SMTP_PASS} | |
| MAIL_SENDER=${SMTP_FROM} | |
| S3_URL=http://s3:3900 | |
| S3_REGION=garage | |
| S3_BUCKET_NAME=${S3_BUCKET_NAME} | |
| S3_ACCESS_KEY_ID=${S3_ACCESS_KEY_ID} | |
| S3_ACCESS_KEY_SECRET=${S3_ACCESS_KEY_SECRET} | |
| STORAGE_PASS=${STORAGE_PASS} | |
| WEB_URL=${APP_URL} | |
| API_URL=http://backend:4000/api | |
| VITE_APP_SITE_KEY=6LfTXfIqAAAAAJlvZqRWyP9PixuwBrCCQ6oCYwRW | |
| VITE_SECRET_KEY=6LfTXfIqAAAAADaSXa5hOcyQLo9KhvUCZBNHRXBo | |
| EOF | |
| # ── .env.storage | |
| cat > "$APP_DIR/.env.storage" <<EOF | |
| TZ=Asia/Jakarta | |
| STORAGE_PASS=${STORAGE_PASS} | |
| S3_URL=http://s3:3900 | |
| S3_REGION=garage | |
| S3_BUCKET_NAME=${S3_BUCKET_NAME} | |
| S3_ACCESS_KEY_ID=${S3_ACCESS_KEY_ID} | |
| S3_ACCESS_KEY_SECRET=${S3_ACCESS_KEY_SECRET} | |
| EOF | |
| # Simpan registry credentials | |
| printf '%s' "$REGISTRY_USER" > "$APP_DIR/.registry_user" | |
| printf '%s' "$REGISTRY_PASS" > "$APP_DIR/.registry_pass" | |
| # Secure semua file | |
| chmod 600 \ | |
| "$APP_DIR/.env" \ | |
| "$APP_DIR/.env.backend" \ | |
| "$APP_DIR/.env.mongodb" \ | |
| "$APP_DIR/.env.s3" \ | |
| "$APP_DIR/.env.storage" \ | |
| "$APP_DIR/.registry_user" \ | |
| "$APP_DIR/.registry_pass" | |
| # Fingerprint | |
| FINGERPRINT=$(generate_fingerprint) | |
| echo "$FINGERPRINT" > "$APP_DIR/.fingerprint" | |
| echo | |
| log_info "Machine Fingerprint:" | |
| echo -e " ${BOLD}${FINGERPRINT}${NC}" | |
| log_warn "Kirimkan fingerprint ini ke admin untuk aktivasi lisensi." | |
| log_ok "Semua konfigurasi berhasil dibuat" | |
| fi | |
| # ─── STEP 4: REGISTRY LOGIN & PULL ─────────────────────────────────────────── | |
| log_section "Step 4: Login Registry & Pull Images" | |
| REG_USER=$(cat "$APP_DIR/.registry_user" 2>/dev/null || true) | |
| REG_PASS=$(cat "$APP_DIR/.registry_pass" 2>/dev/null || true) | |
| if [[ -z "$REG_USER" || -z "$REG_PASS" ]]; then | |
| log_warn "Credentials registry tidak ditemukan di cache." | |
| prompt_required REG_USER "Registry Username" | |
| prompt_secret REG_PASS "Registry Password" | |
| fi | |
| log_info "Login ke $REGISTRY_HOST..." | |
| echo "$REG_PASS" | docker login "$REGISTRY_HOST" \ | |
| --username "$REG_USER" \ | |
| --password-stdin \ | |
| || die "Gagal login ke registry. Periksa username/password." | |
| log_ok "Login berhasil" | |
| log_info "Pulling Docker images (mungkin membutuhkan beberapa menit)..." | |
| docker compose -f "$APP_DIR/docker-compose.yml" \ | |
| --env-file "$APP_DIR/.env" \ | |
| pull \ | |
| || die "Gagal pull Docker images." | |
| log_ok "Semua image berhasil di-pull" | |
| # ─── STEP 5: JALANKAN ──────────────────────────────────────────────────────── | |
| log_section "Step 5: Menjalankan Aplikasi" | |
| docker compose -f "$APP_DIR/docker-compose.yml" \ | |
| --env-file "$APP_DIR/.env" \ | |
| up -d \ | |
| || die "Gagal menjalankan compose." | |
| log_info "Menunggu container startup (20 detik)..." | |
| sleep 20 | |
| log_info "Status container:" | |
| docker compose -f "$APP_DIR/docker-compose.yml" ps | |
| # ─── DONE ───────────────────────────────────────────────────────────────────── | |
| log_section "Setup Selesai" | |
| APP_URL_DISPLAY=$(grep "^WEB_URL=" "$APP_DIR/.env.backend" | cut -d= -f2-) | |
| echo -e " | |
| ${GREEN}${BOLD}✓ Legal Plus Enterprise berhasil diinstall!${NC} | |
| ${BOLD}Direktori${NC} : $APP_DIR | |
| ${BOLD}URL Aplikasi${NC} : ${APP_URL_DISPLAY} | |
| ${BOLD}Fingerprint${NC} : $(cat "$APP_DIR/.fingerprint") | |
| ${BOLD}File konfigurasi:${NC} | |
| $APP_DIR/.env.backend — konfigurasi backend & S3 | |
| $APP_DIR/.env.mongodb — credentials MongoDB | |
| $APP_DIR/.env.s3 — credentials Garage S3 | |
| $APP_DIR/.env.storage — konfigurasi storage service | |
| $APP_DIR/garage.toml — konfigurasi Garage | |
| ${BOLD}Perintah berguna:${NC} | |
| Log semua service : docker compose -f $APP_DIR/docker-compose.yml logs -f | |
| Log service tertentu: docker compose -f $APP_DIR/docker-compose.yml logs -f backend | |
| Restart : docker compose -f $APP_DIR/docker-compose.yml restart | |
| Stop : docker compose -f $APP_DIR/docker-compose.yml down | |
| Update image : docker compose -f $APP_DIR/docker-compose.yml pull \\ | |
| && docker compose -f $APP_DIR/docker-compose.yml up -d | |
| ${YELLOW}Hubungi support jika ada masalah.${NC} | |
| " |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment