Skip to content

Instantly share code, notes, and snippets.

@askareija
Last active June 5, 2026 08:19
Show Gist options
  • Select an option

  • Save askareija/7fef0a3ad91813e5efe1c343b821b144 to your computer and use it in GitHub Desktop.

Select an option

Save askareija/7fef0a3ad91813e5efe1c343b821b144 to your computer and use it in GitHub Desktop.
LP Install script
#!/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