#!/bin/bash # Script configuration script_log_file="script_log.log" backup_dir="/root/config_backup_$(date +%Y%m%d_%H%M%S)" green_color="\033[1;32m" red_color="\033[1;31m" yellow_color="\033[1;33m" no_color="\033[0m" # Generate random MySQL password MYSQL_ROOT_PASSWORD=$(openssl rand -base64 16 | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1) # Error handling set -e trap 'echo "${red_color}Error occurred on line $LINENO${no_color}"' ERR # Function to log messages log_message() { local level=$1 local message=$2 local color=$no_color case $level in "INFO") color=$green_color ;; "WARNING") color=$yellow_color ;; "ERROR") color=$red_color ;; esac echo -e "${color}${message}${no_color}" echo "$(date '+%Y-%m-%d %H:%M:%S') - $level - $message" >> "$script_log_file" } # Function to check command status check_command_status() { if [ $? -ne 0 ]; then log_message "ERROR" "$1 failed" exit 1 fi } # Parse command line arguments while getopts d: flag; do case "${flag}" in d) domain=${OPTARG};; *) log_message "ERROR" "Invalid option: -$OPTARG" exit 1 ;; esac done # Check if domain is provided if [ -z "$domain" ]; then log_message "ERROR" "Domain parameter is required. Usage: $0 -d example.com" exit 1 fi # Main installation process starts here log_message "INFO" "Starting installation process for $domain" # Prepare system for installation log_message "INFO" "Preparing system for installation..." rm -rf /var/lib/dpkg/lock /var/lib/dpkg/lock-frontend /var/cache/apt/archives/lock check_command_status "Lock file removal" # Update system packages log_message "INFO" "Updating system packages..." apt-get update -qq check_command_status "System update" # Remove Apache if installed log_message "INFO" "Removing Apache if present..." apt-get purge apache* -y systemctl stop apache2 2>/dev/null || true kill -9 $(lsof -t -i:80) 2>/dev/null || true kill -9 $(lsof -t -i:443) 2>/dev/null || true # Install and configure Nginx log_message "INFO" "Installing and configuring Nginx..." apt-get install nginx -y check_command_status "Nginx installation" # Configure firewall log_message "INFO" "Configuring firewall..." ufw --force enable ufw allow 'Nginx Full' ufw allow OpenSSH check_command_status "Firewall configuration" # Install PHP and extensions log_message "INFO" "Installing PHP and extensions..." add-apt-repository ppa:ondrej/php -y apt-get update # Install PHP 8.2 apt-get install -y php8.2 php8.2-fpm php8.2-common php8.2-mysql php8.2-xml php8.2-curl \ php8.2-gd php8.2-imagick php8.2-cli php8.2-dev php8.2-imap php8.2-mbstring \ php8.2-opcache php8.2-soap php8.2-zip php8.2-intl php8.2-bcmath check_command_status "PHP 8.2 installation" # Install PHP 8.3 apt-get install -y php8.3 php8.3-fpm php8.3-common php8.3-mysql php8.3-xml php8.3-curl \ php8.3-gd php8.3-imagick php8.3-cli php8.3-dev php8.3-imap php8.3-mbstring \ php8.3-opcache php8.3-soap php8.3-zip php8.3-intl php8.3-bcmath check_command_status "PHP 8.3 installation" # Install and configure Redis log_message "INFO" "Installing Redis..." apt-get install -y redis-server php8.2-redis php8.3-redis systemctl enable redis-server systemctl start redis-server sed -i 's/supervised no/supervised systemd/' /etc/redis/redis.conf systemctl restart redis-server check_command_status "Redis installation" # Install Node.js and NPM log_message "INFO" "Installing Node.js and NPM..." apt-get install -y nodejs npm check_command_status "Node.js installation" # Install Certbot for SSL log_message "INFO" "Installing Certbot..." snap install --classic certbot ln -sf /snap/bin/certbot /usr/bin/certbot check_command_status "Certbot installation" # Configure Nginx for the domain log_message "INFO" "Configuring Nginx for $domain..." cat > "/etc/nginx/sites-available/$domain" << 'ENDOFFILE' server { listen 80; listen [::]:80; server_name DOMAIN_PLACEHOLDER www.DOMAIN_PLACEHOLDER; root /var/www/html/DOMAIN_PLACEHOLDER/public; add_header X-Frame-Options "SAMEORIGIN"; add_header X-Content-Type-Options "nosniff"; index index.php; charset utf-8; location / { try_files $uri $uri/ /index.php?$query_string; } location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } error_page 404 /index.php; location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; } location ~ /\.(?!well-known).* { deny all; } } ENDOFFILE # Replace placeholder with actual domain sed -i "s/DOMAIN_PLACEHOLDER/$domain/g" "/etc/nginx/sites-available/$domain" # Create web root directory mkdir -p "/var/www/html/$domain/public" chown -R www-data:www-data "/var/www/html/$domain" chmod -R 755 "/var/www/html/$domain" # Enable the site ln -sf "/etc/nginx/sites-available/$domain" /etc/nginx/sites-enabled/ rm -f /etc/nginx/sites-enabled/default # Optimize Nginx configuration cat > /etc/nginx/nginx.conf << 'ENDOFNGINX' user www-data; worker_processes auto; worker_rlimit_nofile 65535; pid /run/nginx.pid; events { worker_connections 65535; multi_accept on; use epoll; } http { charset utf-8; sendfile on; tcp_nopush on; tcp_nodelay on; server_tokens off; log_not_found off; types_hash_max_size 2048; client_max_body_size 16M; # MIME include mime.types; default_type application/octet-stream; # Logging access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log warn; # SSL ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; # Gzip gzip on; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml; # Virtual Host Configs include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; } ENDOFNGINX # Optimize PHP configuration for version in "8.2" "8.3"; do phpfpm_conf="/etc/php/$version/fpm/php.ini" if [ -f "$phpfpm_conf" ]; then # Optimize PHP settings sed -i 's/memory_limit = .*/memory_limit = 512M/' "$phpfpm_conf" sed -i 's/upload_max_filesize = .*/upload_max_filesize = 64M/' "$phpfpm_conf" sed -i 's/post_max_size = .*/post_max_size = 64M/' "$phpfpm_conf" sed -i 's/max_execution_time = .*/max_execution_time = 300/' "$phpfpm_conf" # Configure OpCache cat >> "$phpfpm_conf" << 'ENDOFPHP' [opcache] opcache.enable=1 opcache.memory_consumption=256 opcache.interned_strings_buffer=16 opcache.max_accelerated_files=10000 opcache.revalidate_freq=0 opcache.validate_timestamps=0 opcache.save_comments=1 opcache.fast_shutdown=1 ENDOFPHP systemctl restart "php$version-fpm" fi done # Install and configure MySQL if not already installed if ! command -v mysql &> /dev/null; then log_message "INFO" "Installing MySQL..." export DEBIAN_FRONTEND=noninteractive debconf-set-selections <<< "mysql-server mysql-server/root_password password $MYSQL_ROOT_PASSWORD" debconf-set-selections <<< "mysql-server mysql-server/root_password_again password $MYSQL_ROOT_PASSWORD" apt-get install -y mysql-server # Secure MySQL installation mysql -e "DELETE FROM mysql.user WHERE User='';" mysql -e "DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');" mysql -e "DROP DATABASE IF EXISTS test;" mysql -e "DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';" mysql -e "FLUSH PRIVILEGES;" # Optimize MySQL configuration cat >> /etc/mysql/mysql.conf.d/mysqld.cnf << 'ENDOFMYSQL' # Custom optimizations innodb_buffer_pool_size = 1G innodb_log_file_size = 256M innodb_flush_log_at_trx_commit = 2 innodb_flush_method = O_DIRECT ENDOFMYSQL systemctl restart mysql log_message "INFO" "MySQL root password: $MYSQL_ROOT_PASSWORD" echo "$MYSQL_ROOT_PASSWORD" > "/var/www/html/mysql_password.txt" chmod 600 "/var/www/html/mysql_password.txt" fi # Setup Laravel Cron Jobs crontab_content="################## START $domain #################### * * * * * cd /var/www/html/$domain && php artisan schedule:run >> /dev/null 2>&1 * * * * * cd /var/www/html/$domain && php artisan queue:work --stop-when-empty >> /dev/null 2>&1 ################## END $domain ####################" (crontab -l 2>/dev/null; echo "$crontab_content") | crontab - # Setup monitoring (Prometheus + Node Exporter) log_message "INFO" "Setting up monitoring..." apt-get install -y prometheus node-exporter # Configure Prometheus cat > /etc/prometheus/prometheus.yml << 'ENDOFPROMETHEUS' global: scrape_interval: 15s scrape_configs: - job_name: 'node' static_configs: - targets: ['localhost:9100'] ENDOFPROMETHEUS systemctl enable prometheus node-exporter systemctl start prometheus node-exporter # Install Fail2Ban log_message "INFO" "Installing Fail2Ban..." apt-get install -y fail2ban cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local systemctl enable fail2ban systemctl start fail2ban # Generate SSL certificate log_message "INFO" "Generating SSL certificate for $domain..." certbot --nginx -d "$domain" -d "www.$domain" --non-interactive --agree-tos -m "admin@$domain" --redirect # Final system tweaks log_message "INFO" "Applying system optimizations..." cat >> /etc/sysctl.conf << 'ENDOFSYSCTL' # Custom optimizations net.core.somaxconn = 65535 net.core.netdev_max_backlog = 65535 net.ipv4.tcp_max_syn_backlog = 65535 net.ipv4.tcp_fin_timeout = 10 net.ipv4.tcp_keepalive_time = 300 net.ipv4.tcp_keepalive_probes = 5 net.ipv4.tcp_keepalive_intvl = 15 ENDOFSYSCTL sysctl -p # Clean up apt-get autoremove -y apt-get autoclean # Final restart of services systemctl restart nginx php8.2-fpm log_message "INFO" "Installation completed successfully!" log_message "INFO" "Your MySQL root password is: $MYSQL_ROOT_PASSWORD" log_message "INFO" "Please save this password in a secure location."