#!/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" # Color codes for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # Logging function log() { 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} } # 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 fi } trap 'handle_error ${LINENO}' ERR # System health check function check_system_health() { log "INFO" "Performing system health checks..." # 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 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 log "INFO" "System health checks passed" return 0 } # 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" } # 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" } # Setup NGINX Function setup_nginx() { log "INFO" "Setting up NGINX" # 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 # Install NGINX log "INFO" "Installing NGINX" sudo apt-get update || handle_error ${LINENO} sudo apt install nginx -y || handle_error ${LINENO} # 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" } # Setup PHP Function setup_php() { log "INFO" "Setting up PHP" # 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 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} log "SUCCESS" "PHP setup completed" } # 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' 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; # Enhanced security headers add_header X-Frame-Options "SAMEORIGIN"; add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options "nosniff"; location / { try_files \$uri \$uri/ /index.php?\$query_string; } 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; include fastcgi_params; } location ~ /\.ht { 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} # 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" } # Setup SSL Function setup_ssl() { local domain=$1 log "INFO" "Setting up SSL for domain: ${domain}" # 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 # 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" } # Setup Database Function setup_mysql() { log "INFO" "Setting up MySQL" if ! command -v mysql &> /dev/null; then export DEBIAN_FRONTEND=noninteractive # 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} # Secure MySQL installation sudo mysql_secure_installation --password="$MYSQL_ROOT_PASSWORD" << EOF y 0 n y y y y EOF # 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" fi } # Setup Monitoring Function setup_monitoring() { log "INFO" "Setting up monitoring with Prometheus and Node Exporter" # 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} # Create Node Exporter service sudo bash -c 'cat > /etc/systemd/system/node_exporter.service << EOF [Unit] Description=Node Exporter After=network.target [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} log "SUCCESS" "Monitoring setup completed" } # 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 if [ -z "$domain" ]; then log "ERROR" "Domain parameter is required. Usage: $0 -d domain.com" exit 1 fi # 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 } # Create initial backup create_backup # Run installation steps prepare_installation setup_nginx setup_php setup_redis setup_domain "$domain" setup_ssl "$domain" setup_mysql setup_monitoring # Create final backup create_backup # 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" } # Start script execution main "$@"