Last active
April 28, 2025 21:46
-
-
Save morrning/4fbeaa2bb92e994c313b025e344305d7 to your computer and use it in GitHub Desktop.
Install hesabix standalone on ubuntu servers
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
#!/bin/bash | |
# Hesabix Installation Script | |
# Version: 2.6 | |
# Modernized and optimized for Ubuntu 24.04 LTS | |
# Last Updated: April 28, 2025 | |
# Exit on any error | |
set -e | |
# Colors for better UI | |
declare -r RED='\e[31m' | |
declare -r GREEN='\e[32m' | |
declare -r YELLOW='\e[33m' | |
declare -r BLUE='\e[34m' | |
declare -r NC='\e[0m' | |
declare -r BOLD='\e[1m' | |
declare -r UNDERLINE='\e[4m' | |
# ASCII Art | |
print_logo() { | |
echo -e "${BOLD}${BLUE}" | |
echo " _ _ ___ ___ _ ___ ___ __ __" | |
echo " | || | | __| / __| /_\ | _ ) |_ _| \ \/ /" | |
echo " | __ | | _| \__ \ / _ \ | _ \ | | > < " | |
echo " |_||_| |___| |___/ /_/ \_\ |___/ |___| /_/\_\\" | |
echo -e "${NC}" | |
} | |
# Print header | |
print_header() { | |
clear | |
print_logo | |
echo -e "${BOLD}${BLUE}=================================================${NC}" | |
echo -e "${BOLD}${BLUE} Hesabix Installation Script ${NC}" | |
echo -e "${BOLD}${BLUE}=================================================${NC}" | |
echo -e "${YELLOW}Hesabix is a powerful open-source accounting software${NC}" | |
echo -e "${YELLOW}developed with ❤ by Babak Alizadeh (alizadeh.babak)${NC}" | |
echo -e "${YELLOW}License: GNU GPL v3${NC}" | |
echo -e "${YELLOW}Website: ${UNDERLINE}https://hesabix.ir${NC}" | |
echo -e "${YELLOW}Support us: ${UNDERLINE}https://hesabix.ir/page/sponsors${NC} ❤" | |
echo -e "${BOLD}${BLUE}=================================================${NC}\n" | |
} | |
# Show the header immediately | |
print_header | |
# Configuration | |
declare -r LOG_FILE="/var/log/hesabix_install.log" | |
declare -r LOG_LEVEL="DEBUG" # Options: DEBUG, INFO, WARNING, ERROR | |
declare -r REQUIRED_DISK_SPACE_MB=2000 | |
declare -r REQUIRED_MEMORY_MB=1024 | |
declare -r MIN_PHP_VERSION="8.2" | |
declare -r NODE_VERSION="20" | |
declare -r COMPOSER_TIMEOUT=600 | |
declare -r NPM_TIMEOUT=600 | |
# Global variables | |
declare SEND_TELEMETRY=false | |
declare domain="" | |
declare apache_user="www-data" | |
# Function to log messages in JSON format | |
log_message() { | |
local level="$1" | |
local message="$2" | |
local timestamp | |
timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ") | |
# Create JSON log entry | |
local log_entry | |
log_entry=$(printf '{"timestamp":"%s","level":"%s","message":"%s"}\n' "$timestamp" "$level" "$message") | |
# Write to log file | |
echo "$log_entry" >> "$LOG_FILE" | |
# Display to console based on level | |
case "$level" in | |
"INFO") | |
echo -e "${GREEN}[INFO] $message${NC}" | |
;; | |
"WARNING") | |
echo -e "${YELLOW}[WARNING] $message${NC}" | |
;; | |
"ERROR") | |
echo -e "${RED}[ERROR] $message${NC}" | |
;; | |
"DEBUG") | |
[[ "$LOG_LEVEL" == "DEBUG" ]] && echo -e "${BLUE}[DEBUG] $message${NC}" | |
;; | |
esac | |
} | |
# Function to initialize logging | |
init_logging() { | |
mkdir -p "$(dirname "$LOG_FILE")" || { | |
echo -e "${RED}Error: Cannot create log directory${NC}" | |
exit 1 | |
} | |
touch "$LOG_FILE" || { | |
echo -e "${RED}Error: Cannot create log file${NC}" | |
exit 1 | |
} | |
chmod 644 "$LOG_FILE" | |
log_message "INFO" "Hesabix installation script started" | |
log_message "INFO" "Log file: $LOG_FILE" | |
log_message "INFO" "To view logs: tail -f $LOG_FILE" | |
} | |
# Function to handle errors | |
handle_error() { | |
local message="$1" | |
local exit_code="${2:-1}" | |
log_message "ERROR" "$message" | |
log_message "ERROR" "Installation failed. Check logs: $LOG_FILE" | |
exit "$exit_code" | |
} | |
# Function to check if command exists | |
command_exists() { | |
command -v "$1" >/dev/null 2>&1 | |
} | |
# Function to check internet connectivity | |
check_internet() { | |
log_message "INFO" "Checking internet connectivity..." | |
if ! ping -c 1 8.8.8.8 >/dev/null 2>&1; then | |
handle_error "No internet connection detected. Please ensure the server has internet access." | |
fi | |
log_message "INFO" "Internet connectivity verified" | |
} | |
# Function to validate system requirements | |
check_system_requirements() { | |
log_message "INFO" "Checking system requirements..." | |
# Check root privileges | |
[[ "$EUID" -ne 0 ]] && handle_error "This script must be run as root" | |
# Check OS compatibility | |
if [[ -f /etc/os-release ]]; then | |
. /etc/os-release | |
log_message "INFO" "Detected OS: $NAME $VERSION" | |
[[ ! "$ID" =~ ^(ubuntu|debian)$ ]] && handle_error "Only Ubuntu and Debian are supported" | |
else | |
handle_error "Cannot determine OS type" | |
fi | |
# Check disk space | |
local available_space | |
available_space=$(df -m / | awk 'NR==2 {print $4}') | |
log_message "DEBUG" "Required disk space: ${REQUIRED_DISK_SPACE_MB}MB" | |
log_message "DEBUG" "Available disk space: ${available_space}MB" | |
[[ "$available_space" -lt "$REQUIRED_DISK_SPACE_MB" ]] && \ | |
handle_error "Insufficient disk space. Required: ${REQUIRED_DISK_SPACE_MB}MB, Available: ${available_space}MB" | |
# Check memory | |
local total_memory | |
total_memory=$(free -m | awk '/^Mem:/{print $2}') | |
log_message "DEBUG" "Required memory: ${REQUIRED_MEMORY_MB}MB" | |
log_message "DEBUG" "Total memory: ${total_memory}MB" | |
[[ "$total_memory" -lt "$REQUIRED_MEMORY_MB" ]] && \ | |
log_message "WARNING" "Low memory detected. Performance may be affected" | |
log_message "INFO" "System requirements check completed" | |
} | |
# Function to update package lists | |
update_packages() { | |
log_message "INFO" "Updating package lists..." | |
apt-get update -y || handle_error "Failed to update package lists" | |
} | |
# Function to install required tools | |
install_tools() { | |
local tools=("curl" "coreutils" "git" "unzip") | |
for tool in "${tools[@]}"; do | |
if ! command_exists "$tool"; then | |
log_message "INFO" "Installing $tool..." | |
apt-get install -y "$tool" || handle_error "Failed to install $tool" | |
log_message "INFO" "$tool installed successfully" | |
else | |
log_message "INFO" "$tool is already installed" | |
fi | |
done | |
} | |
# Function to get installed PHP version | |
get_php_version() { | |
local version | |
version=$(php -v | head -n 1 | awk '{print $2}' | cut -d'.' -f1,2) | |
echo "$version" | |
} | |
# Function to get all installed PHP versions | |
get_installed_php_versions() { | |
local versions=() | |
for version_dir in /etc/php/*; do | |
if [[ -d "$version_dir" && "$version_dir" =~ /etc/php/[0-9]+\.[0-9]+$ ]]; then | |
versions+=("$(basename "$version_dir")") | |
fi | |
done | |
echo "${versions[@]}" | |
} | |
# Function to check if all required extensions are installed for all PHP versions | |
check_required_extensions() { | |
local missing_extensions=() | |
local installed_versions | |
installed_versions=($(get_installed_php_versions)) | |
for version in "${installed_versions[@]}"; do | |
log_message "INFO" "Checking required extensions for PHP $version..." | |
for ext in raphf http dom xml gd curl simplexml xmlwriter zip; do | |
if ! php"$version" -m | grep -q "$ext"; then | |
missing_extensions+=("php${version}-${ext}") | |
log_message "WARNING" "Extension $ext is missing for PHP $version" | |
fi | |
done | |
done | |
if [[ ${#missing_extensions[@]} -gt 0 ]]; then | |
echo -e "\nWarning: The following extensions are missing:" | |
printf '%s\n' "${missing_extensions[@]}" | |
echo -e "\nDo you want to install them now?" | |
read -p "Install missing extensions? (y/n) [y]: " response | |
if [[ "$response" =~ ^[Yy]$ ]] || [[ -z "$response" ]]; then | |
log_message "INFO" "Installing missing extensions..." | |
# First try to install from default repositories | |
if ! apt-get install -y "${missing_extensions[@]}"; then | |
log_message "WARNING" "Failed to install from default repositories. Trying custom repositories..." | |
# Add custom repository | |
LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/php || log_message "WARNING" "PPA already exists" | |
update_packages | |
# Try installing again | |
apt-get install -y "${missing_extensions[@]}" || { | |
log_message "ERROR" "Failed to install missing extensions even with custom repository" | |
return 1 | |
} | |
fi | |
# Enable extensions after installation | |
for version in "${installed_versions[@]}"; do | |
for ext in raphf http dom xml gd curl simplexml xmlwriter zip; do | |
if ! php"$version" -m | grep -q "$ext"; then | |
log_message "INFO" "Enabling $ext for PHP $version..." | |
phpenmod -v "$version" "$ext" || log_message "WARNING" "Failed to enable $ext for CLI in version $version" | |
phpenmod -v "$version" -s apache2 "$ext" || log_message "WARNING" "Failed to enable $ext for Apache in version $version" | |
fi | |
done | |
done | |
# Verify extensions are now installed | |
local still_missing=() | |
for version in "${installed_versions[@]}"; do | |
for ext in raphf http dom xml gd curl simplexml xmlwriter zip; do | |
if ! php"$version" -m | grep -q "$ext"; then | |
still_missing+=("php${version}-${ext}") | |
fi | |
done | |
done | |
if [[ ${#still_missing[@]} -gt 0 ]]; then | |
echo -e "\nWarning: The following extensions are still missing after installation:" | |
printf '%s\n' "${still_missing[@]}" | |
return 1 | |
fi | |
# Restart Apache | |
systemctl restart apache2 || log_message "WARNING" "Failed to restart Apache" | |
else | |
log_message "WARNING" "User chose not to install missing extensions" | |
return 1 | |
fi | |
fi | |
return 0 | |
} | |
# Function to verify CLI extensions | |
verify_cli_extensions() { | |
local version="$1" | |
log_message "INFO" "Verifying CLI extensions for PHP $version..." | |
# Get the list of enabled extensions from CLI | |
local enabled_extensions | |
enabled_extensions=$(php"$version" -m) | |
# Check each required extension | |
for ext in raphf http dom xml gd curl simplexml xmlwriter zip intl mbstring mysql bcmath; do | |
if ! echo "$enabled_extensions" | grep -q "^$ext$"; then | |
log_message "ERROR" "Extension $ext is not enabled in CLI for PHP $version" | |
log_message "INFO" "Attempting to enable $ext for CLI..." | |
# Try to enable the extension | |
phpenmod -v "$version" "$ext" || { | |
log_message "ERROR" "Failed to enable $ext for CLI in version $version" | |
return 1 | |
} | |
# Verify again after enabling | |
enabled_extensions=$(php"$version" -m) | |
if ! echo "$enabled_extensions" | grep -q "^$ext$"; then | |
log_message "ERROR" "Extension $ext is still not enabled in CLI for PHP $version" | |
return 1 | |
fi | |
fi | |
done | |
return 0 | |
} | |
# Function to install PHP and extensions | |
install_php() { | |
log_message "INFO" "Checking PHP installation..." | |
# Check if php-cli is installed | |
if ! command_exists php; then | |
log_message "INFO" "Installing php-cli..." | |
apt-get install -y php-cli || handle_error "Failed to install php-cli" | |
fi | |
# Get current PHP version | |
local current_version | |
current_version=$(get_php_version) | |
log_message "DEBUG" "Current PHP version: $current_version" | |
# Check if PHP version meets minimum requirement | |
if [[ "$(echo "$current_version >= $MIN_PHP_VERSION" | bc -l)" -ne 1 ]]; then | |
log_message "INFO" "Installing PHP $MIN_PHP_VERSION or higher..." | |
# First try to install from default Ubuntu repositories | |
log_message "INFO" "Attempting to install PHP from default Ubuntu repositories..." | |
apt-get install -y software-properties-common | |
local php_packages=( | |
"php${MIN_PHP_VERSION}" | |
"php${MIN_PHP_VERSION}-cli" | |
"libapache2-mod-php${MIN_PHP_VERSION}" | |
"php${MIN_PHP_VERSION}-intl" | |
"php${MIN_PHP_VERSION}-mbstring" | |
"php${MIN_PHP_VERSION}-zip" | |
"php${MIN_PHP_VERSION}-gd" | |
"php${MIN_PHP_VERSION}-mysql" | |
"php${MIN_PHP_VERSION}-curl" | |
"php${MIN_PHP_VERSION}-xml" | |
"php${MIN_PHP_VERSION}-bcmath" | |
"php${MIN_PHP_VERSION}-raphf" | |
"php${MIN_PHP_VERSION}-http" | |
"php${MIN_PHP_VERSION}-dom" | |
"php${MIN_PHP_VERSION}-simplexml" | |
"php${MIN_PHP_VERSION}-xmlwriter" | |
) | |
# Try installing from default repositories | |
if ! apt-get install -y "${php_packages[@]}"; then | |
log_message "WARNING" "Failed to install PHP from default repositories. Trying custom repositories..." | |
# Add custom repository if default installation fails | |
LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/php || log_message "WARNING" "PPA already exists" | |
update_packages | |
# Try installing again with custom repository | |
apt-get install -y "${php_packages[@]}" || handle_error "Failed to install PHP packages" | |
fi | |
fi | |
# Get all installed PHP versions | |
local installed_versions | |
installed_versions=($(get_installed_php_versions)) | |
log_message "INFO" "Found installed PHP versions: ${installed_versions[*]}" | |
# Install and configure extensions for all PHP versions | |
for version in "${installed_versions[@]}"; do | |
log_message "INFO" "Configuring PHP $version..." | |
# Install all required extensions for this version | |
local required_extensions=( | |
"php${version}-raphf" | |
"php${version}-http" | |
"php${version}-dom" | |
"php${version}-xml" | |
"php${version}-gd" | |
"php${version}-curl" | |
"php${version}-simplexml" | |
"php${version}-xmlwriter" | |
"php${version}-zip" | |
"php${version}-intl" | |
"php${version}-mbstring" | |
"php${version}-mysql" | |
"php${version}-bcmath" | |
) | |
# Install extensions | |
log_message "INFO" "Installing required extensions for PHP $version..." | |
apt-get install -y "${required_extensions[@]}" || { | |
log_message "WARNING" "Failed to install some extensions for PHP $version. Trying custom repository..." | |
# Add custom repository if needed | |
LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/php || log_message "WARNING" "PPA already exists" | |
update_packages | |
# Try installing again | |
apt-get install -y "${required_extensions[@]}" || handle_error "Failed to install PHP extensions for version $version" | |
} | |
# Enable all extensions | |
for ext in raphf http dom xml gd curl simplexml xmlwriter zip intl mbstring mysql bcmath; do | |
log_message "INFO" "Enabling $ext for PHP $version..." | |
phpenmod -v "$version" "$ext" || log_message "WARNING" "Failed to enable $ext for CLI in version $version" | |
phpenmod -v "$version" -s apache2 "$ext" || log_message "WARNING" "Failed to enable $ext for Apache in version $version" | |
done | |
# Create PHP configuration for both CLI and Apache | |
for sapi in cli apache2; do | |
if [[ -d "/etc/php/${version}/${sapi}/conf.d" ]]; then | |
cat > "/etc/php/${version}/${sapi}/conf.d/99-hesabix.ini" << EOF | |
extension=raphf.so | |
extension=http.so | |
extension=dom.so | |
extension=xml.so | |
extension=gd.so | |
extension=curl.so | |
extension=simplexml.so | |
extension=xmlwriter.so | |
extension=zip.so | |
extension=intl.so | |
extension=mbstring.so | |
extension=mysql.so | |
extension=bcmath.so | |
EOF | |
fi | |
done | |
# Enable PHP module for Apache | |
if [[ -d "/etc/php/${version}/apache2" ]]; then | |
a2enmod "php${version}" || handle_error "Failed to enable PHP module for version $version" | |
fi | |
# Verify extensions are loaded | |
log_message "INFO" "Verifying extensions for PHP $version..." | |
for ext in raphf http dom xml gd curl simplexml xmlwriter zip intl mbstring mysql bcmath; do | |
if ! php"$version" -m | grep -q "$ext"; then | |
log_message "ERROR" "Extension $ext is not loaded for PHP $version" | |
handle_error "Failed to load extension $ext for PHP $version" | |
fi | |
done | |
# Verify CLI extensions specifically | |
if ! verify_cli_extensions "$version"; then | |
log_message "ERROR" "Failed to verify CLI extensions for PHP $version" | |
handle_error "CLI extensions verification failed for PHP $version" | |
fi | |
done | |
# Restart Apache if any PHP version was configured | |
if [[ ${#installed_versions[@]} -gt 0 ]]; then | |
systemctl restart apache2 || handle_error "Failed to restart Apache" | |
fi | |
log_message "INFO" "PHP installation and configuration completed for all versions" | |
} | |
# Function to install MySQL | |
install_mysql() { | |
log_message "INFO" "Checking MySQL installation..." | |
if command_exists mysql; then | |
local mysql_version | |
mysql_version=$(mysql -V | grep -oP '\d+\.\d+\.\d+' | head -1) | |
log_message "INFO" "MySQL/MariaDB version $mysql_version is installed" | |
else | |
log_message "INFO" "Installing MySQL..." | |
apt-get install -y mysql-server || handle_error "Failed to install MySQL" | |
systemctl enable mysql || handle_error "Failed to enable MySQL" | |
systemctl start mysql || handle_error "Failed to start MySQL" | |
log_message "INFO" "MySQL installed successfully" | |
fi | |
# Verify MySQL service | |
if ! systemctl is-active --quiet mysql; then | |
handle_error "MySQL service is not running" | |
fi | |
} | |
# Function to install Node.js | |
install_nodejs() { | |
log_message "INFO" "Checking Node.js installation..." | |
if command_exists node; then | |
local node_version | |
node_version=$(node -v | cut -d'v' -f2 | cut -d'.' -f1) | |
if [[ "$node_version" -ge "$NODE_VERSION" ]]; then | |
log_message "INFO" "Node.js version $(node -v) is installed" | |
return | |
fi | |
fi | |
log_message "INFO" "Installing Node.js $NODE_VERSION..." | |
check_internet | |
curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash - || handle_error "Failed to setup Node.js repository" | |
apt-get install -y nodejs || handle_error "Failed to install Node.js" | |
# Verify npm installation | |
if ! command_exists npm; then | |
log_message "INFO" "Installing npm..." | |
apt-get install -y npm || handle_error "Failed to install npm" | |
fi | |
log_message "INFO" "Node.js and npm installed successfully" | |
} | |
# Function to install Apache | |
install_apache() { | |
log_message "INFO" "Checking Apache installation..." | |
if command_exists apache2; then | |
log_message "INFO" "Apache is installed" | |
else | |
log_message "INFO" "Installing Apache..." | |
apt-get install -y apache2 || handle_error "Failed to install Apache" | |
systemctl enable apache2 || handle_error "Failed to enable Apache" | |
systemctl start apache2 || handle_error "Failed to start Apache" | |
log_message "INFO" "Apache installed successfully" | |
fi | |
# Verify Apache service | |
if ! systemctl is-active --quiet apache2; then | |
handle_error "Apache service is not running" | |
fi | |
} | |
# Function to install Composer | |
install_composer() { | |
log_message "INFO" "Checking Composer installation..." | |
if command_exists composer; then | |
log_message "INFO" "Composer is already installed" | |
return | |
fi | |
log_message "INFO" "Installing Composer..." | |
check_internet | |
local composer_setup="/tmp/composer-setup.php" | |
# Set environment variables for Composer | |
export COMPOSER_ALLOW_SUPERUSER=1 | |
export COMPOSER_HOME=/root/.config/composer | |
export COMPOSER_NO_INTERACTION=1 | |
php -r "copy('https://getcomposer.org/installer', '$composer_setup');" || handle_error "Failed to download Composer installer" | |
php "$composer_setup" --install-dir=/usr/local/bin --filename=composer || handle_error "Failed to install Composer" | |
rm -f "$composer_setup" | |
# Configure Composer to work with root user | |
mkdir -p /root/.config/composer | |
cat > /root/.config/composer/config.json << EOF | |
{ | |
"config": { | |
"allow-plugins": { | |
"php-http/discovery": true, | |
"symfony/flex": true, | |
"symfony/runtime": true | |
}, | |
"sort-packages": true, | |
"optimize-autoloader": true, | |
"preferred-install": "dist", | |
"no-interaction": true | |
} | |
} | |
EOF | |
command_exists composer || handle_error "Composer installation verification failed" | |
log_message "INFO" "Composer installed successfully" | |
} | |
# Function to setup SSL with Let's Encrypt | |
setup_ssl() { | |
local domain="$1" | |
log_message "INFO" "Setting up SSL for $domain..." | |
check_internet | |
if ! command_exists certbot; then | |
log_message "INFO" "Installing Certbot..." | |
apt-get install -y certbot python3-certbot-apache || handle_error "Failed to install Certbot" | |
fi | |
certbot --apache -d "$domain" -d "www.$domain" --non-interactive --agree-tos --email "admin@$domain" || { | |
log_message "WARNING" "Failed to setup SSL automatically. Please configure SSL manually." | |
} | |
log_message "INFO" "SSL setup completed" | |
} | |
# Function to validate domain | |
validate_domain() { | |
local domain="$1" | |
if [[ "$domain" =~ ^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then | |
return 0 | |
fi | |
handle_error "Invalid domain format: $domain. Must be like example.com" | |
} | |
# Function to get domain input | |
get_domain() { | |
local domain | |
while true; do | |
read -p "Please enter the domain for Hesabix installation (e.g., example.com): " domain | |
if validate_domain "$domain"; then | |
echo "$domain" | |
break | |
fi | |
done | |
} | |
# Function to setup domain | |
setup_domain() { | |
local domain="$1" | |
local domain_path="/var/www/html/$domain/public_html" | |
log_message "INFO" "Setting up domain: $domain" | |
# Create domain directory | |
mkdir -p "$domain_path" || handle_error "Failed to create domain directory" | |
chown -R "$apache_user:$apache_user" "$domain_path" | |
chmod -R 755 "$domain_path" | |
# Enable Apache rewrite module | |
a2enmod rewrite || handle_error "Failed to enable Apache rewrite module" | |
# Create Apache virtual host | |
local config_file="/etc/apache2/sites-available/$domain.conf" | |
cat > "$config_file" << EOF | |
<VirtualHost *:80> | |
ServerName $domain | |
ServerAlias www.$domain | |
DocumentRoot $domain_path | |
<Directory $domain_path> | |
Options Indexes FollowSymLinks | |
AllowOverride All | |
Require all granted | |
</Directory> | |
ErrorLog \${APACHE_LOG_DIR}/$domain-error.log | |
CustomLog \${APACHE_LOG_DIR}/$domain-access.log combined | |
</VirtualHost> | |
EOF | |
apache2ctl configtest || handle_error "Apache configuration test failed" | |
a2ensite "$domain.conf" || handle_error "Failed to enable Apache site" | |
systemctl restart apache2 || handle_error "Failed to restart Apache" | |
log_message "INFO" "Domain setup completed" | |
} | |
# Function to setup database | |
setup_database() { | |
local domain="$1" | |
local db_name="hesabix_$(echo "$domain" | tr '.-' '_')" | |
local db_user="hesabix_user" | |
local db_password | |
db_password=$(openssl rand -base64 12) | |
local domain_path="/var/www/html/$domain" | |
log_message "INFO" "Setting up database: $db_name" | |
# Verify MySQL is running | |
if ! systemctl is-active --quiet mysql; then | |
handle_error "MySQL service is not running" | |
fi | |
# Create database | |
mysql -e "CREATE DATABASE IF NOT EXISTS \`$db_name\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" || \ | |
handle_error "Failed to create database" | |
# Create user | |
mysql -e "CREATE USER IF NOT EXISTS '$db_user'@'localhost' IDENTIFIED BY '$db_password';" || \ | |
handle_error "Failed to create database user" | |
# Grant privileges | |
mysql -e "GRANT ALL PRIVILEGES ON \`$db_name\`.* TO '$db_user'@'localhost';" || \ | |
handle_error "Failed to grant database privileges" | |
mysql -e "FLUSH PRIVILEGES;" || handle_error "Failed to flush privileges" | |
# Update environment configuration | |
local env_file="$domain_path/hesabixCore/.env.local.php" | |
cat > "$env_file" << EOF | |
<?php | |
return [ | |
'APP_ENV' => 'prod', | |
'APP_SECRET' => '$(openssl rand -hex 16)', | |
'DATABASE_URL' => 'mysql://$db_user:[email protected]:3306/$db_name?serverVersion=8.0.32&charset=utf8mb4', | |
'MESSENGER_TRANSPORT_DSN' => 'doctrine://default?auto_setup=0', | |
'MAILER_DSN' => 'null://null', | |
'CORS_ALLOW_ORIGIN' => '*', | |
'LOCK_DSN' => 'flock', | |
]; | |
EOF | |
# Set proper permissions | |
chown "$apache_user:$apache_user" "$env_file" | |
chmod 644 "$env_file" | |
log_message "INFO" "Database setup completed" | |
} | |
# Function to install software | |
install_software() { | |
local domain="$1" | |
local domain_path="/var/www/html/$domain" | |
local current_version | |
current_version=$(get_php_version) | |
log_message "INFO" "Installing software for domain: $domain" | |
# Ensure domain directory exists | |
if [[ ! -d "$domain_path" ]]; then | |
handle_error "Domain directory $domain_path does not exist" | |
fi | |
cd "$domain_path" || handle_error "Failed to change to domain directory: $domain_path" | |
# Check internet connectivity | |
check_internet | |
# Check required extensions before proceeding | |
if ! check_required_extensions; then | |
echo -e "\nWarning: Some required extensions are missing or could not be installed." | |
echo -e "Do you want to continue with the installation anyway?" | |
echo -e "Note: This might cause issues with some features." | |
read -p "Continue? (y/n) [n]: " response | |
if [[ ! "$response" =~ ^[Yy]$ ]]; then | |
log_message "ERROR" "User chose not to continue with missing extensions" | |
handle_error "Installation aborted by user" | |
fi | |
# If user continues, add --ignore-platform-req flags | |
local composer_flags="--ignore-platform-req=ext-simplexml --ignore-platform-req=ext-xmlwriter --ignore-platform-req=ext-zip" | |
else | |
local composer_flags="" | |
fi | |
# Initialize git repository | |
log_message "INFO" "Initializing git repository in $domain_path..." | |
git init || handle_error "Failed to initialize git repository" | |
# Add remote repository | |
git remote add origin https://github.com/morrning/hesabixCore.git || \ | |
handle_error "Failed to add remote repository" | |
# Fetch and checkout the repository | |
log_message "INFO" "Fetching repository contents..." | |
git fetch origin || handle_error "Failed to fetch repository" | |
git checkout -b main origin/main || handle_error "Failed to checkout repository" | |
# Verify repository path | |
if [[ ! -d "$domain_path" ]]; then | |
handle_error "Repository directory $domain_path was not created" | |
fi | |
cd "$domain_path" || handle_error "Failed to change to domain directory: $domain_path" | |
# Verify composer.json exists in hesabixCore directory | |
if [[ ! -f "hesabixCore/composer.json" ]]; then | |
handle_error "composer.json file not found in $domain_path/hesabixCore" | |
fi | |
# Configure Composer | |
export COMPOSER_ALLOW_SUPERUSER=1 | |
export COMPOSER_HOME=/root/.config/composer | |
export COMPOSER_NO_INTERACTION=1 | |
# Install dependencies | |
log_message "INFO" "Installing Composer dependencies..." | |
cd "hesabixCore" || handle_error "Failed to change to hesabixCore directory" | |
# Try to install dependencies | |
if ! timeout "$COMPOSER_TIMEOUT" composer install --no-interaction --optimize-autoloader $composer_flags; then | |
log_message "ERROR" "Failed to install Composer dependencies" | |
handle_error "Failed to install Composer dependencies" | |
fi | |
# Generate environment | |
log_message "INFO" "Generating environment file..." | |
timeout 300 composer dump-env prod --no-interaction || \ | |
handle_error "Failed to generate environment file" | |
# Verify environment file | |
if [[ ! -f ".env.local.php" ]]; then | |
handle_error "Environment file (.env.local.php) was not generated" | |
fi | |
log_message "INFO" "Software installation completed" | |
} | |
# Function to setup web UI | |
setup_web_ui() { | |
local domain="$1" | |
local domain_path="/var/www/html/$domain" | |
local webui_path="$domain_path/webUI" | |
log_message "INFO" "Setting up web UI..." | |
# Check if webUI directory exists | |
if [[ ! -d "$webui_path" ]]; then | |
handle_error "Web UI directory ($webui_path) does not exist" | |
fi | |
cd "$webui_path" || handle_error "Failed to change to webUI directory" | |
# Install dependencies | |
log_message "INFO" "Installing web UI dependencies..." | |
timeout "$NPM_TIMEOUT" npm install || handle_error "Failed to install web UI dependencies" | |
# Build web UI | |
log_message "INFO" "Building web UI..." | |
timeout "$NPM_TIMEOUT" npm run build-only || handle_error "Failed to build web UI" | |
log_message "INFO" "Web UI setup completed" | |
} | |
# Function to set Apache ownership | |
set_apache_ownership() { | |
local domain="$1" | |
local domain_path="/var/www/html/$domain" | |
log_message "INFO" "Setting Apache ownership..." | |
chown -R "$apache_user:$apache_user" "$domain_path" || \ | |
handle_error "Failed to set Apache ownership" | |
find "$domain_path" -type d -exec chmod 755 {} \; | |
find "$domain_path" -type f -exec chmod 644 {} \; | |
log_message "INFO" "Apache ownership set" | |
} | |
# Function to show installation summary | |
show_installation_summary() { | |
local domain="$1" | |
local domain_path="/var/www/html/$domain" | |
log_message "INFO" "Showing installation summary..." | |
echo -e "\n${BOLD}${BLUE}=================================================${NC}" | |
echo -e "${BOLD}${BLUE} Hesabix Installation Summary ${NC}" | |
echo -e "${BOLD}${BLUE}=================================================${NC}" | |
echo -e "\n${YELLOW}Installation Details:${NC}" | |
echo -e "Domain: $domain" | |
echo -e "Installation Path: $domain_path" | |
echo -e "Web Server: Apache" | |
echo -e "PHP Version: $(php -v | head -n 1 | awk '{print $2}')" | |
echo -e "Node.js Version: $(node -v)" | |
echo -e "\n${YELLOW}Next Steps:${NC}" | |
echo -e "1. Configure domain DNS to point to this server" | |
echo -e "2. Access the web interface: https://$domain" | |
echo -e "3. Register the first user (system administrator)" | |
echo -e "\n${YELLOW}Support:${NC}" | |
echo -e "• Developer: Babak Alizadeh (alizadeh.babak)" | |
echo -e "• License: GNU GPL v3" | |
echo -e "• Website: ${UNDERLINE}https://hesabix.ir${NC}" | |
echo -e "• Support us: ${UNDERLINE}https://hesabix.ir/page/sponsors${NC} ❤" | |
echo -e "\n${GREEN}Installation completed successfully!${NC}" | |
echo -e "${BOLD}${BLUE}=================================================${NC}" | |
} | |
# Function to display telemetry consent | |
display_telemetry_consent() { | |
echo -e "\n${RED}=================================================" | |
echo -e "${RED} Anonymous Data Collection " | |
echo -e "${RED}=================================================" | |
echo -e "${BLUE}To improve Hesabix, we would like to collect anonymous data:" | |
echo -e "${BLUE}• System information (OS, PHP, MySQL versions)" | |
echo -e "${BLUE}• Installation path and domain" | |
echo -e "${BLUE}• Installation date" | |
read -p "Do you agree? (y/n) [n]: " response | |
[[ "$response" =~ ^[Yy]$ ]] && SEND_TELEMETRY=true | |
} | |
# Main execution | |
main() { | |
# Show header first | |
print_header | |
# Wait for user to see the header | |
sleep 2 | |
# Then start logging | |
init_logging | |
check_system_requirements | |
install_tools | |
display_telemetry_consent | |
update_packages | |
install_php | |
install_mysql | |
install_nodejs | |
install_apache | |
install_composer | |
domain=$(get_domain) | |
setup_domain "$domain" | |
install_software "$domain" | |
setup_database "$domain" | |
setup_web_ui "$domain" | |
set_apache_ownership "$domain" | |
setup_ssl "$domain" | |
show_installation_summary "$domain" | |
} | |
# Execute main with error handling | |
main || handle_error "Installation failed" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment