#!/bin/bash # ============================================================================ # ServerManager - Installation Script # For Ubuntu Server 22.04+ / 24.04+ # ============================================================================ 1 set -e RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${GREEN}[INFO]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } log_step() { echo -e "\n${BLUE}=== $1 ===${NC}"; } APP_DIR="/var/www/servermanager" NGINX_CONFIG="/etc/nginx/sites-available/servermanager" KEY_FILE="/etc/servermanager/master.key" PHP_VERSION="${PHP_VERSION:-8.3}" check_root() { if [[ $EUID -ne 0 ]]; then log_error "This script must be run as root (use sudo)" exit 1 fi } install_system_packages() { return log_step "Installing System Packages" apt-get update -qq apt-get install -y -qq \ nginx \ mysql-server \ php${PHP_VERSION} \ php${PHP_VERSION}-fpm \ php${PHP_VERSION}-cli \ php${PHP_VERSION}-mysql \ php${PHP_VERSION}-mbstring \ php${PHP_VERSION}-xml \ php${PHP_VERSION}-curl \ php${PHP_VERSION}-zip \ php${PHP_VERSION}-gd \ php${PHP_VERSION}-openssl \ php${PHP_VERSION}-json \ composer \ unzip \ git \ curl \ wget \ openssl log_info "System packages installed successfully" } configure_php() { log_step "Configuring PHP ${PHP_VERSION}" PHP_INI="/etc/php/${PHP_VERSION}/fpm/php.ini" PHP_CLI_INI="/etc/php/${PHP_VERSION}/cli/php.ini" for INI in "$PHP_INI" "$PHP_CLI_INI"; do if [ -f "$INI" ]; then sed -i 's/^memory_limit = .*/memory_limit = 256M/' "$INI" sed -i 's/^max_execution_time = .*/max_execution_time = 300/' "$INI" sed -i 's/^post_max_size = .*/post_max_size = 64M/' "$INI" sed -i 's/^upload_max_filesize = .*/upload_max_filesize = 32M/' "$INI" sed -i 's/^;?max_input_vars = .*/max_input_vars = 3000/' "$INI" log_info "Configured: $INI" fi done systemctl restart php${PHP_VERSION}-fpm log_info "PHP-FPM restarted" } configure_mysql() { log_step "Configuring MySQL" DB_NAME="servermanager" DB_USER="servermanager" DB_PASS=$(openssl rand -base64 32) if mysql -e "SELECT 1" &>/dev/null; then mysql -e "CREATE DATABASE IF NOT EXISTS \`${DB_NAME}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" mysql -e "CREATE USER IF NOT EXISTS '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';" mysql -e "GRANT ALL PRIVILEGES ON \`${DB_NAME}\`.* TO '${DB_USER}'@'localhost';" mysql -e "FLUSH PRIVILEGES;" mysql "${DB_NAME}" < "${APP_DIR}/database/migrations/001_initial_schema.sql" log_info "Database '${DB_NAME}' created and migrated" log_info "DB Username: ${DB_USER}" log_info "DB Password: ${DB_PASS} (saved in .env)" else log_error "Could not connect to MySQL. Please configure manually." DB_PASS="CHANGE_ME" fi echo "$DB_PASS" > /tmp/servermanager_db_pass chmod 600 /tmp/servermanager_db_pass } generate_master_key() { log_step "Generating Master Encryption Key" if [ -f "$KEY_FILE" ]; then log_warn "Master key already exists at ${KEY_FILE}" log_warn "Skipping generation (backup existing key first if you want to regenerate)" return fi MASTER_KEY=$(openssl rand -hex 32) echo "$MASTER_KEY" > "$KEY_FILE" chmod 600 "$KEY_FILE" chown rafael:rafael "$KEY_FILE" log_info "Master key generated: ${KEY_FILE}" log_warn "IMPORTANT: Store this key securely. If lost, ALL SSH credentials become unrecoverable!" } deploy_application() { log_step "Deploying Application" mkdir -p "$APP_DIR" if [ -f "./composer.json" ]; then cp -r ./* "$APP_DIR/" cp .env.example "$APP_DIR/.env" cp .env "$APP_DIR/.env" 2>/dev/null || true fi chown -R rafael:rafael "$APP_DIR" chmod -R 755 "$APP_DIR" mkdir -p "${APP_DIR}/logs" mkdir -p "${APP_DIR}/storage/ssh_keys" chown -R rafael:rafael "${APP_DIR}/logs" "${APP_DIR}/storage" chmod -R 750 "${APP_DIR}/logs" "${APP_DIR}/storage" chmod 700 "${APP_DIR}/storage/ssh_keys" log_info "Application deployed to ${APP_DIR}" } configure_env() { log_step "Configuring Environment" DB_PASS=$(cat /tmp/servermanager_db_pass 2>/dev/null || echo "CHANGE_ME") MASTER_KEY=$(cat "$KEY_FILE" 2>/dev/null || echo "") sed -i "s|DB_HOST=.*|DB_HOST=127.0.0.1|" "${APP_DIR}/.env" sed -i "s|DB_PORT=.*|DB_PORT=3306|" "${APP_DIR}/.env" sed -i "s|DB_DATABASE=.*|DB_DATABASE=servermanager|" "${APP_DIR}/.env" sed -i "s|DB_USERNAME=.*|DB_USERNAME=servermanager|" "${APP_DIR}/.env" sed -i "s|DB_PASSWORD=.*|DB_PASSWORD=${DB_PASS}|" "${APP_DIR}/.env" sed -i "s|SESSION_SECURE=.*|SESSION_SECURE=true|" "${APP_DIR}/.env" sed -i "s|SESSION_HTTP_ONLY=.*|SESSION_HTTP_ONLY=true|" "${APP_DIR}/.env" sed -i "s|SESSION_SAME_SITE=.*|SESSION_SAME_SITE=Lax|" "${APP_DIR}/.env" sed -i "s|MASTER_ENCRYPTION_KEY=.*|MASTER_ENCRYPTION_KEY=${MASTER_KEY}|" "${APP_DIR}/.env" sed -i "s|MASTER_ENCRYPTION_KEY_FILE=.*|MASTER_ENCRYPTION_KEY_FILE=${KEY_FILE}|" "${APP_DIR}/.env" sed -i "s|APP_ENV=.*|APP_ENV=production|" "${APP_DIR}/.env" sed -i "s|APP_DEBUG=.*|APP_DEBUG=false|" "${APP_DIR}/.env" log_info ".env file configured" rm -f /tmp/servermanager_db_pass } install_composer_dependencies() { log_step "Installing Composer Dependencies" cd "$APP_DIR" sudo -u www-data composer install --no-dev --optimize-autoloader --no-interaction log_info "Dependencies installed" } configure_nginx() { log_step "Configuring Nginx" cat > "$NGINX_CONFIG" << 'NGINXEOF' server { listen 80; listen [::]:80; server_name _; root /var/www/servermanager/public; index index.php; charset utf-8; client_max_body_size 64M; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php8.3-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } location ~ /\.(?!well-known).* { deny all; } location ~* \.(env|log|json|lock|key|sql|md)$ { deny all; } location /assets/ { expires 30d; add_header Cache-Control "public, immutable"; } add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "DENY" always; add_header X-XSS-Protection "1; mode=block" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; } NGINXEOF ln -sf "$NGINX_CONFIG" /etc/nginx/sites-enabled/servermanager rm -f /etc/nginx/sites-enabled/default nginx -t && systemctl reload nginx log_info "Nginx configured and reloaded" } configure_cron() { log_step "Configuring Cron Jobs" cat > /etc/cron.d/servermanager << CRONEOF # ServerManager Monitoring Cron # Collect metrics every minute * * * * * www-data /usr/bin/php ${APP_DIR}/bin/monitor.php >> ${APP_DIR}/logs/cron.log 2>&1 # Cleanup old logs weekly 0 3 * * 0 www-data find ${APP_DIR}/logs/ -name "*.log" -mtime +30 -delete CRONEOF chmod 644 /etc/cron.d/servermanager log_info "Cron jobs configured" } create_binaries() { log_step "Creating CLI Scripts" mkdir -p "${APP_DIR}/bin" cat > "${APP_DIR}/bin/monitor.php" << 'PHPEOF' boot(dirname(__DIR__)); $monitoring = new MonitoringService(); $results = $monitoring->collectAllMetrics(); $online = count(array_filter($results, fn($r) => $r && ($r['status'] ?? '') === 'online')); $offline = count($results) - $online; echo sprintf("[%s] Metrics collected: %d servers (%d online, %d offline)\n", date('Y-m-d H:i:s'), count($results), $online, $offline); } catch (\Throwable $e) { echo sprintf("[%s] ERROR: %s\n", date('Y-m-d H:i:s'), $e->getMessage()); exit(1); } PHPEOF cat > "${APP_DIR}/bin/generate-key.php" << 'PHPEOF' 1 && $argv[1] === '--force') { echo "Generating new master encryption key...\n"; } elseif (file_exists($keyFile)) { echo "Master key already exists at {$keyFile}\n"; echo "Use --force to regenerate (WARNING: this will make existing encrypted data unreadable)\n"; exit(1); } $key = bin2hex(random_bytes(32)); file_put_contents($keyFile, $key, LOCK_EX); chmod($keyFile, 0600); echo "Master key generated: {$keyFile}\n"; echo "IMPORTANT: Store this key securely!\n"; PHPEOF chmod +x "${APP_DIR}/bin/monitor.php" chmod +x "${APP_DIR}/bin/generate-key.php" chown -R rafael:rafael "${APP_DIR}/bin" log_info "CLI scripts created" } show_completion_message() { log_step "Installation Complete" echo "" echo -e "${GREEN}╔════════════════════════════════════════════════════════╗${NC}" echo -e "${GREEN}║ ServerManager Installation Completed! ║${NC}" echo -e "${GREEN}╚════════════════════════════════════════════════════════╝${NC}" echo "" echo -e " URL: ${BLUE}http://$(hostname -I | awk '{print $1}')${NC}" echo -e " Username: ${YELLOW}admin${NC}" echo -e " Password: ${YELLOW}Admin@123${NC} ${RED}(CHANGE IMMEDIATELY!)${NC}" echo -e " Key File: ${YELLOW}${KEY_FILE}${NC}" echo "" echo -e " ${RED}IMPORTANT:${NC}" echo -e " 1. Change the default admin password immediately" echo -e " 2. Backup your master encryption key: ${KEY_FILE}" echo -e " 3. Configure HTTPS with Let's Encrypt:" echo -e " ${BLUE}certbot --nginx -d your-domain.com${NC}" echo -e " 4. Review logs at: ${APP_DIR}/logs/" echo "" } main() { echo "" echo -e "${GREEN}╔════════════════════════════════════════════════════════╗${NC}" echo -e "${GREEN}║ ServerManager - Automated Installer ║${NC}" echo -e "${GREEN}╚════════════════════════════════════════════════════════╝${NC}" echo "" check_root install_system_packages deploy_application configure_mysql generate_master_key configure_env install_composer_dependencies configure_php configure_nginx create_binaries configure_cron show_completion_message } main "$@"