#!/bin/bash clear set -e UNINSTALL=false REINSTALL=false SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" LOG_FILE="/tmp/altcor_install_$(date +%Y%m%d_%H%M%S).log" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' while getopts ":ur" opt; do case $opt in u) UNINSTALL=true ;; r) REINSTALL=true ;; \?) echo -e "${RED}[Ошибка]${NC} Неизвестный параметр: -$OPTARG" >&2 echo "Использование: $0 [-u] [-r]" echo " -u Полное удаление" echo " -r Переустановка (удаление + установка)" exit 1 ;; esac done log_to_file() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE"; } log_success() { echo -e "${GREEN}[Успех]${NC} $1"; log_to_file "SUCCESS: $1"; } log_error() { echo -e "${RED}[Ошибка]${NC} $1"; log_to_file "ERROR: $1"; } log_info() { echo -e "${BLUE}[Инфо]${NC} $1"; log_to_file "INFO: $1"; } log_warning() { echo -e "${YELLOW}[Предупреждение]${NC} $1"; log_to_file "WARNING: $1"; } log_step() { echo -e "${CYAN}[Шаг]${NC} $1"; log_to_file "STEP: $1"; } generate_password() { if command -v openssl >/dev/null 2>&1; then openssl rand -base64 32 | tr -d "=+/" | cut -c1-16 else head /dev/urandom | tr -dc A-Za-z0-9 | head -c 16 fi } check_root() { if [[ $EUID -ne 0 ]]; then log_error "Запустите этот скрипт с правами администратора (sudo)." exit 1 fi } detect_distro() { if [ -f /etc/os-release ]; then source /etc/os-release DISTRO="$ID" FAMILY="$ID_LIKE" VERSION_ID="${VERSION_ID}" else log_error "Не удалось определить дистрибутив." exit 1 fi if echo "$DISTRO $FAMILY" | grep -qi "debian\|ubuntu"; then PKG_MANAGER="apt" DISTRO_FAMILY="debian" WEBSERVER_SERVICE="apache2" WEBROOT="/var/www/html" APACHE_CONF="/etc/apache2/sites-available/000-default.conf" WEBSERVER_USER="www-data" PHP_INI_PATH="/etc/php/8.3/apache2/php.ini" DB_SOCKET="/var/run/mysqld/mysqld.sock" elif echo "$DISTRO $FAMILY" | grep -qi "rhel\|centos\|fedora\|rocky\|almalinux"; then DISTRO_FAMILY="rhel" WEBSERVER_SERVICE="httpd" WEBROOT="/var/www/html" APACHE_CONF="/etc/httpd/conf.d/altcor.conf" WEBSERVER_USER="apache" DB_SOCKET="/var/lib/mysql/mysql.sock" if command -v dnf >/dev/null 2>&1; then PKG_MANAGER="dnf" else PKG_MANAGER="yum" fi if [ -f "/etc/opt/remi/php83/php.ini" ]; then PHP_INI_PATH="/etc/opt/remi/php83/php.ini" PHP_FPM_CONF="/etc/opt/remi/php83/php-fpm.d/www.conf" PHP_FPM_SERVICE="php83-php-fpm" SOCKET_PATH="/var/opt/remi/php83/run/php-fpm/www.sock" elif [ -f "/etc/php.ini" ]; then PHP_INI_PATH="/etc/php.ini" PHP_FPM_CONF="/etc/php-fpm.d/www.conf" PHP_FPM_SERVICE="php-fpm" SOCKET_PATH="/run/php-fpm/www.sock" fi else log_error "Дистрибутив '$DISTRO' не поддерживается." log_info "Поддерживаются: Debian, Ubuntu, CentOS, RHEL, Fedora, Rocky Linux, AlmaLinux" exit 1 fi log_info "Обнаружен дистрибутив: $DISTRO ($DISTRO_FAMILY)" } safe_execute() { local description="$1" shift log_info "$description..." if "$@" >/dev/null 2>&1; then log_success "$description - выполнено" return 0 else log_error "$description - не удалось выполнить" log_to_file "FAILED COMMAND: $*" return 1 fi } check_component_status() { local component=$1 local command_check=$2 local service_check=$3 if command -v "$command_check" >/dev/null 2>&1; then if [[ -n "$service_check" ]]; then if systemctl is-active --quiet "$service_check" 2>/dev/null; then return 0 else return 1 fi else return 0 fi else return 2 fi } check_existing_installation() { log_step "Проверка существующей установки..." local apache_status php_status mariadb_status redis_status local need_reinstall=false log_info "Проверка Apache..." if [ "$DISTRO_FAMILY" = "debian" ]; then check_component_status "Apache" "apache2" "apache2" apache_status=$? else check_component_status "Apache" "httpd" "httpd" apache_status=$? fi log_info "Проверка PHP..." check_component_status "PHP" "php" "" php_status=$? log_info "Проверка MariaDB..." check_component_status "MariaDB" "mysql" "mariadb" mariadb_status=$? log_info "Проверка Redis..." if systemctl is-active --quiet redis-server 2>/dev/null || systemctl is-active --quiet redis 2>/dev/null; then redis_status=0 elif command -v redis-cli >/dev/null 2>&1; then redis_status=1 else redis_status=2 fi echo "" display_component_status "Apache" $apache_status display_php_status $php_status display_component_status "MariaDB" $mariadb_status display_component_status "Redis" $redis_status if [ -f "/var/www/html/db_config.php" ]; then echo -e "Конфигурация БД: ${GREEN}Найдена${NC}" else echo -e "Конфигурация БД: ${RED}Не найдена${NC}" need_reinstall=true fi echo "" if [[ $apache_status -ne 0 ]] || [[ $php_status -ne 0 ]] || [[ $mariadb_status -ne 0 ]]; then need_reinstall=true fi return $([ "$need_reinstall" = "true" ] && echo 1 || echo 0) } display_component_status() { local name=$1 local status=$2 case $status in 0) echo -e "$name: ${GREEN}Установлен и работает${NC}" ;; 1) echo -e "$name: ${YELLOW}Установлен, но не работает${NC}" ;; 2) echo -e "$name: ${RED}Не установлен${NC}" ;; esac } display_php_status() { local status=$1 case $status in 0) local php_version=$(php -v 2>/dev/null | head -1 | cut -d' ' -f2 | cut -d'.' -f1,2 2>/dev/null || echo "неизвестно") if [[ "$php_version" == "8.3" ]]; then echo -e "PHP: ${GREEN}Установлен (версия $php_version)${NC}" else echo -e "PHP: ${YELLOW}Установлен (версия $php_version, требуется 8.3)${NC}" return 1 fi ;; 2) echo -e "PHP: ${RED}Не установлен${NC}"; return 1 ;; esac return 0 } full_uninstall() { log_step "Начинаем полное удаление Altcor..." log_info "Остановка сервисов..." for service in nginx apache2 httpd php*-fpm mariadb mysql redis redis-server php83-php-fpm; do systemctl stop "$service" 2>/dev/null || true done log_info "Удаление пакетов..." if [ "$DISTRO_FAMILY" = "debian" ]; then export DEBIAN_FRONTEND=noninteractive for db_package in mariadb-server mysql-server; do for version in "" "-10.3" "-10.5" "-10.6" "-10.11" "-5.7" "-8.0"; do echo "${db_package}${version} mysql-server/remove-data-dir boolean true" | debconf-set-selections 2>/dev/null || true done done safe_execute "Удаление пакетов (Debian/Ubuntu)" \ apt purge -y nginx* apache2* php* mariadb* mysql* redis* safe_execute "Очистка неиспользуемых пакетов" apt autoremove -y else safe_execute "Удаление пакетов (RHEL/CentOS/Fedora)" \ $PKG_MANAGER remove -y nginx httpd php* mariadb* mysql* redis* fi log_info "Удаление файлов конфигурации и данных..." rm -rf /etc/nginx /etc/apache2 /etc/httpd /etc/php* /var/www/html/* \ /var/lib/mysql* /var/lib/redis* ~/.mysql_history /root/.mysql_history \ /root/.db_password /etc/opt/remi/php83 /opt/remi/php83 2>/dev/null || true log_success "Полное удаление завершено." if [ "$REINSTALL" = false ]; then exit 0 else log_info "Переустановка: удаление завершено, продолжаем установку..." echo "" fi } update_system() { log_step "Обновление системы и установка базовых пакетов..." if [ "$DISTRO_FAMILY" = "debian" ]; then export DEBIAN_FRONTEND=noninteractive safe_execute "Обновление списка пакетов" apt update -y safe_execute "Установка базовых пакетов" \ apt install -y software-properties-common lsb-release ca-certificates \ curl wget gnupg2 apt-transport-https unzip else safe_execute "Обновление системы" $PKG_MANAGER update -y safe_execute "Установка EPEL репозитория" $PKG_MANAGER install -y epel-release || true safe_execute "Установка базовых пакетов" \ $PKG_MANAGER install -y curl wget gnupg2 unzip fi } setup_php_repositories() { log_step "Настройка репозиториев для PHP 8.3..." if [ "$DISTRO_FAMILY" = "debian" ]; then if ! apt-cache show php8.3 &>/dev/null; then log_info "Добавление репозитория Sury для PHP 8.3..." if ! curl -fsSL https://packages.sury.org/php/apt.gpg | gpg --dearmor -o /usr/share/keyrings/php-archive-keyring.gpg 2>/dev/null; then log_warning "Не удалось добавить ключ Sury, пробуем PPA..." safe_execute "Добавление PPA ondrej/php" add-apt-repository ppa:ondrej/php -y else CODENAME=$(lsb_release -cs) echo "deb [signed-by=/usr/share/keyrings/php-archive-keyring.gpg] https://packages.sury.org/php/ $CODENAME main" > /etc/apt/sources.list.d/php.list fi safe_execute "Обновление списка пакетов после добавления репозитория PHP" apt update -y if ! apt-cache show php8.3 &>/dev/null; then log_error "PHP 8.3 недоступен после добавления репозиториев" exit 1 fi fi log_success "Репозиторий PHP 8.3 настроен" else log_info "Настройка репозиториев Remi для RHEL-семейства..." local version_id=$(echo "$VERSION_ID" | cut -d'.' -f1) if [ "$DISTRO" = "fedora" ]; then local fedora_version=$(rpm -E %fedora) safe_execute "Установка Remi репозитория для Fedora" \ $PKG_MANAGER install -y "https://rpms.remirepo.net/fedora/remi-release-${fedora_version}.rpm" else safe_execute "Установка Remi репозитория для RHEL/CentOS" \ $PKG_MANAGER install -y "https://rpms.remirepo.net/enterprise/remi-release-${version_id}.rpm" fi if command -v dnf >/dev/null 2>&1; then safe_execute "Сброс модуля PHP" dnf module reset php -y || true safe_execute "Включение модуля PHP 8.3" dnf module enable php:remi-8.3 -y || true fi log_success "Репозиторий Remi настроен" fi } install_components() { log_step "Установка основных компонентов..." log_info "Остановка конфликтующих сервисов..." for service in nginx httpd apache2 php*-fpm mariadb mysql; do systemctl stop "$service" 2>/dev/null || true done systemctl disable nginx httpd 2>/dev/null || true sleep 3 remove_old_packages if [ "$DISTRO_FAMILY" = "debian" ]; then safe_execute "Установка Apache" apt install -y apache2 else safe_execute "Установка Apache (httpd)" $PKG_MANAGER install -y httpd fi install_mariadb install_php83 install_additional_components } remove_old_packages() { log_info "Удаление старых версий пакетов..." if [ "$DISTRO_FAMILY" = "debian" ]; then export DEBIAN_FRONTEND=noninteractive for db_package in mariadb-server mysql-server; do for version in "" "-10.3" "-10.5" "-10.6" "-10.11" "-5.7" "-8.0"; do echo "${db_package}${version} mysql-server/remove-data-dir boolean true" | debconf-set-selections 2>/dev/null || true done done apt remove -y nginx nginx-common nginx-core 2>/dev/null || true apt remove -y php7.* php8.0* php8.1* php8.2* libapache2-mod-php7.* libapache2-mod-php8.0* libapache2-mod-php8.1* libapache2-mod-php8.2* 2>/dev/null || true apt remove --purge -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" mariadb* mysql* 2>/dev/null || true apt autoremove -y 2>/dev/null || true else $PKG_MANAGER remove -y nginx php php7* php80* php81* php82* mariadb* mysql* 2>/dev/null || true fi rm -rf /var/lib/mysql* /etc/mysql* /var/log/mysql* /etc/my.cnf* 2>/dev/null || true } install_mariadb() { log_info "Установка MariaDB..." if [ "$DISTRO_FAMILY" = "debian" ]; then export DEBIAN_FRONTEND=noninteractive echo "mariadb-server mysql-server/root_password password ''" | debconf-set-selections 2>/dev/null || true echo "mariadb-server mysql-server/root_password_again password ''" | debconf-set-selections 2>/dev/null || true safe_execute "Установка MariaDB" apt install -y mariadb-server else safe_execute "Установка MariaDB" $PKG_MANAGER install -y mariadb-server fi safe_execute "Запуск MariaDB" systemctl start mariadb safe_execute "Включение MariaDB в автозагрузку" systemctl enable mariadb log_info "Ожидание полного запуска MariaDB..." local retry_count=0 while ! systemctl is-active --quiet mariadb && [ $retry_count -lt 10 ]; do sleep 2 ((retry_count++)) done if ! systemctl is-active --quiet mariadb; then log_error "MariaDB не удалось запустить" exit 1 fi } install_php83() { log_info "Установка PHP 8.3 и расширений..." if [ "$DISTRO_FAMILY" = "debian" ]; then export DEBIAN_FRONTEND=noninteractive local php_packages="php8.3 php8.3-cli php8.3-common php8.3-mysql php8.3-curl php8.3-gd php8.3-mbstring php8.3-xml php8.3-zip php8.3-opcache php8.3-intl php8.3-bcmath php8.3-json php8.3-readline libapache2-mod-php8.3" else if $PKG_MANAGER list available | grep -q "php83-php\b"; then local php_packages="php83-php php83-php-cli php83-php-common php83-php-mysqlnd php83-php-curl php83-php-gd php83-php-mbstring php83-php-xml php83-php-zip php83-php-opcache php83-php-intl php83-php-bcmath php83-php-json php83-php-fpm" else local php_packages="php php-cli php-common php-mysqlnd php-curl php-gd php-mbstring php-xml php-zip php-opcache php-intl php-bcmath php-json php-fpm" fi fi if ! $PKG_MANAGER install -y $php_packages >/dev/null 2>&1; then log_error "Не удалось установить PHP пакеты. Подробности в логе: $LOG_FILE" $PKG_MANAGER install -y $php_packages 2>&1 | tee -a "$LOG_FILE" exit 1 fi if command -v php83 >/dev/null 2>&1 && [ ! -f /usr/bin/php ]; then ln -sf /opt/remi/php83/root/usr/bin/php /usr/bin/php 2>/dev/null || true echo 'export PATH=/opt/remi/php83/root/usr/bin:$PATH' > /etc/profile.d/php83.sh fi verify_php_installation } verify_php_installation() { log_info "Проверка установки PHP..." if ! command -v php >/dev/null 2>&1; then log_error "PHP не найден после установки" exit 1 fi local php_version=$(php -v 2>/dev/null | head -1 | cut -d' ' -f2 | cut -d'.' -f1,2 2>/dev/null || echo "неизвестно") if [[ "$php_version" != "8.3" ]]; then log_warning "PHP версия $php_version (ожидалась 8.3)" if [ "$DISTRO_FAMILY" = "debian" ] && [ -f /usr/bin/php8.3 ]; then update-alternatives --set php /usr/bin/php8.3 2>/dev/null || true php_version=$(php -v 2>/dev/null | head -1 | cut -d' ' -f2 | cut -d'.' -f1,2 2>/dev/null || echo "неизвестно") fi fi if [[ "$php_version" == "8.3" ]]; then log_success "PHP 8.3 успешно установлен" else log_error "Не удалось установить PHP 8.3 (текущая версия: $php_version)" exit 1 fi verify_php_extensions } verify_php_extensions() { log_info "Проверка PHP расширений..." local required_extensions="mysqli pdo_mysql curl gd mbstring xml zip opcache intl bcmath json" local missing_extensions="" for ext in $required_extensions; do if php -m 2>/dev/null | grep -q "^$ext$"; then log_success "Расширение $ext: установлено" else log_warning "Расширение $ext: НЕ найдено" missing_extensions="$missing_extensions $ext" fi done if [ -n "$missing_extensions" ]; then log_warning "Попытка установки отсутствующих расширений:$missing_extensions" install_missing_php_extensions "$missing_extensions" fi } install_missing_php_extensions() { local missing_extensions="$1" if [ "$DISTRO_FAMILY" = "debian" ]; then for ext in $missing_extensions; do if [[ "$ext" =~ ^(mysqli|pdo_mysql)$ ]]; then apt install -y php8.3-mysql 2>/dev/null || true else apt install -y "php8.3-$ext" 2>/dev/null || true fi done else for ext in $missing_extensions; do if [[ "$ext" =~ ^(mysqli|pdo_mysql)$ ]]; then $PKG_MANAGER install -y php*-mysqlnd 2>/dev/null || true else $PKG_MANAGER install -y "php*-$ext" 2>/dev/null || true fi done fi } install_additional_components() { log_info "Установка дополнительных компонентов (Redis, LibreOffice, Java)..." if [ "$DISTRO_FAMILY" = "debian" ]; then export DEBIAN_FRONTEND=noninteractive safe_execute "Установка дополнительных компонентов" \ apt install -y redis-server libreoffice default-jre else safe_execute "Установка дополнительных компонентов" \ $PKG_MANAGER install -y redis libreoffice java-11-openjdk fi } configure_apache_php() { log_step "Настройка Apache и PHP..." if [ "$DISTRO_FAMILY" = "debian" ]; then configure_apache_debian else configure_apache_rhel fi configure_php_ini create_virtual_host verify_apache_config } configure_apache_debian() { log_info "Настройка Apache для Debian/Ubuntu..." a2enmod php8.3 rewrite ssl headers expires deflate 2>/dev/null || true for php_ver in 7.4 8.0 8.1 8.2; do a2dismod "php$php_ver" 2>/dev/null || true done } configure_apache_rhel() { log_info "Настройка Apache для RHEL семейства..." rm -f /etc/httpd/conf.d/php.conf /etc/httpd/conf.modules.d/*php*.conf 2>/dev/null || true if ! httpd -V | grep -q "prefork"; then log_info "Переключение на MPM prefork..." $PKG_MANAGER remove -y httpd $PKG_MANAGER install -y httpd httpd-tools fi cat > /etc/httpd/conf.modules.d/00-mpm.conf << EOF LoadModule mpm_prefork_module modules/mod_mpm_prefork.so EOF # Добавление обязательных модулей echo "LoadModule rewrite_module modules/mod_rewrite.so" > /etc/httpd/conf.modules.d/00-altcor.conf echo "LoadModule proxy_module modules/mod_proxy.so" >> /etc/httpd/conf.modules.d/00-altcor.conf echo "LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so" >> /etc/httpd/conf.modules.d/00-altcor.conf configure_php_fpm create_php_fpm_config create_altcor_config # Резервное копирование конфигурации cp "$APACHE_CONF" "$APACHE_CONF.bak" cat > /etc/httpd/conf.modules.d/00-altcor-modules.conf << EOF LoadModule rewrite_module modules/mod_rewrite.so LoadModule headers_module modules/mod_headers.so LoadModule expires_module modules/mod_expires.so LoadModule deflate_module modules/mod_deflate.so LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so EOF } configure_php_fpm() { log_info "Настройка PHP-FPM..." if [ -z "$PHP_FPM_CONF" ] || [ ! -f "$PHP_FPM_CONF" ]; then PHP_FPM_CONF=$(find /etc/opt/remi/ -name www.conf 2>/dev/null | head -1) if [ -z "$PHP_FPM_CONF" ]; then PHP_FPM_CONF=$(find /etc/ -name www.conf 2>/dev/null | head -1) fi if [ -z "$PHP_FPM_CONF" ]; then log_error "Файл конфигурации PHP-FPM не найден" exit 1 fi fi cp "$PHP_FPM_CONF" "${PHP_FPM_CONF}.backup.$(date +%Y%m%d_%H%M%S)" sed -i "s|;*listen = .*|listen = $SOCKET_PATH|" "$PHP_FPM_CONF" sed -i 's/;*listen.owner = .*/listen.owner = apache/' "$PHP_FPM_CONF" sed -i 's/;*listen.group = .*/listen.group = apache/' "$PHP_FPM_CONF" sed -i 's/;*listen.mode = .*/listen.mode = 0660/' "$PHP_FPM_CONF" sed -i 's/;*user = .*/user = apache/' "$PHP_FPM_CONF" sed -i 's/;*group = .*/group = apache/' "$PHP_FPM_CONF" sed -i 's/;*pm = .*/pm = dynamic/' "$PHP_FPM_CONF" sed -i 's/;*pm.max_children = .*/pm.max_children = 50/' "$PHP_FPM_CONF" sed -i 's/;*pm.start_servers = .*/pm.start_servers = 5/' "$PHP_FPM_CONF" sed -i 's/;*pm.min_spare_servers = .*/pm.min_spare_servers = 5/' "$PHP_FPM_CONF" sed -i 's/;*pm.max_spare_servers = .*/pm.max_spare_servers = 35/' "$PHP_FPM_CONF" local socket_dir=$(dirname "$SOCKET_PATH") mkdir -p "$socket_dir" chown apache:apache "$socket_dir" chmod 775 "$socket_dir" chown apache:apache "$socket_dir" safe_execute "Запуск PHP-FPM" systemctl start "$PHP_FPM_SERVICE" safe_execute "Включение PHP-FPM в автозагрузку" systemctl enable "$PHP_FPM_SERVICE" if ! systemctl is-active --quiet "$PHP_FPM_SERVICE"; then log_error "PHP-FPM не удалось запустить" systemctl status "$PHP_FPM_SERVICE" --no-pager -l | tee -a "$LOG_FILE" exit 1 fi } create_php_fpm_config() { log_info "Создание конфигурации PHP-FPM для Apache..." cat > "/etc/httpd/conf.d/php-fpm.conf" << EOF # PHP-FPM configuration for Apache # Использование только PHP-FPM, без mod_php # Загрузка необходимых модулей LoadModule rewrite_module modules/mod_rewrite.so LoadModule headers_module modules/mod_headers.so LoadModule expires_module modules/mod_expires.so LoadModule deflate_module modules/mod_deflate.so LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so # Обработка PHP файлов через PHP-FPM SetHandler "proxy:unix:$SOCKET_PATH|fcgi://localhost" # Настройки производительности ProxyTimeout 300 ProxyPassMatch ^/(.*\.php(/.*)?)$ unix:$SOCKET_PATH|fcgi://localhost/var/www/html/ EOF } create_altcor_config() { log_info "Создание конфигурации Altcor..." cat > "/etc/httpd/conf.d/altcor.conf" << 'EOF' # Altcor main configuration # Безопасность сервера ServerTokens Prod ServerSignature Off echo "LoadModule rewrite_module modules/mod_rewrite.so" >> /etc/httpd/conf.d/altcor.conf # Основные настройки директории Options -Indexes +FollowSymLinks AllowOverride All Require all granted # Сжатие контента SetOutputFilter DEFLATE SetEnvIfNoCase Request_URI \ \.(?:gif|jpe?g|png|ico|exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary SetEnvIfNoCase User-Agent "^Mozilla/4\.0[678]" no-gzip SetEnvIfNoCase User-Agent "MSIE [1-6]\." no-gzip # Кэширование статических ресурсов ExpiresActive On ExpiresByType image/jpg "access plus 1 month" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType image/gif "access plus 1 month" ExpiresByType image/png "access plus 1 month" ExpiresByType image/svg+xml "access plus 1 month" ExpiresByType image/webp "access plus 1 month" ExpiresByType image/x-icon "access plus 1 month" ExpiresByType text/css "access plus 1 month" ExpiresByType application/javascript "access plus 1 month" ExpiresByType text/javascript "access plus 1 month" ExpiresByType font/woff "access plus 1 month" ExpiresByType font/woff2 "access plus 1 month" ExpiresByType font/ttf "access plus 1 month" ExpiresByType font/otf "access plus 1 month" ExpiresByType text/html "access plus 0 seconds" ExpiresByType application/x-httpd-php "access plus 0 seconds" # Заголовки безопасности Header always set X-Content-Type-Options nosniff Header always set X-Frame-Options SAMEORIGIN Header always set X-XSS-Protection "1; mode=block" Header always set Referrer-Policy "strict-origin-when-cross-origin" Header set Cache-Control "public, max-age=2592000" # Запрет доступа к служебным файлам Require all denied Require all denied Require all denied # Защита директории uploads Require all denied EOF } configure_php_ini() { log_info "Настройка PHP.ini..." if [ ! -f "$PHP_INI_PATH" ]; then log_warning "Файл PHP.ini не найден по пути: $PHP_INI_PATH" return fi cp "$PHP_INI_PATH" "${PHP_INI_PATH}.backup.$(date +%Y%m%d_%H%M%S)" sed -i 's/;*upload_max_filesize = .*/upload_max_filesize = 64M/' "$PHP_INI_PATH" sed -i 's/;*post_max_size = .*/post_max_size = 64M/' "$PHP_INI_PATH" sed -i 's/;*max_execution_time = .*/max_execution_time = 300/' "$PHP_INI_PATH" sed -i 's/;*memory_limit = .*/memory_limit = 256M/' "$PHP_INI_PATH" sed -i 's/;*max_input_vars = .*/max_input_vars = 3000/' "$PHP_INI_PATH" sed -i 's/;*opcache.enable=.*/opcache.enable=1/' "$PHP_INI_PATH" sed -i 's/;*opcache.enable_cli=.*/opcache.enable_cli=1/' "$PHP_INI_PATH" sed -i 's/;*opcache.memory_consumption=.*/opcache.memory_consumption=128/' "$PHP_INI_PATH" sed -i 's/;*opcache.revalidate_freq=.*/opcache.revalidate_freq=2/' "$PHP_INI_PATH" sed -i 's/;*opcache.max_accelerated_files=.*/opcache.max_accelerated_files=4000/' "$PHP_INI_PATH" sed -i 's/;*expose_php = .*/expose_php = Off/' "$PHP_INI_PATH" sed -i 's/;*display_errors = .*/display_errors = Off/' "$PHP_INI_PATH" sed -i 's/;*log_errors = .*/log_errors = On/' "$PHP_INI_PATH" log_success "PHP.ini настроен" } create_virtual_host() { log_info "Создание конфигурации виртуального хоста..." mkdir -p "$WEBROOT" if [ "$DISTRO_FAMILY" = "debian" ]; then cat > "$APACHE_CONF" << EOF DocumentRoot $WEBROOT ServerName localhost ServerAlias www.localhost Options -Indexes +FollowSymLinks AllowOverride All Require all granted SetOutputFilter DEFLATE SetEnvIfNoCase Request_URI \ \.(?:gif|jpe?g|png)$ no-gzip dont-vary SetEnvIfNoCase Request_URI \ \.(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary SetHandler application/x-httpd-php Require all denied ExpiresActive On ExpiresByType image/jpg "access plus 1 month" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType image/gif "access plus 1 month" ExpiresByType image/png "access plus 1 month" ExpiresByType text/css "access plus 1 month" ExpiresByType application/javascript "access plus 1 month" ErrorLog \${APACHE_LOG_DIR}/error.log CustomLog \${APACHE_LOG_DIR}/access.log combined EOF fi } verify_apache_config() { log_info "Проверка конфигурации Apache..." if [ "$DISTRO_FAMILY" = "debian" ]; then if ! apache2ctl configtest >/dev/null 2>&1; then log_error "Конфигурация Apache содержит ошибки:" apache2ctl configtest 2>&1 | tee -a "$LOG_FILE" exit 1 fi else log_info "Проверка загруженных модулей:" httpd -M 2>&1 | tee -a "$LOG_FILE" if ! httpd -t >/dev/null 2>&1; then log_error "Ошибки конфигурации:" httpd -t 2>&1 | tee -a "$LOG_FILE" # Автоматическое исправление распространённых ошибок if grep -q "Could not open configuration file" "$LOG_FILE"; then log_info "Попытка восстановления конфигурации..." cp -f "$APACHE_CONF.bak" "$APACHE_CONF" fi exit 1 fi fi log_success "Конфигурация Apache проверена" } configure_database() { log_step "Настройка базы данных MariaDB..." local db_password=$(generate_password) if ! systemctl is-active --quiet mariadb; then log_error "MariaDB не запущен" exit 1 fi setup_mariadb_security "$db_password" create_db_config "$db_password" save_db_credentials "$db_password" echo "$db_password" } setup_mariadb_security() { local db_password="$1" log_info "Выполнение базовой настройки безопасности MariaDB..." if mysql -u root -e "SELECT 1;" >/dev/null 2>&1; then log_info "Первичная настройка MariaDB..." setup_fresh_mariadb "$db_password" elif mysql -u root -p"$db_password" -e "SELECT 1;" >/dev/null 2>&1; then log_info "MariaDB уже настроен, обновляем базу данных..." update_existing_mariadb "$db_password" else log_warning "Требуется сброс пароля root в MariaDB..." reset_mariadb_password "$db_password" fi } setup_fresh_mariadb() { local db_password="$1" local script_file="/tmp/mysql_secure_$(date +%s).sql" cat > "$script_file" << MYSQL_SCRIPT ALTER USER 'root'@'localhost' IDENTIFIED BY '$db_password'; DELETE FROM mysql.user WHERE User=''; DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1'); DROP DATABASE IF EXISTS test; DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%'; CREATE DATABASE IF NOT EXISTS ALTCor CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; GRANT ALL PRIVILEGES ON ALTCor.* TO 'root'@'localhost'; FLUSH PRIVILEGES; MYSQL_SCRIPT if mysql -u root < "$script_file" >/dev/null 2>&1; then log_success "Первичная настройка MariaDB выполнена" else log_error "Ошибка при настройке MariaDB" rm -f "$script_file" exit 1 fi rm -f "$script_file" } update_existing_mariadb() { local db_password="$1" local script_file="/tmp/mysql_update_$(date +%s).sql" cat > "$script_file" << MYSQL_SCRIPT CREATE DATABASE IF NOT EXISTS ALTCor CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; GRANT ALL PRIVILEGES ON ALTCor.* TO 'root'@'localhost'; FLUSH PRIVILEGES; MYSQL_SCRIPT if mysql -u root -p"$db_password" < "$script_file" >/dev/null 2>&1; then log_success "База данных ALTCor обновлена" else log_error "Ошибка при обновлении базы данных" rm -f "$script_file" exit 1 fi rm -f "$script_file" } reset_mariadb_password() { local db_password="$1" log_info "Сброс пароля root в MariaDB..." systemctl stop mariadb mysqld_safe --skip-grant-tables --skip-networking & local mysqld_pid=$! sleep 5 local reset_script="/tmp/mysql_reset_$(date +%s).sql" cat > "$reset_script" << MYSQL_SCRIPT USE mysql; UPDATE user SET password=PASSWORD('$db_password') WHERE User='root'; UPDATE user SET plugin='mysql_native_password' WHERE User='root'; FLUSH PRIVILEGES; MYSQL_SCRIPT if mysql -u root < "$reset_script" >/dev/null 2>&1; then kill $mysqld_pid 2>/dev/null || true sleep 3 killall mysqld_safe mysqld 2>/dev/null || true sleep 3 systemctl start mariadb sleep 3 if systemctl is-active --quiet mariadb && mysql -u root -p"$db_password" -e "SELECT 1;" >/dev/null 2>&1; then update_existing_mariadb "$db_password" log_success "Пароль MariaDB сброшен и база данных настроена" else log_error "MariaDB не запустился после сброса пароля" exit 1 fi else log_error "Не удалось сбросить пароль root в MariaDB" kill $mysqld_pid 2>/dev/null || true exit 1 fi rm -f "$reset_script" } create_db_config() { local db_password="$1" log_info "Создание конфигурации базы данных..." cat > "$WEBROOT/db_config.php" << EOF EOF chown "$WEBSERVER_USER:$WEBSERVER_USER" "$WEBROOT/db_config.php" chmod 600 "$WEBROOT/db_config.php" if ! sudo -u "$WEBSERVER_USER" test -r "$WEBROOT/db_config.php"; then log_error "Веб-сервер не может читать db_config.php" exit 1 fi log_success "Конфигурация БД создана" } save_db_credentials() { local db_password="$1" local credentials_file="/root/.db_password" cat > "$credentials_file" << EOF # Altcor Database Credentials DB_HOST=localhost DB_USER=root DB_PASSWORD=$db_password DB_NAME=ALTCor DB_SOCKET=$DB_SOCKET CREATED=$(date) EOF chmod 600 "$credentials_file" log_info "Учетные данные сохранены в $credentials_file" } setup_web_application() { log_step "Настройка веб-приложения..." find "$WEBROOT" -type f ! -name "db_config.php" -delete 2>/dev/null || true download_application_files create_htaccess_file setup_file_permissions } download_application_files() { local download_url="https://cloud.altcor.ru/setup/download.php" log_info "Загрузка файлов приложения..." if curl -f -L --max-time 30 -o "$WEBROOT/index.php" "$download_url" 2>/dev/null; then if head -n 1 "$WEBROOT/index.php" | grep -q "/dev/null; then log_success "Файлы приложения загружены" return fi fi log_warning "Не удалось загрузить файлы с $download_url, создаем резервную страницу" create_fallback_index } create_fallback_index() { cat > "$WEBROOT/index.php" << 'EOF' Altcor - Сервер готов

