From d0e6d651b4e841c780a07296e2b399b934aceee2 Mon Sep 17 00:00:00 2001 From: Babak Alizadeh Date: Tue, 29 Apr 2025 11:36:02 +0000 Subject: [PATCH] start working with docker --- .env.example | 15 + .gitignore | 41 ++- Dockerfile | 56 ++++ docker-compose.yml | 80 ++++++ docker/README.md | 68 +++++ docker/apache.conf | 13 + docker/check-requirements.sh | 66 +++++ docker/init-db.sh | 56 ++++ docker/setup.sh | 105 +++++++ install.sh | 536 ++++++++++++++++++++--------------- 10 files changed, 801 insertions(+), 235 deletions(-) create mode 100644 .env.example create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 docker/README.md create mode 100644 docker/apache.conf create mode 100644 docker/check-requirements.sh create mode 100644 docker/init-db.sh create mode 100644 docker/setup.sh diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..f287f01 --- /dev/null +++ b/.env.example @@ -0,0 +1,15 @@ +# Database settings +MYSQL_ROOT_PASSWORD=change_this_password +MYSQL_DATABASE=hesabix_db +MYSQL_USER=hesabix_user +MYSQL_PASSWORD=change_this_password + +# Application settings +APP_ENV=prod +APP_SECRET=change_this_secret +DATABASE_URL=mysql://hesabix_user:change_this_password@db:3306/hesabix_db + +# phpMyAdmin settings +PMA_HOST=db +PMA_USER=hesabix_user +PMA_PASSWORD=change_this_password \ No newline at end of file diff --git a/.gitignore b/.gitignore index d316c39..8e8b56d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,45 @@ +# Environment files +.env +.env.local +.env.*.local + +# Dependency directories +/vendor/ +/node_modules/ +/webUI/node_modules/ + +# Log files +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Temporary files +/tmp/ +/temp/ +.DS_Store +Thumbs.db + +# IDE files +.idea/ +.vscode/ +*.swp +*.swo + +# Compiled files +/webUI/dist/ +/webUI/build/ + +# Database files +*.sql +*.sqlite +*.sqlite3 + +# Docker files +.docker/ +docker-compose.override.yml hesabixArchive/ hesabixBackup/ backup/ -.idea/ public_html/u/* diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a82753d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,56 @@ +# Use PHP 8.3 with Apache as base image +FROM php:8.3-apache + +# Install required packages +RUN apt-get update && apt-get install -y \ + git \ + curl \ + libpng-dev \ + libonig-dev \ + libxml2-dev \ + libzip-dev \ + zip \ + unzip \ + nodejs \ + npm + +# Install PHP extensions +RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip + +# Install Composer +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +# Set working directory +WORKDIR /var/www/html + +# Copy project files +COPY hesabixCore/ /var/www/html/hesabixCore/ +COPY webUI/ /var/www/html/webUI/ +COPY public_html/ /var/www/html/public_html/ + +# Set permissions +RUN chown -R www-data:www-data /var/www/html \ + && chmod -R 755 /var/www/html + +# Enable Apache modules +RUN a2enmod rewrite + +# Copy Apache configuration +COPY docker/apache.conf /etc/apache2/sites-available/000-default.conf + +# Install PHP dependencies +WORKDIR /var/www/html/hesabixCore +RUN composer install --no-interaction --optimize-autoloader + +# Install Node.js dependencies and build web UI +WORKDIR /var/www/html/webUI +RUN npm install && npm run build-only + +# Return to main directory +WORKDIR /var/www/html + +# Expose ports +EXPOSE 80 + +# Run command +CMD ["apache2-foreground"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..25a7de5 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,80 @@ +version: '3.8' + +services: + # Web service + web: + build: . + ports: + - "80:80" + - "443:443" + volumes: + - ./hesabixCore:/var/www/html/hesabixCore + - ./webUI:/var/www/html/webUI + - ./public_html:/var/www/html/public_html + - ./hesabixBackup:/var/www/html/hesabixBackup + - ./ssl:/etc/ssl/private + depends_on: + - db + environment: + - DATABASE_URL=mysql://hesabix_user:hesabix_password@db:3306/hesabix_db + - APP_ENV=prod + - APP_SECRET=${APP_SECRET:-your-secret-key} + - DOMAIN=${DOMAIN:-localhost} + networks: + - hesabix-network + restart: unless-stopped + + # Database service + db: + image: mysql:8.0 + environment: + - MYSQL_ROOT_PASSWORD=root_password + - MYSQL_DATABASE=hesabix_db + - MYSQL_USER=hesabix_user + - MYSQL_PASSWORD=hesabix_password + volumes: + - mysql_data:/var/lib/mysql + - ./hesabixBackup:/docker-entrypoint-initdb.d + networks: + - hesabix-network + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot_password"] + interval: 5s + timeout: 5s + retries: 5 + restart: unless-stopped + + # phpMyAdmin service + phpmyadmin: + image: phpmyadmin/phpmyadmin + ports: + - "8080:80" + environment: + - PMA_HOST=db + - PMA_USER=hesabix_user + - PMA_PASSWORD=hesabix_password + depends_on: + - db + networks: + - hesabix-network + restart: unless-stopped + + # Certbot service for SSL + certbot: + image: certbot/certbot + volumes: + - ./ssl:/etc/letsencrypt + - ./public_html:/var/www/html + depends_on: + - web + entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'" + networks: + - hesabix-network + restart: unless-stopped + +networks: + hesabix-network: + driver: bridge + +volumes: + mysql_data: \ No newline at end of file diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..d7a5373 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,68 @@ +# راهنمای استقرار Hesabix با Docker + +این راهنما به شما کمک می‌کند تا Hesabix را با استفاده از Docker مستقر کنید. + +## پیش‌نیازها + +- Docker +- Docker Compose + +## مراحل نصب + +1. ابتدا مخزن را کلون کنید: +```bash +git clone https://github.com/your-username/hesabix.git +cd hesabix +``` + +2. فایل‌های تنظیمات را کپی کنید: +```bash +cp .env.example .env +``` + +3. مقادیر مورد نظر خود را در فایل `.env` تنظیم کنید. + +4. ساخت و اجرای کانتینرها: +```bash +docker-compose up -d +``` + +## دسترسی به سرویس‌ها + +- وب‌سایت: http://localhost +- phpMyAdmin: http://localhost:8080 + +## اطلاعات ورود به دیتابیس + +- نام کاربری: hesabix_user +- رمز عبور: hesabix_password (یا مقدار تعیین شده در فایل .env) +- نام دیتابیس: hesabix_db +- هاست: db +- پورت: 3306 + +## دستورات مفید + +- مشاهده لاگ‌ها: +```bash +docker-compose logs -f +``` + +- توقف سرویس‌ها: +```bash +docker-compose down +``` + +- راه‌اندازی مجدد سرویس‌ها: +```bash +docker-compose restart +``` + +## نکات امنیتی + +1. حتماً رمزهای عبور پیش‌فرض را در فایل `.env` تغییر دهید. +2. از SSL/TLS برای اتصالات استفاده کنید. +3. فایل‌های حساس را در `.gitignore` قرار دهید. + +## پشتیبانی + +برای گزارش مشکلات یا درخواست کمک، لطفاً یک issue در مخزن GitHub ایجاد کنید. \ No newline at end of file diff --git a/docker/apache.conf b/docker/apache.conf new file mode 100644 index 0000000..49f28bb --- /dev/null +++ b/docker/apache.conf @@ -0,0 +1,13 @@ + + ServerAdmin webmaster@localhost + DocumentRoot /var/www/html/public_html + + + Options Indexes FollowSymLinks + AllowOverride All + Require all granted + + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + \ No newline at end of file diff --git a/docker/check-requirements.sh b/docker/check-requirements.sh new file mode 100644 index 0000000..6caa7b5 --- /dev/null +++ b/docker/check-requirements.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +# Colors for better display +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +# Required values +REQUIRED_DISK_SPACE_MB=2000 +REQUIRED_MEMORY_MB=1024 + +# Function to display messages +print_message() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +# Function to display errors +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Function to display warnings +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +# Check root privileges +if [ "$EUID" -ne 0 ]; then + print_error "This script must be run as root" + exit 1 +fi + +# Check Docker installation +if ! command -v docker &> /dev/null; then + print_error "Docker is not installed. Please install Docker first." + exit 1 +fi + +# Check Docker Compose installation +if ! command -v docker-compose &> /dev/null; then + print_error "Docker Compose is not installed. Please install Docker Compose first." + exit 1 +fi + +# Check disk space +available_space=$(df -m / | awk 'NR==2 {print $4}') +if [ "$available_space" -lt "$REQUIRED_DISK_SPACE_MB" ]; then + print_error "Insufficient disk space. Required: ${REQUIRED_DISK_SPACE_MB}MB, Available: ${available_space}MB" + exit 1 +fi + +# Check memory +total_memory=$(free -m | awk '/^Mem:/{print $2}') +if [ "$total_memory" -lt "$REQUIRED_MEMORY_MB" ]; then + print_warning "Low memory detected. Performance may be affected." +fi + +# Check internet connectivity +print_message "Checking internet connectivity..." +if ! ping -c 1 8.8.8.8 >/dev/null 2>&1; then + print_error "No internet connection detected. Please ensure the server has internet access." + exit 1 +fi + +print_message "System requirements check completed successfully." \ No newline at end of file diff --git a/docker/init-db.sh b/docker/init-db.sh new file mode 100644 index 0000000..b54204f --- /dev/null +++ b/docker/init-db.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# Colors for better display +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +# Function to display messages +print_message() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +# Function to display errors +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Function to display warnings +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +# Wait for MySQL to be ready +print_message "Waiting for MySQL to be ready..." +while ! docker-compose exec -T db mysqladmin ping -h localhost -u root -proot_password --silent; do + sleep 1 +done + +# Import initial database structure +print_message "Importing initial database structure..." +if [ -f "hesabixBackup/databasefiles/hesabix-db-default.sql" ]; then + docker-compose exec -T db mysql -u root -proot_password hesabix_db < hesabixBackup/databasefiles/hesabix-db-default.sql + if [ $? -eq 0 ]; then + print_message "Initial database structure imported successfully." + else + print_error "Failed to import initial database structure." + exit 1 + fi +else + print_error "Initial database file not found at hesabixBackup/databasefiles/hesabix-db-default.sql" + exit 1 +fi + +# Update database schema +print_message "Updating database schema..." +docker-compose exec -T web php /var/www/html/hesabixCore/bin/console doctrine:schema:update --force + +if [ $? -eq 0 ]; then + print_message "Database schema updated successfully." +else + print_error "Failed to update database schema." + exit 1 +fi + +print_message "Database initialization completed successfully." \ No newline at end of file diff --git a/docker/setup.sh b/docker/setup.sh new file mode 100644 index 0000000..39a24af --- /dev/null +++ b/docker/setup.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +# Colors for better display +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +# Function to display messages +print_message() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +# Function to display errors +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Function to display warnings +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +# Check system requirements +print_message "Checking system requirements..." +chmod +x docker/check-requirements.sh +./docker/check-requirements.sh + +if [ $? -ne 0 ]; then + print_error "System requirements check failed." + exit 1 +fi + +# Check if Docker is installed +if ! command -v docker &> /dev/null; then + print_error "Docker is not installed. Please install Docker first." + exit 1 +fi + +# Check if Docker Compose is installed +if ! command -v docker-compose &> /dev/null; then + print_error "Docker Compose is not installed. Please install Docker Compose first." + exit 1 +fi + +# Copy .env.example to .env if it doesn't exist +if [ ! -f .env ]; then + print_message "Copying .env.example to .env" + cp .env.example .env + print_warning "Please configure values in the .env file." + exit 0 +fi + +# Create SSL directory if it doesn't exist +if [ ! -d "ssl" ]; then + print_message "Creating SSL directory..." + mkdir -p ssl +fi + +# Build and start containers +print_message "Building and starting containers..." +docker-compose up -d + +# Check container status +if [ $? -eq 0 ]; then + print_message "Containers started successfully." +else + print_error "Error starting containers." + exit 1 +fi + +# Initialize database +print_message "Initializing database..." +chmod +x docker/init-db.sh +./docker/init-db.sh + +if [ $? -eq 0 ]; then + print_message "Database initialized successfully." +else + print_error "Error initializing database." + exit 1 +fi + +# Setup SSL if domain is provided +if [ -n "$DOMAIN" ] && [ "$DOMAIN" != "localhost" ]; then + print_message "Setting up SSL for $DOMAIN..." + docker-compose run --rm certbot certonly --webroot --webroot-path /var/www/html -d $DOMAIN -d www.$DOMAIN --email admin@$DOMAIN --agree-tos --non-interactive + + if [ $? -eq 0 ]; then + print_message "SSL setup completed successfully." + else + print_warning "SSL setup failed. Continuing without SSL." + fi +fi + +print_message "Installation completed successfully." +print_message "Website: http://localhost" +if [ -n "$DOMAIN" ] && [ "$DOMAIN" != "localhost" ]; then + print_message "Secure Website: https://$DOMAIN" +fi +print_message "phpMyAdmin: http://localhost:8080" + +# Display logs +print_message "Displaying logs (press Ctrl+C to exit)..." +docker-compose logs -f \ No newline at end of file diff --git a/install.sh b/install.sh index 7d2a7f9..2c0fa9a 100755 --- a/install.sh +++ b/install.sh @@ -50,7 +50,6 @@ 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 @@ -182,6 +181,9 @@ update_packages() { install_tools() { local tools=("curl" "coreutils" "git" "unzip") + # Update package lists first + update_packages + for tool in "${tools[@]}"; do if ! command_exists "$tool"; then log_message "INFO" "Installing $tool..." @@ -213,77 +215,25 @@ get_installed_php_versions() { # Function to check if all required extensions are installed for all PHP versions check_required_extensions() { - local missing_extensions=() + local missing_packages=() 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" + log_message "INFO" "Checking required packages for PHP $version..." + for pkg in 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; do + if ! dpkg -l | grep -q "^ii $pkg "; then + missing_packages+=("$pkg") + log_message "WARNING" "Package $pkg is missing" 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 + if [[ ${#missing_packages[@]} -gt 0 ]]; then + echo -e "\nWarning: The following packages are missing:" + printf '%s\n' "${missing_packages[@]}" + echo -e "\nThese packages will need to be installed manually after the installation is complete." + return 0 fi return 0 @@ -291,29 +241,28 @@ check_required_extensions() { # Function to verify CLI extensions verify_cli_extensions() { - local version="$1" - log_message "INFO" "Verifying CLI extensions for PHP $version..." + log_message "INFO" "Verifying CLI extensions for PHP..." # Get the list of enabled extensions from CLI local enabled_extensions - enabled_extensions=$(php"$version" -m) + enabled_extensions=$(php -m) # Check each required extension - for ext in raphf http dom xml gd curl simplexml xmlwriter zip intl mbstring mysql bcmath; do + for ext in iconv 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 "ERROR" "Extension $ext is not enabled in CLI" 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" + phpenmod "$ext" || { + log_message "ERROR" "Failed to enable $ext for CLI" return 1 } # Verify again after enabling - enabled_extensions=$(php"$version" -m) + enabled_extensions=$(php -m) if ! echo "$enabled_extensions" | grep -q "^$ext$"; then - log_message "ERROR" "Extension $ext is still not enabled in CLI for PHP $version" + log_message "ERROR" "Extension $ext is still not enabled in CLI" return 1 fi fi @@ -326,157 +275,67 @@ verify_cli_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 + # Update package lists first + update_packages - # Get current PHP version - local current_version - current_version=$(get_php_version) - log_message "DEBUG" "Current PHP version: $current_version" + # Remove any existing PHP packages first + apt-get remove --purge php* -y + apt-get autoremove -y + apt-get clean - # 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 + # Install PHP and required extensions + log_message "INFO" "Installing PHP and required extensions..." + local php_packages=( + "php" + "php-cli" + "libapache2-mod-php" + "php-intl" + "php-mbstring" + "php-zip" + "php-gd" + "php-mysql" + "php-curl" + "php-xml" + "php-bcmath" + "php-raphf" + "php-http" + "php-dom" + "php-simplexml" + "php-xmlwriter" + "php-iconv" + ) - # 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" + # Install each package individually to handle dependencies + for pkg in "${php_packages[@]}"; do + log_message "INFO" "Installing $pkg..." + if ! apt-get install -y "$pkg"; then + log_message "WARNING" "Failed to install $pkg, continuing with other packages..." 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 + # Install specific PHP 8.3 packages + for pkg in php8.3-dom php8.3-simplexml php8.3-xmlwriter; do + if ! apt-get install -y "$pkg"; then + log_message "WARNING" "Failed to install $pkg, continuing with other packages..." + fi + done - log_message "INFO" "PHP installation and configuration completed for all versions" + # Enable PHP module for Apache + a2enmod php8.3 || a2enmod php8.2 || a2enmod php8.1 || a2enmod php8.0 || a2enmod php7.4 || log_message "WARNING" "Failed to enable PHP module" + + # Restart Apache + systemctl restart apache2 || log_message "WARNING" "Failed to restart Apache" + + log_message "INFO" "PHP installation and configuration completed" } # Function to install MySQL install_mysql() { log_message "INFO" "Checking MySQL installation..." + # Update package lists first + update_packages + if command_exists mysql; then local mysql_version mysql_version=$(mysql -V | grep -oP '\d+\.\d+\.\d+' | head -1) @@ -499,6 +358,9 @@ install_mysql() { install_nodejs() { log_message "INFO" "Checking Node.js installation..." + # Update package lists first + update_packages + if command_exists node; then local node_version node_version=$(node -v | cut -d'v' -f2 | cut -d'.' -f1) @@ -526,6 +388,9 @@ install_nodejs() { install_apache() { log_message "INFO" "Checking Apache installation..." + # Update package lists first + update_packages + if command_exists apache2; then log_message "INFO" "Apache is installed" else @@ -630,9 +495,32 @@ get_domain() { setup_domain() { local domain="$1" local domain_path="/var/www/html/$domain/public_html" + local config_file="/etc/apache2/sites-available/$domain.conf" log_message "INFO" "Setting up domain: $domain" + # Remove existing virtual host if it exists + if [[ -f "$config_file" ]]; then + log_message "INFO" "Removing existing virtual host configuration..." + a2dissite "$domain.conf" >/dev/null 2>&1 + rm -f "$config_file" + fi + + # Check for existing domain directory + if [[ -d "/var/www/html/$domain" ]]; then + echo -e "\n${YELLOW}Warning: The directory /var/www/html/$domain already exists.${NC}" + echo -e "${YELLOW}All its contents will be deleted.${NC}" + read -p "Do you want to continue? (y/n) [n]: " response + + if [[ ! "$response" =~ ^[Yy]$ ]]; then + log_message "ERROR" "User chose not to delete existing directory" + handle_error "Installation aborted by user" + fi + + log_message "INFO" "Removing existing domain directory..." + rm -rf "/var/www/html/$domain" + fi + # Create domain directory mkdir -p "$domain_path" || handle_error "Failed to create domain directory" chown -R "$apache_user:$apache_user" "$domain_path" @@ -642,7 +530,6 @@ setup_domain() { 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 ServerName $domain @@ -670,51 +557,95 @@ EOF # Function to setup database setup_database() { local domain="$1" - local db_name="hesabix_$(echo "$domain" | tr '.-' '_')" + local base_db_name="hesabix_$(echo "$domain" | tr '.-' '_')" + local db_name="$base_db_name" local db_user="hesabix_user" local db_password db_password=$(openssl rand -base64 12) local domain_path="/var/www/html/$domain" + local counter=1 - log_message "INFO" "Setting up database: $db_name" + log_message "INFO" "Setting up database..." # Verify MySQL is running if ! systemctl is-active --quiet mysql; then handle_error "MySQL service is not running" fi + # Check if database exists and create new name if needed + while mysql -e "SHOW DATABASES LIKE '$db_name'" | grep -q "$db_name"; do + db_name="${base_db_name}_${counter}" + counter=$((counter + 1)) + done + + if [[ "$db_name" != "$base_db_name" ]]; then + log_message "WARNING" "Database $base_db_name already exists, using $db_name instead" + fi + + # Drop existing user if exists + mysql -e "DROP USER IF EXISTS '$db_user'@'localhost';" || \ + log_message "WARNING" "Failed to drop existing user" + # 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';" || \ + # Create user with proper permissions + mysql -e "CREATE USER '$db_user'@'localhost' IDENTIFIED BY '$db_password';" || \ handle_error "Failed to create database user" - # Grant privileges + # Grant all privileges and make sure they are applied 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" + # Verify user can connect + if ! mysql -u"$db_user" -p"$db_password" -e "SELECT 1;" >/dev/null 2>&1; then + handle_error "Failed to verify database user access" + fi + + # Import default database structure + log_message "INFO" "Importing default database structure..." + if [[ -f "$domain_path/hesabixBackup/databasefiles/hesabix-db-default.sql" ]]; then + mysql -u"$db_user" -p"$db_password" "$db_name" < "$domain_path/hesabixBackup/databasefiles/hesabix-db-default.sql" || \ + log_message "WARNING" "Failed to import default database structure" + else + log_message "WARNING" "Default database structure file not found" + fi + # Update environment configuration local env_file="$domain_path/hesabixCore/.env.local.php" cat > "$env_file" << EOF 'prod', - 'APP_SECRET' => '$(openssl rand -hex 16)', - 'DATABASE_URL' => 'mysql://$db_user:$db_password@127.0.0.1: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', -]; + +// This file was generated by running "composer dump-env dev" + +return array ( + 'APP_ENV' => 'prod', + 'SYMFONY_DOTENV_PATH' => './.env', + 'APP_SECRET' => '$(openssl rand -hex 16)', + 'DATABASE_URL' => 'mysql://$db_user:$db_password@127.0.0.1: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" + # Update database schema + log_message "INFO" "Updating database schema..." + cd "$domain_path/hesabixCore" || handle_error "Failed to change to hesabixCore directory" + + # Set environment variables for doctrine command + export DATABASE_URL="mysql://$db_user:$db_password@127.0.0.1:3306/$db_name?serverVersion=8.0.32&charset=utf8mb4" + + php bin/console doctrine:schema:update --force || \ + log_message "WARNING" "Failed to update database schema" + log_message "INFO" "Database setup completed" } @@ -755,18 +686,37 @@ install_software() { 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" + # Initialize git repository if not already initialized + if [[ ! -d ".git" ]]; then + log_message "INFO" "Initializing git repository in $domain_path..." + git init || handle_error "Failed to initialize git repository" + fi - # Add remote repository - git remote add origin https://github.com/morrning/hesabixCore.git || \ - handle_error "Failed to add remote repository" + # Check if remote origin exists + if ! git remote get-url origin >/dev/null 2>&1; then + # Add remote repository if it doesn't exist + git remote add origin https://github.com/morrning/hesabixCore.git || \ + handle_error "Failed to add remote repository" + else + # Update remote URL if it exists + git remote set-url origin https://github.com/morrning/hesabixCore.git || \ + handle_error "Failed to update remote repository" + fi # 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" + + # Check if master branch exists + if git show-ref --verify --quiet refs/heads/master; then + # Switch to master branch + git checkout master || handle_error "Failed to checkout master branch" + # Pull latest changes + git pull origin master || handle_error "Failed to pull latest changes" + else + # Create and checkout master branch + git checkout -b master origin/master || handle_error "Failed to checkout repository" + fi # Verify repository path if [[ ! -d "$domain_path" ]]; then @@ -850,13 +800,108 @@ set_apache_ownership() { log_message "INFO" "Apache ownership set" } +# Function to display GPL license +display_gpl_license() { + echo -e "\n${BOLD}${BLUE}=================================================${NC}" + echo -e "${BOLD}${BLUE} GNU General Public License v3 ${NC}" + echo -e "${BOLD}${BLUE}=================================================${NC}" + echo -e "${YELLOW}This program is free software: you can redistribute it and/or modify${NC}" + echo -e "${YELLOW}it under the terms of the GNU General Public License as published by${NC}" + echo -e "${YELLOW}the Free Software Foundation, either version 3 of the License, or${NC}" + echo -e "${YELLOW}(at your option) any later version.${NC}" + echo -e "\n${YELLOW}This program is distributed in the hope that it will be useful,${NC}" + echo -e "${YELLOW}but WITHOUT ANY WARRANTY; without even the implied warranty of${NC}" + echo -e "${YELLOW}MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.${NC}" + echo -e "${YELLOW}See the GNU General Public License for more details.${NC}" + echo -e "${BOLD}${BLUE}=================================================${NC}\n" + + read -p "Do you accept the terms of the GNU General Public License v3? (y/n) [y]: " response + if [[ ! "$response" =~ ^[Yy]$ ]] && [[ -n "$response" ]]; then + handle_error "License terms not accepted" + fi +} + +# Function to confirm installation +confirm_installation() { + echo -e "\n${BOLD}${BLUE}=================================================${NC}" + echo -e "${BOLD}${BLUE} Installation Confirmation ${NC}" + echo -e "${BOLD}${BLUE}=================================================${NC}" + echo -e "${YELLOW}This script will install:${NC}" + echo -e "• PHP and required extensions" + echo -e "• MySQL/MariaDB" + echo -e "• Apache" + echo -e "• Node.js" + echo -e "• Composer" + echo -e "• phpMyAdmin" + echo -e "• Hesabix Core" + echo -e "• Hesabix Web UI" + echo -e "\n${YELLOW}The installation will require approximately 2GB of disk space.${NC}" + echo -e "${BOLD}${BLUE}=================================================${NC}\n" + + read -p "Do you want to continue with the installation? (y/n) [y]: " response + if [[ ! "$response" =~ ^[Yy]$ ]] && [[ -n "$response" ]]; then + handle_error "Installation cancelled by user" + fi +} + +# Function to install phpMyAdmin +install_phpmyadmin() { + log_message "INFO" "Installing phpMyAdmin..." + + # Update package lists first + update_packages + + # Install phpMyAdmin + apt-get install -y phpmyadmin || handle_error "Failed to install phpMyAdmin" + + # Configure phpMyAdmin + log_message "INFO" "Configuring phpMyAdmin..." + + # Create Apache configuration + cat > /etc/apache2/conf-available/phpmyadmin.conf << EOF +Alias /phpmyadmin /usr/share/phpmyadmin + + Options FollowSymLinks + DirectoryIndex index.php + AllowOverride All + Require all granted + +EOF + + # Enable configuration + a2enconf phpmyadmin || handle_error "Failed to enable phpMyAdmin configuration" + + # Restart Apache + systemctl restart apache2 || handle_error "Failed to restart Apache" + + log_message "INFO" "phpMyAdmin installation completed" +} + # Function to show installation summary show_installation_summary() { local domain="$1" local domain_path="/var/www/html/$domain" + local missing_packages=() + local db_name="hesabix_$(echo "$domain" | tr '.-' '_')" + local db_user="hesabix_user" + local db_password + + # Get database password from env file + if [[ -f "$domain_path/hesabixCore/.env.local.php" ]]; then + db_password=$(php -r "include '$domain_path/hesabixCore/.env.local.php'; echo \$env['DATABASE_URL']; echo PHP_EOL;" | grep -oP '(?<=://)[^:]+(?=:)') + fi log_message "INFO" "Showing installation summary..." + # Check for missing packages + for version in $(get_installed_php_versions); do + for pkg in 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; do + if ! dpkg -l | grep -q "^ii $pkg "; then + missing_packages+=("$pkg") + fi + done + done + echo -e "\n${BOLD}${BLUE}=================================================${NC}" echo -e "${BOLD}${BLUE} Hesabix Installation Summary ${NC}" echo -e "${BOLD}${BLUE}=================================================${NC}" @@ -866,11 +911,27 @@ show_installation_summary() { 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 "phpMyAdmin URL: https://$domain/phpmyadmin" + + echo -e "\n${YELLOW}Database Information:${NC}" + echo -e "Database Name: $db_name" + echo -e "Database User: $db_user" + echo -e "Database Password: $db_password" + echo -e "Database Host: localhost" + echo -e "Database Port: 3306" + + if [[ ${#missing_packages[@]} -gt 0 ]]; then + echo -e "\n${RED}Warning: The following packages were not installed:${NC}" + printf '%s\n' "${missing_packages[@]}" + echo -e "\n${YELLOW}Please install these packages manually using:${NC}" + echo -e "sudo apt-get install ${missing_packages[*]}" + fi 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 "3. Access phpMyAdmin: https://$domain/phpmyadmin" + echo -e "4. Register the first user (system administrator)" echo -e "\n${YELLOW}Support:${NC}" echo -e "• Developer: Babak Alizadeh (alizadeh.babak)" @@ -880,6 +941,10 @@ show_installation_summary() { echo -e "\n${GREEN}Installation completed successfully!${NC}" echo -e "${BOLD}${BLUE}=================================================${NC}" + + # Restart Apache at the end of installation + log_message "INFO" "Restarting Apache..." + systemctl restart apache2 || log_message "WARNING" "Failed to restart Apache" } # Function to display telemetry consent @@ -908,6 +973,8 @@ main() { init_logging check_system_requirements install_tools + display_gpl_license + confirm_installation display_telemetry_consent update_packages install_php @@ -915,6 +982,7 @@ main() { install_nodejs install_apache install_composer + install_phpmyadmin domain=$(get_domain) setup_domain "$domain"