#!/bin/bash # ============================================================================= # MY UPLOADER BOT - ПОЛНАЯ АВТОМАТИЧЕСКАЯ УСТАНОВКА НА PRODUCTION СЕРВЕР # ============================================================================= # Клонирует все модули из projscale.dev и настраивает полную систему # Поддерживает типы нод: main (основная) и regular (обычная) # ============================================================================= set -euo pipefail # Выход при любой ошибке # Цвета для вывода RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' WHITE='\033[1;37m' NC='\033[0m' # No Color # Конфигурация DOMAIN="$1" NODE_TYPE="${2:-regular}" # main или regular, по умолчанию: regular EMAIL="${3:-admin@${1}}" PROJECT_DIR="/home/myuploader" SERVICE_USER="myuploader" PROGRESS_FILE="/home/myuploader/.installation_progress" # Репозитории для клонирования UPLOADER_REPO="https://git.projscale.dev/my-dev/uploader-bot" CONVERTER_REPO="https://git.projscale.dev/my-dev/converter-module" WEB2_REPO="https://git.projscale.dev/my-dev/web2-client" # Функция логирования log() { echo -e "${WHITE}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" >&2 } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } log_info() { echo -e "${BLUE}[INFO]${NC} $1" } # Функция записи прогресса log_progress() { local step="$1" echo "$step:$(date '+%Y-%m-%d %H:%M:%S')" >> "$PROGRESS_FILE" log_success "Этап завершен: $step" } # Функция проверки завершенности этапа is_step_completed() { local step="$1" if [ -f "$PROGRESS_FILE" ]; then grep -q "^$step:" "$PROGRESS_FILE" else return 1 fi } # Функция пропуска уже выполненных этапов check_and_skip() { local step="$1" local description="$2" if is_step_completed "$step"; then log_info "⏭️ Пропускаем: $description (уже выполнено)" return 0 else log "🔄 Выполняется: $description" return 1 fi } # Проверка аргументов if [ $# -lt 1 ]; then echo -e "${RED}Использование: $0 [node_type] [email]${NC}" echo "Примеры:" echo " $0 my-uploader.example.com regular" echo " $0 my-uploader.example.com main admin@example.com" echo "" echo "Типы нод:" echo " main - Основная нода (с web2-client, полные возможности)" echo " regular - Обычная нода (только uploader-bot + converter-module)" exit 1 fi # Создание директории прогресса mkdir -p "$(dirname "$PROGRESS_FILE")" touch "$PROGRESS_FILE" echo "" echo -e "${PURPLE}================================================${NC}" echo -e "${WHITE}🚀 MY UPLOADER BOT - PRODUCTION SETUP${NC}" echo -e "${PURPLE}================================================${NC}" echo -e "${CYAN}Домен:${NC} $DOMAIN" echo -e "${CYAN}Тип ноды:${NC} $NODE_TYPE" echo -e "${CYAN}Email:${NC} $EMAIL" echo -e "${CYAN}Пользователь:${NC} $SERVICE_USER" echo -e "${CYAN}Директория:${NC} $PROJECT_DIR" echo -e "${CYAN}Прогресс файл:${NC} $PROGRESS_FILE" echo "" echo -e "${CYAN}Репозитории:${NC}" echo -e " 📦 Uploader Bot: $UPLOADER_REPO" echo -e " 🔄 Converter: $CONVERTER_REPO" if [ "$NODE_TYPE" = "main" ]; then echo -e " 🌐 Web2 Client: $WEB2_REPO" else echo -e " 🌐 Web2 Client: ${YELLOW}пропускается (обычная нода)${NC}" fi echo -e "${PURPLE}================================================${NC}" echo "" # Проверка прав root if [ "$EUID" -ne 0 ]; then log_error "Этот скрипт должен запускаться с правами root" exit 1 fi # Проверка интернет соединения if ! ping -c 1 google.com &> /dev/null; then log_error "Нет интернет соединения" exit 1 fi echo "" echo -e "${BLUE}==========================================${NC}" echo -e "${WHITE} 🔄 ШАГ 1: ОБНОВЛЕНИЕ СИСТЕМЫ${NC}" echo -e "${BLUE}==========================================${NC}" echo "" if ! check_and_skip "system_update" "Обновление системы"; then log "Обновление списка пакетов..." apt update -y log "Обновление системы..." apt upgrade -y log "Установка базовых пакетов..." apt install -y \ curl \ wget \ git \ unzip \ htop \ nano \ vim \ tree \ jq \ software-properties-common \ apt-transport-https \ ca-certificates \ gnupg \ lsb-release \ ufw \ fail2ban \ netstat-nat \ python3 \ python3-pip \ nodejs \ npm log_progress "system_update" fi echo "" echo -e "${BLUE}==========================================${NC}" echo -e "${WHITE} 🐳 ШАГ 2: УСТАНОВКА DOCKER${NC}" echo -e "${BLUE}==========================================${NC}" echo "" if ! check_and_skip "docker_install" "Установка Docker"; then # Удаление старых версий Docker log "Удаление старых версий Docker..." apt remove -y docker docker-engine docker.io containerd runc 2>/dev/null || true # Установка Docker log "Добавление Docker GPG ключа..." curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg log "Добавление Docker репозитория..." echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null log "Обновление списка пакетов..." apt update -y log "Установка Docker..." apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin # Установка Docker Compose standalone log "Установка Docker Compose..." DOCKER_COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep 'tag_name' | cut -d\" -f4) curl -L "https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose # Запуск Docker log "Запуск Docker..." systemctl start docker systemctl enable docker # Проверка Docker log "Проверка Docker..." docker --version docker-compose --version log_progress "docker_install" fi echo "" echo -e "${BLUE}==========================================${NC}" echo -e "${WHITE} 🌐 ШАГ 3: УСТАНОВКА NGINX${NC}" echo -e "${BLUE}==========================================${NC}" echo "" if ! check_and_skip "nginx_install" "Установка Nginx"; then log "Установка Nginx..." apt install -y nginx log "Запуск Nginx..." systemctl start nginx systemctl enable nginx log "Nginx версия: $(nginx -v 2>&1)" log_progress "nginx_install" fi echo "" echo -e "${BLUE}==========================================${NC}" echo -e "${WHITE} 🔐 ШАГ 4: УСТАНОВКА CERTBOT${NC}" echo -e "${BLUE}==========================================${NC}" echo "" if ! check_and_skip "certbot_install" "Установка Certbot"; then log "Установка snapd (если нужно)..." apt install -y snapd log "Установка Certbot через snap..." snap install core; snap refresh core snap install --classic certbot log "Создание симлинка для certbot..." ln -sf /snap/bin/certbot /usr/bin/certbot log "Certbot версия: $(certbot --version)" log_progress "certbot_install" fi echo "" echo -e "${BLUE}==========================================${NC}" echo -e "${WHITE} 👤 ШАГ 5: СОЗДАНИЕ ПОЛЬЗОВАТЕЛЯ СЕРВИСА${NC}" echo -e "${BLUE}==========================================${NC}" echo "" if ! check_and_skip "service_user" "Создание пользователя сервиса"; then log "Создание пользователя $SERVICE_USER..." if ! id "$SERVICE_USER" &>/dev/null; then useradd -m -s /bin/bash "$SERVICE_USER" usermod -aG sudo "$SERVICE_USER" usermod -aG docker "$SERVICE_USER" log_success "Пользователь $SERVICE_USER создан" else usermod -aG docker "$SERVICE_USER" log_info "Пользователь $SERVICE_USER уже существует" fi log_progress "service_user" fi echo "" echo -e "${BLUE}==========================================${NC}" echo -e "${WHITE} 📂 ШАГ 6: КЛОНИРОВАНИЕ РЕПОЗИТОРИЕВ${NC}" echo -e "${BLUE}==========================================${NC}" echo "" if ! check_and_skip "repositories_clone" "Клонирование репозиториев"; then log "Создание директории проекта..." mkdir -p "$PROJECT_DIR" chown "$SERVICE_USER:$SERVICE_USER" "$PROJECT_DIR" # Переключение на пользователя myuploader для клонирования cd "$PROJECT_DIR" log "Клонирование uploader-bot..." if [ -d "uploader-bot" ]; then log_warning "Директория uploader-bot уже существует, удаляем..." rm -rf uploader-bot fi sudo -u "$SERVICE_USER" git clone "$UPLOADER_REPO" uploader-bot log_success "uploader-bot склонирован" log "Клонирование converter-module..." if [ -d "converter-module" ]; then log_warning "Директория converter-module уже существует, удаляем..." rm -rf converter-module fi sudo -u "$SERVICE_USER" git clone "$CONVERTER_REPO" converter-module log_success "converter-module склонирован" # Клонирование web2-client только для основной ноды if [ "$NODE_TYPE" = "main" ]; then log "Клонирование web2-client..." if [ -d "web2-client" ]; then log_warning "Директория web2-client уже существует, удаляем..." rm -rf web2-client fi sudo -u "$SERVICE_USER" git clone "$WEB2_REPO" web2-client log_success "web2-client склонирован" else log_info "⏭️ Пропускаем web2-client (обычная нода)" fi # Проверка структуры log "Структура проекта:" sudo -u "$SERVICE_USER" tree -L 2 "$PROJECT_DIR" || ls -la "$PROJECT_DIR" log_progress "repositories_clone" fi echo "" echo -e "${BLUE}==========================================${NC}" echo -e "${WHITE} ⚙️ ШАГ 7: НАСТРОЙКА ОКРУЖЕНИЯ${NC}" echo -e "${BLUE}==========================================${NC}" echo "" if ! check_and_skip "environment_setup" "Настройка окружения"; then # Переход в основную директорию uploader-bot MAIN_PROJECT_DIR="$PROJECT_DIR/uploader-bot" cd "$MAIN_PROJECT_DIR" log "Генерация .env файла для uploader-bot..." # Генерация случайных ключей SECRET_KEY=$(openssl rand -hex 32) JWT_SECRET=$(openssl rand -hex 32) ENCRYPTION_KEY=$(openssl rand -hex 16) POSTGRES_PASSWORD=$(openssl rand -hex 16) NODE_ID="$NODE_TYPE-node-$(date +%s)" # Создание .env файла cat > "$MAIN_PROJECT_DIR/.env" << EOF # MY UPLOADER BOT - PRODUCTION CONFIGURATION NODE_ENV=production DEBUG=false # Node Configuration NODE_TYPE=$NODE_TYPE # Domain MY_NETWORK_DOMAIN=$DOMAIN # Database DATABASE_URL=postgresql://my_user:$POSTGRES_PASSWORD@postgres:5432/my_uploader_db POSTGRES_HOST=postgres POSTGRES_PORT=5432 POSTGRES_DB=my_uploader_db POSTGRES_USER=my_user POSTGRES_PASSWORD=$POSTGRES_PASSWORD # Redis REDIS_URL=redis://redis:6379/0 REDIS_HOST=redis REDIS_PORT=6379 # Security Keys SECRET_KEY=$SECRET_KEY JWT_SECRET=$JWT_SECRET ENCRYPTION_KEY=$ENCRYPTION_KEY # MY Network Settings MY_NETWORK_NODE_ID=$NODE_ID MY_NETWORK_PORT=15100 MY_NETWORK_HOST=0.0.0.0 MY_NETWORK_DOMAIN=$DOMAIN MY_NETWORK_SSL_ENABLED=true # API Settings API_HOST=0.0.0.0 API_PORT=15100 API_WORKERS=4 MAX_UPLOAD_SIZE=100MB # Converter Settings (On-Demand) CONVERTER_DOCKER_IMAGE=my-converter:latest CONVERTER_SHARED_PATH=/shared/converter CONVERTER_MAX_PARALLEL=3 CONVERTER_TIMEOUT=300 # Logging LOG_LEVEL=INFO LOG_FORMAT=json # Monitoring GRAFANA_PASSWORD=admin123 EOF chown "$SERVICE_USER:$SERVICE_USER" "$MAIN_PROJECT_DIR/.env" log_success "Файл .env создан" # Создание симлинков для модулей в uploader-bot log "Создание симлинков для модулей..." sudo -u "$SERVICE_USER" mkdir -p "$MAIN_PROJECT_DIR/modules" sudo -u "$SERVICE_USER" ln -sf "$PROJECT_DIR/converter-module" "$MAIN_PROJECT_DIR/modules/converter-module" if [ "$NODE_TYPE" = "main" ]; then sudo -u "$SERVICE_USER" ln -sf "$PROJECT_DIR/web2-client" "$MAIN_PROJECT_DIR/modules/web2-client" fi log_success "Симлинки созданы" log_progress "environment_setup" fi echo "" echo -e "${BLUE}==========================================${NC}" echo -e "${WHITE} 🌐 ШАГ 8: НАСТРОЙКА NGINX${NC}" echo -e "${BLUE}==========================================${NC}" echo "" if ! check_and_skip "nginx_config" "Настройка Nginx"; then log "Настройка Nginx конфигурации..." # Сначала добавляем rate limiting в основной конфиг nginx log "Добавление rate limiting в nginx.conf..." # Создаем backup оригинального конфига cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup # Добавляем rate limiting в блок http if ! grep -q "limit_req_zone" /etc/nginx/nginx.conf; then sed -i '/http {/a\\n\t# Rate limiting zones\n\tlimit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;\n\tlimit_req_zone $binary_remote_addr zone=upload:10m rate=5r/s;\n' /etc/nginx/nginx.conf fi log "Создание site конфигурации для типа ноды: $NODE_TYPE..." # Создание базового nginx конфига для сайта mkdir -p /etc/nginx/sites-available mkdir -p /etc/nginx/sites-enabled if [ "$NODE_TYPE" = "main" ]; then # Конфигурация для основной ноды (с web2-client) cat > "/etc/nginx/sites-available/$DOMAIN" << EOF server { listen 80; server_name $DOMAIN; # Redirect all HTTP requests to HTTPS return 301 https://\$server_name\$request_uri; } server { listen 443 ssl http2; server_name $DOMAIN; # SSL configuration will be added by certbot # Security headers add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; # Web2 Client (main page for main nodes) location / { limit_req zone=api burst=20 nodelay; proxy_pass http://127.0.0.1:3000/; proxy_http_version 1.1; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto \$scheme; } # API endpoints location /api/ { limit_req zone=api burst=20 nodelay; proxy_pass http://127.0.0.1:15100/; proxy_http_version 1.1; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto \$scheme; proxy_cache_bypass \$http_upgrade; proxy_read_timeout 300s; proxy_connect_timeout 75s; } # Upload endpoint with stricter rate limiting location /api/upload { limit_req zone=upload burst=10 nodelay; proxy_pass http://127.0.0.1:15100/upload; proxy_http_version 1.1; proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto \$scheme; proxy_read_timeout 600s; proxy_send_timeout 600s; client_max_body_size 100M; } # Converter API (on-demand, через uploader-bot) location /converter/ { limit_req zone=upload burst=10 nodelay; proxy_pass http://127.0.0.1:15100/api/convert/; proxy_http_version 1.1; proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto \$scheme; proxy_read_timeout 600s; proxy_send_timeout 600s; client_max_body_size 100M; } # Health check (no rate limiting) location /health { proxy_pass http://127.0.0.1:15100/health; access_log off; } # Static files location /static/ { alias $MAIN_PROJECT_DIR/static/; expires 30d; add_header Cache-Control "public, immutable"; } # Disable access to hidden files location ~ /\. { deny all; access_log off; log_not_found off; } } EOF else # Конфигурация для обычной ноды (только API) cat > "/etc/nginx/sites-available/$DOMAIN" << EOF server { listen 80; server_name $DOMAIN; # Redirect all HTTP requests to HTTPS return 301 https://\$server_name\$request_uri; } server { listen 443 ssl http2; server_name $DOMAIN; # SSL configuration will be added by certbot # Security headers add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; # Main API (uploader-bot) location / { limit_req zone=api burst=20 nodelay; proxy_pass http://127.0.0.1:15100; proxy_http_version 1.1; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto \$scheme; proxy_cache_bypass \$http_upgrade; proxy_read_timeout 300s; proxy_connect_timeout 75s; } # Upload endpoint with stricter rate limiting location /upload { limit_req zone=upload burst=10 nodelay; proxy_pass http://127.0.0.1:15100/upload; proxy_http_version 1.1; proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto \$scheme; proxy_read_timeout 600s; proxy_send_timeout 600s; client_max_body_size 100M; } # Converter API (on-demand, через uploader-bot) location /converter/ { limit_req zone=upload burst=10 nodelay; proxy_pass http://127.0.0.1:15100/api/convert/; proxy_http_version 1.1; proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto \$scheme; proxy_read_timeout 600s; proxy_send_timeout 600s; client_max_body_size 100M; } # Health check (no rate limiting) location /health { proxy_pass http://127.0.0.1:15100/health; access_log off; } # Static files location /static/ { alias $MAIN_PROJECT_DIR/static/; expires 30d; add_header Cache-Control "public, immutable"; } # Disable access to hidden files location ~ /\. { deny all; access_log off; log_not_found off; } } EOF fi # Активация сайта ln -sf "/etc/nginx/sites-available/$DOMAIN" "/etc/nginx/sites-enabled/" # Удаление дефолтного сайта rm -f /etc/nginx/sites-enabled/default # Проверка конфигурации log "Проверка конфигурации Nginx..." if nginx -t; then systemctl reload nginx log_success "Nginx конфигурация создана и применена" else log_error "Ошибка в конфигурации Nginx" # Показываем конкретную ошибку nginx -t exit 1 fi log_progress "nginx_config" fi echo "" echo -e "${BLUE}==========================================${NC}" echo -e "${WHITE} 🔐 ШАГ 9: ПОЛУЧЕНИЕ SSL СЕРТИФИКАТА${NC}" echo -e "${BLUE}==========================================${NC}" echo "" if ! check_and_skip "ssl_certificate" "Получение SSL сертификата"; then log "Получение SSL сертификата для $DOMAIN..." # Проверка что домен указывает на этот сервер DOMAIN_IP=$(dig +short "$DOMAIN" | tail -n1) SERVER_IP=$(curl -s ifconfig.me || curl -s ipinfo.io/ip) if [ "$DOMAIN_IP" != "$SERVER_IP" ]; then log_warning "Домен $DOMAIN не указывает на этот сервер" log_warning "Домен IP: $DOMAIN_IP, Сервер IP: $SERVER_IP" log_warning "Попытка получения сертификата может не удаться" fi # Получение SSL сертификата if certbot --nginx -d "$DOMAIN" --non-interactive --agree-tos --email "$EMAIL" --redirect; then log_success "SSL сертификат получен" log_progress "ssl_certificate" else log_error "Не удалось получить SSL сертификат" log_warning "Можете получить его позже командой:" log_warning "sudo certbot --nginx -d $DOMAIN" fi fi echo "" echo -e "${BLUE}==========================================${NC}" echo -e "${WHITE} 🔒 ШАГ 10: НАСТРОЙКА БЕЗОПАСНОСТИ${NC}" echo -e "${BLUE}==========================================${NC}" echo "" if ! check_and_skip "security_setup" "Настройка безопасности"; then log "Настройка UFW firewall..." # Сброс UFW ufw --force reset # Базовые правила ufw default deny incoming ufw default allow outgoing # Разрешение SSH ufw allow ssh # Разрешение HTTP/HTTPS ufw allow 80/tcp ufw allow 443/tcp # Включение UFW ufw --force enable log "Настройка Fail2Ban..." # Создание кастомного фильтра для nginx cat > /etc/fail2ban/filter.d/nginx-my-uploader.conf << 'EOF' [Definition] failregex = ^ -.*"(GET|POST|HEAD).*" (4\d\d|5\d\d) .*$ ^ -.*".*" (4\d\d|5\d\d) .*$ ignoreregex = EOF # Конфигурация jail для MY Uploader cat > /etc/fail2ban/jail.d/my-uploader.conf << 'EOF' [nginx-my-uploader] enabled = true port = http,https filter = nginx-my-uploader logpath = /var/log/nginx/access.log maxretry = 5 findtime = 600 bantime = 3600 action = iptables-multiport[name=nginx-my-uploader, port="http,https", protocol=tcp] EOF # Перезапуск Fail2Ban systemctl restart fail2ban systemctl enable fail2ban log_success "Безопасность настроена" log_progress "security_setup" fi echo "" echo -e "${BLUE}==========================================${NC}" echo -e "${WHITE} 🐳 ШАГ 11: СБОРКА И ЗАПУСК${NC}" echo -e "${BLUE}==========================================${NC}" echo "" if ! check_and_skip "docker_build" "Сборка и запуск"; then MAIN_PROJECT_DIR="$PROJECT_DIR/uploader-bot" cd "$MAIN_PROJECT_DIR" log "Сборка Docker образов..." # Проверяем наличие docker-compose файлов if [ -f "docker-compose.production.yml" ]; then COMPOSE_FILE="docker-compose.production.yml" elif [ -f "docker-compose.yml" ]; then COMPOSE_FILE="docker-compose.yml" else log_error "Не найден docker-compose файл" exit 1 fi log "Используется $COMPOSE_FILE" # Сборка образов от имени пользователя сервиса log "Сборка основного приложения..." sudo -u "$SERVICE_USER" docker-compose -f "$COMPOSE_FILE" build # Сборка converter image (если есть профиль build-only) log "Сборка converter image..." sudo -u "$SERVICE_USER" docker-compose -f "$COMPOSE_FILE" --profile build-only build converter-build 2>/dev/null || \ sudo -u "$SERVICE_USER" docker-compose -f "$COMPOSE_FILE" build converter 2>/dev/null || \ log_warning "Converter build пропущен (нет соответствующего сервиса)" log "Запуск приложения..." if [ "$NODE_TYPE" = "main" ]; then # Для основной ноды запускаем все сервисы sudo -u "$SERVICE_USER" docker-compose -f "$COMPOSE_FILE" up -d log "🚀 Запущены все сервисы для основной ноды" else # Для обычной ноды запускаем только необходимые сервисы sudo -u "$SERVICE_USER" docker-compose -f "$COMPOSE_FILE" up -d uploader-bot converter-builder watchtower 2>/dev/null || \ sudo -u "$SERVICE_USER" docker-compose -f "$COMPOSE_FILE" up -d log "🚀 Запущены основные сервисы для обычной ноды" fi # Ожидание запуска log "Ожидание запуска сервисов..." sleep 15 # Проверка статуса log "Проверка статуса контейнеров..." sudo -u "$SERVICE_USER" docker-compose -f "$COMPOSE_FILE" ps log_success "Приложение запущено" log_progress "docker_build" fi echo "" echo -e "${BLUE}==========================================${NC}" echo -e "${WHITE} 🏁 ШАГ 12: ФИНАЛЬНАЯ ПРОВЕРКА${NC}" echo -e "${BLUE}==========================================${NC}" echo "" if ! check_and_skip "final_check" "Финальная проверка"; then MAIN_PROJECT_DIR="$PROJECT_DIR/uploader-bot" log "Проверка доступности сервисов..." # Проверка локального API if curl -f -s http://localhost:15100/health > /dev/null; then log_success "Локальный API доступен" else log_error "Локальный API недоступен" fi # Проверка web2-client только для основной ноды if [ "$NODE_TYPE" = "main" ]; then if curl -f -s http://localhost:3000/health > /dev/null 2>&1; then log_success "Web2-client доступен" else log_warning "Web2-client может быть недоступен" fi fi # Проверка HTTPS API if curl -f -s "https://$DOMAIN/health" > /dev/null; then log_success "HTTPS API доступен" else log_warning "HTTPS API пока недоступен (может потребоваться время)" fi # Создание управляющих скриптов log "Создание управляющих скриптов..." # Определяем какой compose file использовать if [ -f "$MAIN_PROJECT_DIR/docker-compose.production.yml" ]; then COMPOSE_FILE="docker-compose.production.yml" else COMPOSE_FILE="docker-compose.yml" fi cat > "$MAIN_PROJECT_DIR/start.sh" << EOF #!/bin/bash cd $MAIN_PROJECT_DIR if [ "$NODE_TYPE" = "main" ]; then docker-compose -f $COMPOSE_FILE up -d else docker-compose -f $COMPOSE_FILE up -d uploader-bot converter-builder watchtower 2>/dev/null || docker-compose -f $COMPOSE_FILE up -d fi echo "✅ MY Uploader Bot запущен (тип ноды: $NODE_TYPE)" docker-compose -f $COMPOSE_FILE ps EOF cat > "$MAIN_PROJECT_DIR/stop.sh" << EOF #!/bin/bash cd $MAIN_PROJECT_DIR docker-compose -f $COMPOSE_FILE down echo "🛑 MY Uploader Bot остановлен" EOF cat > "$MAIN_PROJECT_DIR/status.sh" << EOF #!/bin/bash cd $MAIN_PROJECT_DIR echo "📊 Статус MY Uploader Bot (тип ноды: $NODE_TYPE):" docker-compose -f $COMPOSE_FILE ps echo "" echo "🌐 API статус:" curl -s http://localhost:15100/health | jq . 2>/dev/null || echo "API недоступен" echo "" echo "🔒 SSL сертификат:" sudo certbot certificates | grep -A2 -B2 $DOMAIN || echo "Нет SSL сертификата" echo "" echo "📈 Прогресс установки:" cat $PROGRESS_FILE 2>/dev/null || echo "Файл прогресса не найден" EOF cat > "$MAIN_PROJECT_DIR/logs.sh" << EOF #!/bin/bash cd $MAIN_PROJECT_DIR docker-compose -f $COMPOSE_FILE logs -f EOF cat > "$MAIN_PROJECT_DIR/rebuild.sh" << EOF #!/bin/bash cd $MAIN_PROJECT_DIR echo "🔄 Пересборка и перезапуск..." docker-compose -f $COMPOSE_FILE down docker-compose -f $COMPOSE_FILE build if [ "$NODE_TYPE" = "main" ]; then docker-compose -f $COMPOSE_FILE up -d else docker-compose -f $COMPOSE_FILE up -d uploader-bot converter-builder watchtower 2>/dev/null || docker-compose -f $COMPOSE_FILE up -d fi echo "✅ Пересборка завершена" docker-compose -f $COMPOSE_FILE ps EOF chmod +x "$MAIN_PROJECT_DIR"/{start,stop,status,logs,rebuild}.sh chown "$SERVICE_USER:$SERVICE_USER" "$MAIN_PROJECT_DIR"/{start,stop,status,logs,rebuild}.sh # Настройка автозапуска log "Настройка автозапуска..." if [ "$NODE_TYPE" = "main" ]; then SERVICE_EXEC_START="/usr/local/bin/docker-compose -f $COMPOSE_FILE up -d" SERVICE_DESCRIPTION="MY Uploader Bot (Main Node)" else SERVICE_EXEC_START="/usr/local/bin/docker-compose -f $COMPOSE_FILE up -d uploader-bot converter-builder watchtower" SERVICE_DESCRIPTION="MY Uploader Bot (Regular Node)" fi cat > /etc/systemd/system/my-uploader-bot.service << EOF [Unit] Description=$SERVICE_DESCRIPTION Requires=docker.service After=docker.service [Service] Type=oneshot RemainAfterExit=yes User=$SERVICE_USER Group=$SERVICE_USER WorkingDirectory=$MAIN_PROJECT_DIR ExecStart=$SERVICE_EXEC_START ExecStop=/usr/local/bin/docker-compose -f $COMPOSE_FILE down TimeoutStartSec=300 [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable my-uploader-bot.service log_success "Автозапуск настроен" log_progress "final_check" fi echo "" echo -e "${GREEN}================================================${NC}" echo -e "${WHITE}🎉 УСТАНОВКА ЗАВЕРШЕНА УСПЕШНО!${NC}" echo -e "${GREEN}================================================${NC}" echo "" echo -e "${CYAN}🌐 Домен:${NC} https://$DOMAIN" echo -e "${CYAN}🏷️ Тип ноды:${NC} $NODE_TYPE" echo -e "${CYAN}📁 Проект:${NC} $MAIN_PROJECT_DIR" echo -e "${CYAN}👤 Пользователь:${NC} $SERVICE_USER" echo -e "${CYAN}📊 Прогресс:${NC} $PROGRESS_FILE" echo "" echo -e "${YELLOW}📦 Установленные модули:${NC}" echo -e " 🚀 Uploader Bot: $PROJECT_DIR/uploader-bot" echo -e " 🔄 Converter: $PROJECT_DIR/converter-module" if [ "$NODE_TYPE" = "main" ]; then echo -e " 🌐 Web2 Client: $PROJECT_DIR/web2-client" else echo -e " 🌐 Web2 Client: ${YELLOW}пропущен (обычная нода)${NC}" fi echo "" # Показываем разные endpoints в зависимости от типа ноды if [ "$NODE_TYPE" = "main" ]; then echo -e "${YELLOW}🌍 Доступные endpoints (основная нода):${NC}" echo -e " 🌐 Web Interface: https://$DOMAIN/" echo -e " 📊 API: https://$DOMAIN/api/" echo -e " 📤 Upload: https://$DOMAIN/api/upload" echo -e " 🔄 Converter API: https://$DOMAIN/converter/" echo -e " ❤️ Health Check: https://$DOMAIN/health" else echo -e "${YELLOW}🌍 Доступные endpoints (обычная нода):${NC}" echo -e " 📊 API: https://$DOMAIN/" echo -e " 📤 Upload: https://$DOMAIN/upload" echo -e " 🔄 Converter API: https://$DOMAIN/converter/" echo -e " ❤️ Health Check: https://$DOMAIN/health" fi echo "" echo -e "${YELLOW}📋 Полезные команды:${NC}" echo -e "${WHITE}# Статус системы${NC}" echo "sudo $MAIN_PROJECT_DIR/status.sh" echo "" echo -e "${WHITE}# Просмотр логов${NC}" echo "sudo $MAIN_PROJECT_DIR/logs.sh" echo "" echo -e "${WHITE}# Перезапуск системы${NC}" echo "sudo $MAIN_PROJECT_DIR/stop.sh && sudo $MAIN_PROJECT_DIR/start.sh" echo "" echo -e "${WHITE}# Пересборка и перезапуск${NC}" echo "sudo $MAIN_PROJECT_DIR/rebuild.sh" echo "" echo -e "${WHITE}# Проверка SSL сертификата${NC}" echo "sudo certbot certificates" echo "" echo -e "${YELLOW}🔧 Управление сервисом:${NC}" echo "sudo systemctl start my-uploader-bot" echo "sudo systemctl stop my-uploader-bot" echo "sudo systemctl status my-uploader-bot" echo "" echo -e "${YELLOW}🔄 Повторная установка:${NC}" echo "# Для полной переустановки:" echo "sudo rm -f $PROGRESS_FILE" echo "# Для сброса определенного этапа отредактируйте:" echo "sudo nano $PROGRESS_FILE" echo "" echo -e "${YELLOW}🌍 MY Network API:${NC}" echo "curl https://$DOMAIN/api/my/bootstrap/config" echo "" echo -e "${YELLOW}📊 Мониторинг:${NC}" echo "docker stats" echo "sudo docker-compose -f $MAIN_PROJECT_DIR/$COMPOSE_FILE logs -f" echo "" echo -e "${GREEN}✅ MY Uploader Bot готов к работе!${NC}" echo "" # Отметка полной установки log_progress "installation_complete" # Финальная проверка доступности log "Финальная проверка через 5 секунд..." sleep 5 if curl -f -s "https://$DOMAIN/health" > /dev/null; then log_success "Система полностью функциональна: https://$DOMAIN" else log_warning "Система запущена, но требует времени для полной готовности" log_info "Проверьте статус через несколько минут: https://$DOMAIN/health" fi echo -e "${GREEN}🚀 Добро пожаловать в MY Network!${NC}"