Altcor - Система готова

PHP работает
Время:
✅ База данных подключена"; } catch (PDOException $e) { echo "info'>⚠️ БД: " . htmlspecialchars($e->getMessage()); } ?>
Установка завершена!
Система готова для развертывания Altcor.
EOF } create_htaccess_file() { log_info "Создание .htaccess файла..." cat > "$WEBROOT/.htaccess" << 'EOF' # Altcor .htaccess Configuration # Безопасность Require all denied Require all denied # Сжатие AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/json application/xml # Кэширование ExpiresActive On ExpiresByType image/jpg "access plus 1 month" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType image/gif "access plus 1 month" ExpiresByType image/png "access plus 1 month" ExpiresByType image/svg+xml "access plus 1 month" ExpiresByType image/webp "access plus 1 month" ExpiresByType text/css "access plus 1 month" ExpiresByType application/javascript "access plus 1 month" ExpiresByType text/javascript "access plus 1 month" ExpiresByType font/woff "access plus 1 month" ExpiresByType font/woff2 "access plus 1 month" # Заголовки безопасности Header always set X-Content-Type-Options nosniff Header always set X-Frame-Options SAMEORIGIN Header always set X-XSS-Protection "1; mode=block" Header always set Referrer-Policy "strict-origin-when-cross-origin" # URL Rewriting RewriteEngine On # RewriteCond %{REQUEST_FILENAME} !-f # RewriteCond %{REQUEST_FILENAME} !-d # RewriteRule ^(.*)$ index.php [QSA,L] EOF } setup_file_permissions() { log_info "Настройка прав доступа к файлам..." chown -R "$WEBSERVER_USER:$WEBSERVER_USER" "$WEBROOT" find "$WEBROOT" -type d -exec chmod 755 {} \; find "$WEBROOT" -type f -exec chmod 644 {} \; chmod 600 "$WEBROOT/db_config.php" log_success "Права доступа настроены" } start_services() { log_step "Запуск и включение сервисов..." local services_to_restart="" local services_to_enable="" if [ "$DISTRO_FAMILY" = "debian" ]; then services_to_restart="apache2 mariadb" services_to_enable="apache2 mariadb" else services_to_restart="$PHP_FPM_SERVICE httpd mariadb" services_to_enable="$PHP_FPM_SERVICE httpd mariadb" fi if systemctl list-unit-files | grep -q "redis-server.service"; then services_to_restart="$services_to_restart redis-server" services_to_enable="$services_to_enable redis-server" elif systemctl list-unit-files | grep -q "redis.service"; then services_to_restart="$services_to_restart redis" services_to_enable="$services_to_enable redis" fi for service in $services_to_restart; do if safe_execute "Перезапуск $service" systemctl restart "$service"; then log_success "$service перезапущен" else log_error "Не удалось перезапустить $service" fi done for service in $services_to_enable; do safe_execute "Включение $service в автозагрузку" systemctl enable "$service" || true done log_success "Все сервисы настроены" } final_verification() { log_step "Финальная проверка работоспособности..." local errors=0 if ! systemctl is-active --quiet "$WEBSERVER_SERVICE"; then log_error "Веб-сервер ($WEBSERVER_SERVICE) не запущен" ((errors++)) else log_success "Веб-сервер работает" fi if [ "$DISTRO_FAMILY" = "rhel" ] && [ -n "$PHP_FPM_SERVICE" ]; then if ! systemctl is-active --quiet "$PHP_FPM_SERVICE"; then log_error "PHP-FPM ($PHP_FPM_SERVICE) не запущен" ((errors++)) else log_success "PHP-FPM работает" fi fi if ! systemctl is-active --quiet mariadb; then log_error "MariaDB не запущен" ((errors++)) else log_success "MariaDB работает" fi if ! php -r "echo 'PHP OK';" >/dev/null 2>&1; then log_error "PHP не работает корректно" ((errors++)) else log_success "PHP работает корректно" fi if [ -f "$WEBROOT/db_config.php" ]; then if php -r " require '$WEBROOT/db_config.php'; try { \$pdo = new PDO('mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=' . DB_CHARSET, DB_USER, DB_PASS); echo 'DB OK'; } catch (Exception \$e) { exit(1); } " >/dev/null 2>&1; then log_success "Подключение к базе данных работает" else log_error "Не удается подключиться к базе данных" ((errors++)) fi else log_error "Файл конфигурации БД не найден" ((errors++)) fi if [ $errors -eq 0 ]; then log_success "Все компоненты работают корректно" return 0 else log_error "Обнаружено $errors ошибок в работе системы" return 1 fi } show_final_info() { local db_password="$1" local ip_addr=$(hostname -I | awk '{print $1}' 2>/dev/null || echo "N/A") echo "" if [ "$REINSTALL" = true ]; then log_success "Переустановка Altcor успешно завершена" else log_success "Установка Altcor успешно завершена" fi echo "" echo -e "${CYAN}Доступ к сайту:${NC}" echo " • http://localhost/" echo " • http://$ip_addr/" echo "" echo -e "${CYAN}Доступ к БД:${NC}" echo " • Хост: localhost" echo " • Логин: root" echo " • Пароль: $db_password" echo " • База данных: ALTCor" echo "" echo -e "${CYAN}Расположение файлов:${NC}" echo " • Веб-корень: $WEBROOT" echo " • Конфигурация БД: $WEBROOT/db_config.php" echo " • Логи Apache: /var/log/apache2/ или /var/log/httpd/" echo " • Лог установки: $LOG_FILE" echo "" echo -e "${CYAN}Дополнительная информация:${NC}" echo " • Учетные данные БД: /root/.db_password" echo " • Для удаления: $0 -u" echo " • Для переустановки: $0 -r" echo "" echo -e "${GREEN}Система готова к работе!${NC}" echo "==============================================================" echo "" } proceed_with_installation() { echo "" echo "Начинаем установку Altcor..." echo "" update_system setup_php_repositories install_components configure_apache_php local db_password db_password=$(configure_database) setup_web_application start_services if final_verification; then show_final_info "$db_password" else log_error "Установка завершена с ошибками. Проверьте лог: $LOG_FILE" exit 1 fi } handle_existing_installation() { local need_reinstall=$1 if [ $need_reinstall -eq 0 ]; then if [ "$REINSTALL" = true ]; then log_warning "Обнаружена существующая установка. Начинаем переустановку..." return 1 else log_success "Все компоненты уже установлены и работают корректно" echo "" echo -e "${YELLOW}Altcor уже полностью установлен и функционирует.${NC}" echo "" read -p "Хотите переустановить систему? [y/n]: " -n 1 -r echo "" if [[ $REPLY =~ ^[Yy]$ ]]; then log_info "Начинаем переустановку по запросу пользователя..." REINSTALL=true return 1 else echo "" log_info "Переустановка отменена. Система остается без изменений." echo "" echo "Для принудительной переустановки используйте: $0 -r" echo "" exit 0 fi fi else log_warning "Обнаружены проблемы с установленными компонентами." echo "" read -p "Хотите переустановить всю систему? [y/n]: " -n 1 -r echo "" if [[ $REPLY =~ ^[Yy]$ ]]; then log_info "Начинаем полную переустановку..." REINSTALL=true return 1 else log_info "Продолжаем обычную установку/обновление компонентов..." return 0 fi fi } main() { log_to_file "Начало установки Altcor $(date)" check_root detect_distro if [ "$UNINSTALL" = true ]; then full_uninstall elif [ "$REINSTALL" = true ]; then echo "" log_step "Начинаем переустановку Altcor..." echo "" full_uninstall proceed_with_installation else local check_result=0 check_existing_installation || check_result=$? local action_result=0 handle_existing_installation $check_result || action_result=$? if [ $action_result -eq 1 ]; then if [ "$REINSTALL" = true ]; then full_uninstall fi proceed_with_installation elif [ $action_result -eq 0 ]; then proceed_with_installation fi fi log_to_file "=== Завершение установки Altcor $(date) ===" } trap 'log_error "Установка прервана пользователем"; exit 130' INT TERM main "$@"