331 lines
10 KiB
Bash
Executable File
331 lines
10 KiB
Bash
Executable File
#!/bin/bash
|
|
# ============================================================================
|
|
# ServerManager - Installation Script
|
|
# For Ubuntu Server 22.04+ / 24.04+
|
|
# ============================================================================
|
|
|
|
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 Cron Jobs
|
|
# Logs cleanup — 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/generate-key.php" << 'PHPEOF'
|
|
<?php
|
|
declare(strict_types=1);
|
|
|
|
$keyFile = '/etc/servermanager/master.key';
|
|
|
|
if ($argc > 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/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 "$@"
|