diff --git a/setup_server_laravel.sh b/setup_server_laravel.sh index 83e261f..5419e4c 100644 --- a/setup_server_laravel.sh +++ b/setup_server_laravel.sh @@ -1,360 +1,348 @@ #!/bin/bash # Script configuration -SCRIPT_VERSION="1.0.0" -SCRIPT_LOG_FILE="/var/log/server_setup.log" -BACKUP_DIR="/var/backups/server_setup" -MYSQL_ROOT_PASSWORD=$(openssl rand -base64 16) -PROMETHEUS_VERSION="2.37.0" -NODE_EXPORTER_VERSION="1.3.1" +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" -# Color codes for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color +# Generate random MySQL password +MYSQL_ROOT_PASSWORD=$(openssl rand -base64 16 | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1) -# Logging function -log() { +# 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 - shift - local message=$@ - local timestamp=$(date '+%Y-%m-%d %H:%M:%S') - echo -e "${timestamp} [${level}] ${message}" | tee -a ${SCRIPT_LOG_FILE} + 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" } -# Error handling function -handle_error() { - local exit_code=$? - local line_number=$1 - if [ $exit_code -ne 0 ]; then - log "ERROR" "Failed at line ${line_number} with exit code ${exit_code}" - exit $exit_code +# Function to check command status +check_command_status() { + if [ $? -ne 0 ]; then + log_message "ERROR" "$1 failed" + exit 1 fi } -trap 'handle_error ${LINENO}' ERR -# System health check function -check_system_health() { - log "INFO" "Performing system health checks..." +# 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 disk space - local disk_usage=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//') - if [ $disk_usage -gt 85 ]; then - log "WARNING" "Disk usage is above 85% (${disk_usage}%)" - return 1 - fi +# Check if domain is provided +if [ -z "$domain" ]; then + log_message "ERROR" "Domain parameter is required. Usage: $0 -d example.com" + exit 1 +fi - # Check available memory - local available_memory=$(free -m | awk 'NR==2 {print $7}') - if [ $available_memory -lt 1024 ]; then - log "WARNING" "Available memory is less than 1GB (${available_memory}MB)" - return 1 - fi +# Main installation process starts here +log_message "INFO" "Starting installation process for $domain" - log "INFO" "System health checks passed" - return 0 -} +# 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" -# Backup function -create_backup() { - local backup_date=$(date +%Y%m%d_%H%M%S) - local backup_path="${BACKUP_DIR}/${backup_date}" - - log "INFO" "Creating backup at ${backup_path}" - mkdir -p "${backup_path}" || handle_error ${LINENO} - - # Backup existing configurations - if [ -d "/etc/nginx" ]; then - cp -r /etc/nginx "${backup_path}/nginx" || handle_error ${LINENO} - fi - if [ -d "/etc/php" ]; then - cp -r /etc/php "${backup_path}/php" || handle_error ${LINENO} - fi - - log "INFO" "Backup completed successfully" -} +# Update system packages +log_message "INFO" "Updating system packages..." +apt-get update -qq +check_command_status "System update" -# Prepare Installation Function -prepare_installation() { - log "INFO" "Preparing for installation" - - # Your original prepare installing block, enhanced with logging and error handling - rm -rf /var/lib/dpkg/lock || handle_error ${LINENO} - rm -rf /var/lib/dpkg/lock-frontend || handle_error ${LINENO} - rm -rf /var/cache/apt/archives/lock || handle_error ${LINENO} - - log "INFO" "Updating package lists" - sudo apt-get update || handle_error ${LINENO} - - log "SUCCESS" "Installation preparation completed" -} +# 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 -# Setup NGINX Function -setup_nginx() { - log "INFO" "Setting up NGINX" +# Install and configure Nginx +log_message "INFO" "Installing and configuring Nginx..." +apt-get install nginx -y +check_command_status "Nginx installation" - # Remove Apache - log "INFO" "Removing Apache if exists" - sudo apt-get purge apache -y || log "WARNING" "Apache removal returned non-zero exit code" - sudo apt-get purge apache* -y || log "WARNING" "Apache cleanup returned non-zero exit code" - sudo kill -9 $(sudo lsof -t -i:80) 2>/dev/null || true - sudo kill -9 $(sudo lsof -t -i:443) 2>/dev/null || true +# Configure firewall +log_message "INFO" "Configuring firewall..." +ufw --force enable +ufw allow 'Nginx Full' +ufw allow OpenSSH +check_command_status "Firewall configuration" - # Install NGINX - log "INFO" "Installing NGINX" - sudo apt-get update || handle_error ${LINENO} - sudo apt install nginx -y || handle_error ${LINENO} +# Install PHP and extensions +log_message "INFO" "Installing PHP and extensions..." +add-apt-repository ppa:ondrej/php -y +apt-get update - # Configure firewall - log "INFO" "Configuring firewall for NGINX" - echo "y" | sudo ufw enable - sudo ufw allow 'Nginx HTTP' || handle_error ${LINENO} - sudo ufw allow 'Nginx HTTPS' || handle_error ${LINENO} - sudo ufw allow '8443' || handle_error ${LINENO} - sudo ufw allow OpenSSH || handle_error ${LINENO} - - log "SUCCESS" "NGINX setup completed" -} +# 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" -# Setup PHP Function -setup_php() { - log "INFO" "Setting up PHP" +# 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 PHP 8.2 - sudo apt-get update || handle_error ${LINENO} - sudo apt install lsb-release ca-certificates apt-transport-https software-properties-common -y || handle_error ${LINENO} - sudo add-apt-repository ppa:ondrej/php -y || handle_error ${LINENO} - - # Install PHP and extensions - log "INFO" "Installing PHP 8.2 and extensions" - sudo apt install php8.2 php8.2-fpm php8.2-common redis-server php8.2-redis openssl \ - php8.2-curl php8.2-mbstring php8.2-mysql php8.2-xml php8.2-zip php8.2-gd \ - php8.2-cli php8.2-imagick php8.2-intl -y || handle_error ${LINENO} +# 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 PHP 8.3 - log "INFO" "Installing PHP 8.3 and extensions" - sudo apt install php8.3 php8.3-fpm php8.3-redis openssl php8.3-common \ - php8.3-curl php8.3-mbstring php8.3-mysql php8.3-xml php8.3-zip php8.3-gd \ - php8.3-cli php8.3-imagick php8.3-intl -y || handle_error ${LINENO} +# 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" - log "SUCCESS" "PHP setup completed" -} +# 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" -# Setup Redis Function -setup_redis() { - log "INFO" "Setting up Redis" - - sudo apt-get install redis-server -y || handle_error ${LINENO} - - # Configure Redis - sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.backup || handle_error ${LINENO} - sudo sed -i 's/# maxmemory /maxmemory 512mb/' /etc/redis/redis.conf - sudo sed -i 's/# maxmemory-policy noeviction/maxmemory-policy allkeys-lru/' /etc/redis/redis.conf - - sudo systemctl restart redis-server || handle_error ${LINENO} - - log "SUCCESS" "Redis setup completed" -} - -# Setup Domain Function -setup_domain() { - local domain=$1 - log "INFO" "Setting up domain: ${domain}" - - # Create nginx configuration - sudo rm -rf /etc/nginx/sites-available/default /etc/nginx/sites-enabled/default - sudo touch /etc/nginx/sites-available/$domain || handle_error ${LINENO} - - # Your original nginx configuration block here - sudo bash -c "cat > /etc/nginx/sites-available/$domain << 'EOF' +# Configure Nginx for the domain +log_message "INFO" "Configuring Nginx for $domain..." +cat > "/etc/nginx/sites-available/$domain" << 'ENDOFFILE' server { listen 80; listen [::]:80; - root /var/www/html/$domain/public; - index index.php index.html index.htm index.nginx-debian.html; - server_name $domain www.$domain; + server_name DOMAIN_PLACEHOLDER www.DOMAIN_PLACEHOLDER; + root /var/www/html/DOMAIN_PLACEHOLDER/public; - # Enhanced security headers add_header X-Frame-Options "SAMEORIGIN"; - add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options "nosniff"; + index index.php; + charset utf-8; + location / { - try_files \$uri \$uri/ /index.php?\$query_string; + 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$ { - include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php8.2-fpm.sock; - fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; + fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; } - - location ~ /\.ht { + + location ~ /\.(?!well-known).* { deny all; } - - # Enhanced static file caching - location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { - expires 30d; - add_header Cache-Control "public, no-transform"; - } } -EOF" || handle_error ${LINENO} +ENDOFFILE - # Create symbolic link and directory structure - ln -s /etc/nginx/sites-available/$domain /etc/nginx/sites-enabled/ || handle_error ${LINENO} - sudo mkdir -p /var/www/html/$domain/public || handle_error ${LINENO} - - log "SUCCESS" "Domain setup completed" +# 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; } -# Setup SSL Function -setup_ssl() { - local domain=$1 - log "INFO" "Setting up SSL for domain: ${domain}" +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; - # Install certbot if not already installed - if ! command -v certbot &> /dev/null; then - log "INFO" "Installing Certbot" - sudo snap install --classic certbot || handle_error ${LINENO} - sudo ln -s /snap/bin/certbot /usr/bin/certbot || handle_error ${LINENO} - fi + # MIME + include mime.types; + default_type application/octet-stream; - # Generate SSL certificate - log "INFO" "Generating SSL certificate" - certbot --nginx -d $domain -d www.$domain --non-interactive --agree-tos -m admin@$domain || handle_error ${LINENO} - - log "SUCCESS" "SSL setup completed" + # 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 -# Setup Database Function -setup_mysql() { - log "INFO" "Setting up MySQL" - - if ! command -v mysql &> /dev/null; then - export DEBIAN_FRONTEND=noninteractive +# 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" - # Install MySQL - echo debconf mysql-server/root_password password $MYSQL_ROOT_PASSWORD | sudo debconf-set-selections - echo debconf mysql-server/root_password_again password $MYSQL_ROOT_PASSWORD | sudo debconf-set-selections - sudo apt-get -y install mysql-server || handle_error ${LINENO} + # Configure OpCache + cat >> "$phpfpm_conf" << 'ENDOFPHP' - # Secure MySQL installation - sudo mysql_secure_installation --password="$MYSQL_ROOT_PASSWORD" << EOF -y -0 -n -y -y -y -y -EOF +[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 - # Save MySQL password securely - echo $MYSQL_ROOT_PASSWORD | sudo tee /root/.mysql_root_password > /dev/null - chmod 600 /root/.mysql_root_password - - log "SUCCESS" "MySQL setup completed. Root password saved to /root/.mysql_root_password" - else - log "INFO" "MySQL is already installed" + systemctl restart "php$version-fpm" fi -} +done -# Setup Monitoring Function -setup_monitoring() { - log "INFO" "Setting up monitoring with Prometheus and Node Exporter" +# 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 - # Install Node Exporter - useradd --no-create-home --shell /bin/false node_exporter || log "WARNING" "User node_exporter already exists" - wget "https://github.com/prometheus/node_exporter/releases/download/v${NODE_EXPORTER_VERSION}/node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz" || handle_error ${LINENO} - tar xvf "node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz" - sudo cp node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64/node_exporter /usr/local/bin/ || handle_error ${LINENO} + # 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;" - # Create Node Exporter service - sudo bash -c 'cat > /etc/systemd/system/node_exporter.service << EOF -[Unit] -Description=Node Exporter -After=network.target + # Optimize MySQL configuration + cat >> /etc/mysql/mysql.conf.d/mysqld.cnf << 'ENDOFMYSQL' -[Service] -User=node_exporter -Group=node_exporter -Type=simple -ExecStart=/usr/local/bin/node_exporter - -[Install] -WantedBy=multi-user.target -EOF' - - # Start and enable services - sudo systemctl daemon-reload - sudo systemctl start node_exporter || handle_error ${LINENO} - sudo systemctl enable node_exporter || handle_error ${LINENO} +# 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 - log "SUCCESS" "Monitoring setup completed" -} + 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 -# Main function -main() { - local domain="" - - # Parse command line arguments - while getopts "d:h" flag; do - case "${flag}" in - d) domain=${OPTARG};; - h) - echo "Usage: $0 -d domain.com" - exit 0 - ;; - *) - echo "Invalid option. Usage: $0 -d domain.com" - exit 1 - ;; - esac - done +# 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 ####################" - if [ -z "$domain" ]; then - log "ERROR" "Domain parameter is required. Usage: $0 -d domain.com" - exit 1 - fi +(crontab -l 2>/dev/null; echo "$crontab_content") | crontab - - # Start installation process - log "INFO" "Starting server setup for ${domain}" - - # Perform system health check - check_system_health || { - log "ERROR" "System health check failed. Please resolve the issues before continuing." - exit 1 - } +# Setup monitoring (Prometheus + Node Exporter) +log_message "INFO" "Setting up monitoring..." +apt-get install -y prometheus node-exporter - # Create initial backup - create_backup +# Configure Prometheus +cat > /etc/prometheus/prometheus.yml << 'ENDOFPROMETHEUS' +global: + scrape_interval: 15s - # Run installation steps - prepare_installation - setup_nginx - setup_php - setup_redis - setup_domain "$domain" - setup_ssl "$domain" - setup_mysql - setup_monitoring +scrape_configs: + - job_name: 'node' + static_configs: + - targets: ['localhost:9100'] +ENDOFPROMETHEUS - # Create final backup - create_backup +systemctl enable prometheus node-exporter +systemctl start prometheus node-exporter - # Print completion message - log "INFO" "Installation completed successfully" - echo -e "${GREEN}Installation completed successfully!${NC}" - echo -e "${YELLOW}Important Information:${NC}" - echo -e "MySQL Root Password: ${MYSQL_ROOT_PASSWORD}" - echo -e "Installation Log: ${SCRIPT_LOG_FILE}" - echo -e "Backup Directory: ${BACKUP_DIR}" - echo -e "Monitoring URLs:" - echo -e " - Node Exporter: http://localhost:9100/metrics" -} +# 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 -# Start script execution -main "$@" \ No newline at end of file +# 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." \ No newline at end of file