Last active
April 9, 2026 09:54
-
-
Save tvd12/3b0672cd9f7e4f99af8e6ab999048b95 to your computer and use it in GitHub Desktop.
install-ezyplatform.sh
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 | |
| set -euo pipefail | |
| export LANG=C.UTF-8 | |
| export LC_ALL=C.UTF-8 | |
| usage() { | |
| cat <<'EOF' | |
| Usage: | |
| bash install-ezyplatform.sh [mysql_root_password] [ezyplatform_download_url] | |
| sudo bash install-ezyplatform.sh [mysql_root_password] [ezyplatform_download_url] | |
| sudo MYSQL_ROOT_PASSWORD='RootPassword123!' bash install-ezyplatform.sh | |
| sudo DB_PASSWORD='AppPassword123!' bash install-ezyplatform.sh | |
| Example: | |
| bash install-ezyplatform.sh | |
| sudo bash install-ezyplatform.sh | |
| sudo bash install-ezyplatform.sh 'RootPassword123!' | |
| sudo bash install-ezyplatform.sh 'RootPassword123!' 'https://ezyplatform.com/api/v1/platforms/latest/download' | |
| sudo bash install-ezyplatform.sh 'https://ezyplatform.com/api/v1/platforms/latest/download' | |
| Environment variables: | |
| DB_NAME Default: ezyplatform | |
| DB_USER Default: ezyplatform | |
| DB_PASSWORD Default: random 24-character password | |
| MYSQL_ROOT_PASSWORD Default: argument 1 if provided, otherwise unchanged | |
| EZYPLATFORM_DIR Default: current directory + /ezyplatform | |
| EZYPLATFORM_ZIP Default: current directory + /ezyplatform.zip | |
| EZYPLATFORM_URL Default: positional URL argument if provided, otherwise | |
| https://ezyplatform.com/api/v1/platforms/latest/download | |
| What this script does: | |
| - Installs OpenJDK 8 (or OpenJDK 11 if 8 is unavailable), MySQL, Nginx, Certbot, unzip, wget | |
| - Optionally configures MySQL root password if provided | |
| - Creates MySQL database/user for EzyPlatform with a DB password from DB_PASSWORD or random_password() | |
| - Downloads and extracts EzyPlatform | |
| - Writes settings/setup.properties for MySQL | |
| What this script does NOT do: | |
| - Configure Nginx virtual host | |
| - Run Certbot setup | |
| - Complete the web-based EzyPlatform admin/web setup | |
| EOF | |
| } | |
| if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then | |
| usage | |
| exit 0 | |
| fi | |
| if [[ "${EUID}" -ne 0 ]]; then | |
| if ! command -v sudo >/dev/null 2>&1; then | |
| echo "This script needs root privileges and could not find sudo." | |
| exit 1 | |
| fi | |
| echo "Root privileges are required. Re-running with sudo..." | |
| exec sudo -E bash "$0" "$@" | |
| fi | |
| random_password() { | |
| local length="${1:-24}" | |
| local password="" | |
| while [[ "${#password}" -lt "${length}" ]]; do | |
| password+="$( | |
| tr -dc 'A-Za-z0-9' </dev/urandom | head -c "${length}" || true | |
| )" | |
| done | |
| printf '%s' "${password:0:length}" | |
| } | |
| resolve_db_password() { | |
| local setup_file="${EZYPLATFORM_DIR}/settings/setup.properties" | |
| local existing_password="" | |
| if [[ -f "${setup_file}" ]]; then | |
| existing_password="$( | |
| sed -n 's/^datasource\.password=//p' "${setup_file}" | head -n 1 | |
| )" | |
| fi | |
| if [[ -n "${existing_password}" && "${existing_password}" != "12345678" ]]; then | |
| printf '%s' "${existing_password}" | |
| return 0 | |
| fi | |
| random_password | |
| } | |
| ARG1="${1:-}" | |
| ARG2="${2:-}" | |
| POSITIONAL_MYSQL_ROOT_PASSWORD="" | |
| POSITIONAL_EZYPLATFORM_URL="" | |
| if [[ -n "${ARG1}" && "${ARG1}" =~ ^https?:// ]]; then | |
| POSITIONAL_EZYPLATFORM_URL="${ARG1}" | |
| else | |
| POSITIONAL_MYSQL_ROOT_PASSWORD="${ARG1}" | |
| POSITIONAL_EZYPLATFORM_URL="${ARG2}" | |
| fi | |
| MYSQL_ROOT_PASSWORD="${MYSQL_ROOT_PASSWORD:-${POSITIONAL_MYSQL_ROOT_PASSWORD}}" | |
| CURRENT_DIR="$(pwd -P)" | |
| EZYPLATFORM_DIR="${EZYPLATFORM_DIR:-${CURRENT_DIR}/ezyplatform}" | |
| EZYPLATFORM_ZIP="${EZYPLATFORM_ZIP:-${CURRENT_DIR}/ezyplatform.zip}" | |
| DB_PASSWORD="${DB_PASSWORD:-$(resolve_db_password)}" | |
| DB_NAME="${DB_NAME:-ezyplatform}" | |
| DB_USER="${DB_USER:-ezyplatform}" | |
| DEFAULT_EZYPLATFORM_URL="https://ezyplatform.com/api/v1/platforms/latest/download" | |
| EZYPLATFORM_URL="${EZYPLATFORM_URL:-${POSITIONAL_EZYPLATFORM_URL:-$DEFAULT_EZYPLATFORM_URL}}" | |
| JAVA_HOME_PATH="" | |
| EZYPLATFORM_ALREADY_EXISTS=0 | |
| log() { | |
| printf '\n[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" | |
| } | |
| require_command() { | |
| if ! command -v "$1" >/dev/null 2>&1; then | |
| echo "Missing required command: $1" | |
| exit 1 | |
| fi | |
| } | |
| is_package_installed() { | |
| dpkg -s "$1" >/dev/null 2>&1 | |
| } | |
| is_package_available() { | |
| apt-cache show "$1" >/dev/null 2>&1 | |
| } | |
| has_working_java() { | |
| command -v java >/dev/null 2>&1 && java -version >/dev/null 2>&1 | |
| } | |
| is_port_9090_listening() { | |
| ss -ltn 2>/dev/null | awk '{print $4}' | grep -Eq '(^|:)9090$' | |
| } | |
| wait_for_mysql() { | |
| for _ in $(seq 1 30); do | |
| if mysqladmin ping --silent >/dev/null 2>&1 || systemctl is-active --quiet mysql; then | |
| return 0 | |
| fi | |
| sleep 2 | |
| done | |
| echo "MySQL did not become ready in time." | |
| exit 1 | |
| } | |
| mysql_exec_root_socket() { | |
| mysql --protocol=socket -uroot -e "$1" | |
| } | |
| mysql_exec_root_password() { | |
| if [[ -z "${MYSQL_ROOT_PASSWORD}" ]]; then | |
| return 1 | |
| fi | |
| mysql --protocol=socket -uroot -p"${MYSQL_ROOT_PASSWORD}" -e "$1" | |
| } | |
| mysql_exec_root_default() { | |
| mysql -e "$1" | |
| } | |
| mysql_exec_root_auto() { | |
| if mysql_exec_root_password "$1" >/dev/null 2>&1; then | |
| mysql_exec_root_password "$1" | |
| return 0 | |
| fi | |
| if mysql_exec_root_socket "$1" >/dev/null 2>&1; then | |
| mysql_exec_root_socket "$1" | |
| return 0 | |
| fi | |
| if mysql_exec_root_default "$1" >/dev/null 2>&1; then | |
| mysql_exec_root_default "$1" | |
| return 0 | |
| fi | |
| return 1 | |
| } | |
| configure_mysql_root_password() { | |
| if mysql_exec_root_password "SELECT 1;" >/dev/null 2>&1; then | |
| return 0 | |
| fi | |
| if [[ -z "${MYSQL_ROOT_PASSWORD}" ]]; then | |
| log "MySQL root password not provided, keeping current root authentication method" | |
| return 0 | |
| fi | |
| log "Configuring MySQL root password" | |
| if mysql_exec_root_socket "SELECT 1;" >/dev/null 2>&1 || mysql_exec_root_default "SELECT 1;" >/dev/null 2>&1; then | |
| if mysql_exec_root_auto "ALTER USER 'root'@'localhost' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}'; FLUSH PRIVILEGES;" >/dev/null 2>&1; then | |
| return 0 | |
| fi | |
| log "Could not set MySQL root password automatically, continuing with current root authentication method" | |
| return 0 | |
| fi | |
| echo "Unable to connect to MySQL as root by socket or provided password." | |
| exit 1 | |
| } | |
| create_database_and_user() { | |
| log "Creating MySQL database and user" | |
| mysql_exec_root_auto "CREATE DATABASE IF NOT EXISTS \`${DB_NAME}\` DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;" | |
| mysql_exec_root_auto "CREATE USER IF NOT EXISTS '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASSWORD}';" | |
| mysql_exec_root_auto "ALTER USER '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASSWORD}';" | |
| mysql_exec_root_auto "GRANT ALL PRIVILEGES ON \`${DB_NAME}\`.* TO '${DB_USER}'@'localhost'; FLUSH PRIVILEGES;" | |
| } | |
| install_packages() { | |
| log "Updating apt package index" | |
| apt-get update | |
| local packages_to_install=() | |
| local java_package="" | |
| if has_working_java; then | |
| log "Java is already installed, skipping" | |
| else | |
| if is_package_installed openjdk-8-jre-headless || is_package_installed openjdk-11-jre-headless; then | |
| log "Java package appears installed but 'java' is not runnable; reinstalling Java" | |
| fi | |
| if is_package_available openjdk-8-jre-headless; then | |
| java_package="openjdk-8-jre-headless" | |
| elif is_package_available openjdk-11-jre-headless; then | |
| java_package="openjdk-11-jre-headless" | |
| else | |
| echo "Could not find openjdk-8-jre-headless or openjdk-11-jre-headless in apt repositories." | |
| exit 1 | |
| fi | |
| log "Selected Java package: ${java_package}" | |
| packages_to_install+=("${java_package}") | |
| fi | |
| if command -v mysql >/dev/null 2>&1 || is_package_installed mysql-server; then | |
| log "MySQL is already installed, skipping" | |
| else | |
| packages_to_install+=(mysql-server) | |
| fi | |
| if command -v nginx >/dev/null 2>&1 || is_package_installed nginx; then | |
| log "Nginx is already installed, skipping" | |
| else | |
| packages_to_install+=(nginx) | |
| fi | |
| if command -v certbot >/dev/null 2>&1 || is_package_installed certbot; then | |
| log "Certbot is already installed, skipping" | |
| else | |
| packages_to_install+=(certbot) | |
| fi | |
| if is_package_installed python3-certbot-nginx; then | |
| log "python3-certbot-nginx is already installed, skipping" | |
| else | |
| packages_to_install+=(python3-certbot-nginx) | |
| fi | |
| if ! command -v unzip >/dev/null 2>&1 && ! is_package_installed unzip; then | |
| packages_to_install+=(unzip) | |
| fi | |
| if ! command -v wget >/dev/null 2>&1 && ! is_package_installed wget; then | |
| packages_to_install+=(wget) | |
| fi | |
| if [[ ${#packages_to_install[@]} -eq 0 ]]; then | |
| log "All required packages are already installed" | |
| return 0 | |
| fi | |
| log "Installing missing packages: ${packages_to_install[*]}" | |
| DEBIAN_FRONTEND=noninteractive apt-get install -y "${packages_to_install[@]}" | |
| } | |
| configure_java_home() { | |
| log "Configuring JAVA_HOME" | |
| local java_bin="" | |
| local candidate="" | |
| if [[ -n "${JAVA_HOME:-}" && -x "${JAVA_HOME}/bin/java" ]]; then | |
| JAVA_HOME_PATH="${JAVA_HOME}" | |
| fi | |
| if [[ -z "${JAVA_HOME_PATH}" ]]; then | |
| java_bin="$(readlink -f "$(command -v java 2>/dev/null)" 2>/dev/null || true)" | |
| if [[ -n "${java_bin}" ]]; then | |
| candidate="$(dirname "$(dirname "${java_bin}")")" | |
| if [[ -x "${candidate}/bin/java" ]]; then | |
| JAVA_HOME_PATH="${candidate}" | |
| elif [[ "$(basename "${candidate}")" == "jre" ]]; then | |
| candidate="$(dirname "${candidate}")" | |
| if [[ -x "${candidate}/bin/java" ]]; then | |
| JAVA_HOME_PATH="${candidate}" | |
| fi | |
| fi | |
| fi | |
| fi | |
| if [[ -z "${JAVA_HOME_PATH}" ]] && command -v update-alternatives >/dev/null 2>&1; then | |
| java_bin="$(update-alternatives --list java 2>/dev/null | head -n 1 || true)" | |
| if [[ -n "${java_bin}" ]]; then | |
| candidate="$(dirname "$(dirname "${java_bin}")")" | |
| if [[ -x "${candidate}/bin/java" ]]; then | |
| JAVA_HOME_PATH="${candidate}" | |
| elif [[ "$(basename "${candidate}")" == "jre" ]]; then | |
| candidate="$(dirname "${candidate}")" | |
| if [[ -x "${candidate}/bin/java" ]]; then | |
| JAVA_HOME_PATH="${candidate}" | |
| fi | |
| fi | |
| fi | |
| fi | |
| if [[ -z "${JAVA_HOME_PATH}" ]]; then | |
| for candidate in /usr/lib/jvm/*; do | |
| if [[ -x "${candidate}/bin/java" ]]; then | |
| JAVA_HOME_PATH="${candidate}" | |
| break | |
| fi | |
| done | |
| fi | |
| if [[ -z "${JAVA_HOME_PATH}" || ! -x "${JAVA_HOME_PATH}/bin/java" ]]; then | |
| echo "Could not determine a valid JAVA_HOME. Please set JAVA_HOME before running this script." | |
| exit 1 | |
| fi | |
| cat >/etc/profile.d/ezyplatform-java.sh <<EOF | |
| export JAVA_HOME=${JAVA_HOME_PATH} | |
| export PATH=\$JAVA_HOME/bin:\$PATH | |
| EOF | |
| chmod 0644 /etc/profile.d/ezyplatform-java.sh | |
| } | |
| download_and_extract_ezyplatform() { | |
| if [[ -f "${EZYPLATFORM_DIR}/settings/setup.properties" ]]; then | |
| EZYPLATFORM_ALREADY_EXISTS=1 | |
| log "EzyPlatform directory already exists at ${EZYPLATFORM_DIR}, skipping download and extraction" | |
| return 0 | |
| fi | |
| log "Downloading EzyPlatform package" | |
| rm -f "${EZYPLATFORM_ZIP}" | |
| wget -O "${EZYPLATFORM_ZIP}" "${EZYPLATFORM_URL}" | |
| log "Extracting EzyPlatform to ${EZYPLATFORM_DIR}" | |
| rm -rf "${EZYPLATFORM_DIR}" | |
| mkdir -p "${EZYPLATFORM_DIR}" | |
| unzip -oq "${EZYPLATFORM_ZIP}" -d "${EZYPLATFORM_DIR}" | |
| if [[ -d "${EZYPLATFORM_DIR}/ezyplatform" ]]; then | |
| local extracted_dir | |
| extracted_dir="${EZYPLATFORM_DIR}/ezyplatform" | |
| find "${extracted_dir}" -mindepth 1 -maxdepth 1 -exec mv {} "${EZYPLATFORM_DIR}/" \; | |
| rmdir "${extracted_dir}" | |
| fi | |
| if [[ ! -f "${EZYPLATFORM_DIR}/settings/setup.properties" ]]; then | |
| echo "Could not find ${EZYPLATFORM_DIR}/settings/setup.properties after extraction." | |
| exit 1 | |
| fi | |
| } | |
| write_setup_properties() { | |
| if is_port_9090_listening; then | |
| log "Port 9090 is already in use, assuming admin is already running" | |
| fi | |
| if [[ "${EZYPLATFORM_ALREADY_EXISTS}" -eq 1 ]]; then | |
| log "Existing EzyPlatform setup detected, skipping setup.properties update" | |
| return 0 | |
| fi | |
| log "Writing EzyPlatform setup.properties" | |
| cat >"${EZYPLATFORM_DIR}/settings/setup.properties" <<EOF | |
| datasource.jdbc_url=jdbc:mysql://localhost:3306/${DB_NAME} | |
| datasource.driver_class_name=com.mysql.cj.jdbc.Driver | |
| datasource.username=${DB_USER} | |
| datasource.password=${DB_PASSWORD} | |
| tables.create_manually=false | |
| EOF | |
| } | |
| enable_services() { | |
| log "Enabling and starting services" | |
| systemctl enable mysql || true | |
| systemctl enable nginx || true | |
| systemctl start mysql | |
| systemctl start nginx || true | |
| } | |
| start_ezyplatform_admin() { | |
| if is_port_9090_listening; then | |
| log "Port 9090 is already in use, skipping automatic admin startup" | |
| return 0 | |
| fi | |
| if [[ ! -f "${EZYPLATFORM_DIR}/cli.sh" ]]; then | |
| echo "Could not find ${EZYPLATFORM_DIR}/cli.sh to restart admin." | |
| exit 1 | |
| fi | |
| log "Starting EzyPlatform admin" | |
| ( | |
| cd "${EZYPLATFORM_DIR}" | |
| bash cli.sh "start admin" | |
| ) | |
| } | |
| print_summary() { | |
| cat <<EOF | |
| Installation completed. | |
| Database: | |
| name: ${DB_NAME} | |
| user: ${DB_USER} | |
| password: ${DB_PASSWORD} | |
| EzyPlatform: | |
| directory: ${EZYPLATFORM_DIR} | |
| setup file: ${EZYPLATFORM_DIR}/settings/setup.properties | |
| MySQL root: | |
| password: ${MYSQL_ROOT_PASSWORD:-unchanged} | |
| Next steps: | |
| 1. Open: | |
| http://<server-ip>:9090/setup-admin | |
| 2. Complete admin setup in the browser. | |
| 3. If you want to inspect the log: | |
| cd ${EZYPLATFORM_DIR} | |
| tail -f logs/admin-server.log | |
| Notes: | |
| - Nginx and Certbot were installed only. No site or SSL configuration was created. | |
| - Admin is started automatically at the end of the installation. | |
| - Admin access is expected directly via IP:9090 as requested. | |
| - If port 9090 is already listening, the script keeps the existing service and does not stop/restart it. | |
| EOF | |
| } | |
| require_command apt-get | |
| require_command systemctl | |
| require_command wget | |
| require_command unzip | |
| require_command ss | |
| install_packages | |
| enable_services | |
| wait_for_mysql | |
| configure_mysql_root_password | |
| create_database_and_user | |
| configure_java_home | |
| download_and_extract_ezyplatform | |
| write_setup_properties | |
| start_ezyplatform_admin | |
| log "Java version" | |
| java -version || true | |
| print_summary |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment