name: Deploy Mnemo Cards on: workflow_dispatch: push: branches: - master paths: - 'mnemo_cards_web_v2/**' - 'mnemo_cards_admin/**' - 'mnemo_cards_backend/**' - 'mnemo_cards_common/**' - 'mnemo_cards_common_backend/**' jobs: deploy-backend: name: Deploy Backend runs-on: ubuntu-latest steps: - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Checkout code uses: actions/checkout@v3 - name: Install Dependencies run: | apt-get update && apt-get install -y rsync openssh-client - name: Setup SSH run: | echo "🔍 Debugging SSH connection..." echo "Target host: ${{ secrets.SSH_HOST }}" ping -c 3 ${{ secrets.SSH_HOST }} || echo "⚠️ Ping failed" nslookup ${{ secrets.SSH_HOST }} || echo "⚠️ DNS lookup failed" nc -zv ${{ secrets.SSH_HOST }} 22 || echo "⚠️ Port 22 not reachable" mkdir -p ~/.ssh echo "${{ secrets.SSH_KEY }}" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa ssh-keyscan -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts 2>/dev/null || echo "⚠️ SSH keyscan failed" - name: Sync Source Code run: | # Sync common packages rsync -avz --delete --exclude '.*' --exclude 'build' --exclude 'doc' \ mnemo_cards_common \ mnemo_cards_common_backend \ ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:~/ # Sync backend project rsync -avz --delete --exclude '.*' --exclude 'build' --exclude 'server.exe' --exclude 'isar' \ mnemo_cards_backend \ ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:~/ # Sync deploy tools rsync -avz --delete tools/deploy \ ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:~/mnemo_cards/tools/ - name: Setup SSL Certificates run: | ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -o ConnectTimeout=30 -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'ENDSSH' set -e echo "🔐 Setting up SSL certificates for all domains..." # Ensure SSL setup script exists and is executable if [ -f "/root/mnemo_cards/tools/ssl/setup_ssl.sh" ]; then chmod +x /root/mnemo_cards/tools/ssl/setup_ssl.sh echo "🔄 Running SSL setup for all domains..." bash /root/mnemo_cards/tools/ssl/setup_ssl.sh echo "✅ SSL certificates setup completed" else echo "❌ SSL setup script not found at /root/mnemo_cards/tools/ssl/setup_ssl.sh" exit 1 fi ENDSSH - name: Get Dependencies run: | ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -o ConnectTimeout=30 -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'ENDSSH' set -e cd ~/mnemo_cards_backend echo "📦 Getting dependencies..." dart pub get ENDSSH - name: Compile Server run: | ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -o ConnectTimeout=30 -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'ENDSSH' set -e cd ~/mnemo_cards_backend echo "🔨 Compiling server..." dart compile exe --verbose lib/main.dart -o server_build.exe ENDSSH - name: Stop Service run: | ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -o ConnectTimeout=30 -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'ENDSSH' set -e echo "🛑 Stopping backend service..." sudo systemctl stop mnemo_cards_server || true echo "✅ Backend service stopped" echo "🔍 Checking nginx status after stopping backend..." if sudo systemctl is-active --quiet nginx; then echo "✅ nginx still running" else echo "🚨 nginx also stopped! This is the problem!" echo "🚀 Starting nginx..." sudo systemctl start nginx sleep 2 if sudo systemctl is-active --quiet nginx; then echo "✅ nginx restarted" else echo "❌ Failed to restart nginx!" exit 1 fi fi ENDSSH - name: Update Service Configuration run: | ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -o ConnectTimeout=30 -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'ENDSSH' set -e cd ~/mnemo_cards_backend echo "⚙️ Updating service configuration..." sudo chmod 777 mnemo_cards_server.service sudo cp mnemo_cards_server.service /etc/systemd/system/ ENDSSH - name: Update Executable run: | ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -o ConnectTimeout=30 -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'ENDSSH' set -e cd ~/mnemo_cards_backend echo "🔄 Replacing executable..." sudo cp server_build.exe server.exe rm server_build.exe ENDSSH - name: Configure Certificates run: | ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -o ConnectTimeout=30 -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'ENDSSH' set -e # Check certificates and configure mode # Используем multi-domain сертификат mnemo-cards.online (если есть) if [ -d "/etc/letsencrypt/live/mnemo-cards.online" ] && [ -f "/etc/letsencrypt/live/mnemo-cards.online/fullchain.pem" ]; then echo "✅ Let's Encrypt multi-domain сертификат найден. Настраиваем HTTPS режим..." sudo sed -i 's|ExecStart=/root/mnemo_cards_backend/server.exe.*|ExecStart=/root/mnemo_cards_backend/server.exe --certs /etc/letsencrypt/live/mnemo-cards.online -a 0.0.0.0 -p 8081|' /etc/systemd/system/mnemo_cards_server.service elif [ -d "/etc/letsencrypt/live/api.mnemo-cards.online" ]; then echo "✅ Let's Encrypt сертификат для API найден. Настраиваем dual mode..." sudo sed -i 's|ExecStart=/root/mnemo_cards_backend/server.exe.*|ExecStart=/root/mnemo_cards_backend/server.exe --dual --certs /etc/letsencrypt/live/api.mnemo-cards.online -a 0.0.0.0 -p 8081|' /etc/systemd/system/mnemo_cards_server.service else echo "⚠️ No certificates found. Configuring HTTP mode..." sudo sed -i 's|ExecStart=/root/mnemo_cards_backend/server.exe.*|ExecStart=/root/mnemo_cards_backend/server.exe -a 0.0.0.0 -p 8081|' /etc/systemd/system/mnemo_cards_server.service fi ENDSSH - name: Restart Service run: | ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -o ConnectTimeout=30 -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'ENDSSH' set -e echo "🚀 Restarting service..." sudo systemctl daemon-reload sudo systemctl start mnemo_cards_server sleep 2 sudo systemctl status mnemo_cards_server --no-pager --lines=5 || echo "Could not get status" ENDSSH - name: Generate and Deploy Nginx Configs run: | ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -o ConnectTimeout=30 -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'ENDSSH' set -e echo "🔧 Generating nginx configurations..." cd ~/mnemo_cards/tools/deploy ./generate-nginx-configs.sh echo "🧹 Checking for potential conflicts..." # Check if nginx.conf includes generated_configs directly (this would cause duplication) if grep -q "generated_configs" /etc/nginx/nginx.conf; then echo "⚠️ WARNING: nginx.conf includes generated_configs directly!" echo "This may cause server_name conflicts. Please remove the include line:" grep -n "generated_configs" /etc/nginx/nginx.conf echo "For now, proceeding with sites-enabled approach..." fi # Check for existing conflicting server blocks echo "📊 Checking for existing server_name conflicts..." for domain in "mnemo-cards.online" "code.mnemo-cards.online" "vscode.mnemo-cards.online"; do if grep -r "server_name $domain" /etc/nginx/sites-enabled/ 2>/dev/null | grep -v "$domain.conf:"; then echo "⚠️ Found conflicting server_name $domain in other files:" grep -r "server_name $domain" /etc/nginx/sites-enabled/ 2>/dev/null fi done echo "🧹 Cleaning up old configuration files..." # Remove old files without .conf extension that might cause conflicts rm -f /etc/nginx/sites-available/forgejo rm -f /etc/nginx/sites-available/vscode rm -f /etc/nginx/sites-available/vscode.mnemo-cards.online rm -f /etc/nginx/sites-available/mnemo_cards rm -f /etc/nginx/sites-available/mnemo_cards_main # Remove any existing .conf files that we're about to replace rm -f /etc/nginx/sites-enabled/vscode.mnemo-cards.online.conf rm -f /etc/nginx/sites-enabled/code.mnemo-cards.online.conf rm -f /etc/nginx/sites-enabled/mnemo-cards.online.conf rm -f /etc/nginx/sites-available/vscode.mnemo-cards.online.conf rm -f /etc/nginx/sites-available/code.mnemo-cards.online.conf rm -f /etc/nginx/sites-available/mnemo-cards.online.conf echo "📋 Deploying new configurations..." cp generated_configs/*.conf /etc/nginx/sites-available/ echo "🔗 Creating symbolic links..." ln -sf /etc/nginx/sites-available/mnemo-cards.online.conf /etc/nginx/sites-enabled/ ln -sf /etc/nginx/sites-available/code.mnemo-cards.online.conf /etc/nginx/sites-enabled/ ln -sf /etc/nginx/sites-available/vscode.mnemo-cards.online.conf /etc/nginx/sites-enabled/ echo "📊 Testing nginx configuration..." if /usr/sbin/nginx -t; then echo "✅ Configuration is valid" echo "🔄 Reloading nginx..." systemctl reload nginx echo "✅ nginx reloaded successfully" else echo "❌ Configuration test failed!" echo "🔍 Debugging configuration errors..." /usr/sbin/nginx -t 2>&1 || true # Try to identify the problematic file echo "🔍 Checking individual site configs..." for config in /etc/nginx/sites-enabled/*.conf; do echo "Testing $(basename "$config")..." if ! /usr/sbin/nginx -t -c /etc/nginx/nginx.conf -g "include $config;" 2>/dev/null; then echo "❌ Error in $(basename "$config")" head -20 "$config" fi done exit 1 fi echo "🔍 Running final checks..." # Check nginx service status if systemctl is-active --quiet nginx; then echo "✅ nginx service is running" else echo "❌ nginx service is not running!" systemctl status nginx --no-pager || true exit 1 fi # Test site accessibility echo "🌐 Testing site accessibility..." if curl -I --max-time 5 https://mnemo-cards.online/ 2>/dev/null | grep -q "200\|301\|302"; then echo "✅ mnemo-cards.online is accessible" else echo "⚠️ mnemo-cards.online not responding" fi if curl -I --max-time 5 https://code.mnemo-cards.online/ 2>/dev/null | grep -q "200\|301\|302"; then echo "✅ code.mnemo-cards.online is accessible" else echo "⚠️ code.mnemo-cards.online not responding" fi if curl -I --max-time 5 https://vscode.mnemo-cards.online/ 2>/dev/null | grep -q "200\|301\|302"; then echo "✅ vscode.mnemo-cards.online is accessible" else echo "⚠️ vscode.mnemo-cards.online not responding" fi echo "✅ Nginx configuration deployment completed successfully!" ENDSSH deploy-web: name: Deploy Web App runs-on: ubuntu-latest container: image: ghcr.io/cirruslabs/flutter:3.35.5 options: --memory=2048m --memory-swap=4096m needs: deploy-backend if: always() && needs.deploy-backend.result == 'success' steps: - name: Install System Dependencies run: | apt-get update && apt-get install -y rsync openssh-client jq git curl wget gnupg2 software-properties-common ca-certificates - name: Setup Node.js run: | # Install Node.js manually in container curl -fsSL https://deb.nodesource.com/setup_20.x | bash - apt-get install -y nodejs echo "Node.js version: $(node --version)" echo "NPM version: $(npm --version)" # Set Node.js memory limits for increased container memory (512MB) echo "NODE_OPTIONS=--max-old-space-size=512" >> $GITHUB_ENV || echo "NODE_OPTIONS=--max-old-space-size=512" >> ~/.bashrc || true - name: Configure Git run: | git config --global http.postBuffer 524288000 git config --global http.maxRequestBuffer 500M git config --global core.compression 0 git config --global http.lowSpeedLimit 1000 git config --global http.lowSpeedTime 60 - name: Setup SSH run: | mkdir -p ~/.ssh echo "${{ secrets.SSH_KEY }}" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa ssh-keyscan -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts - name: Checkout code uses: actions/checkout@v3 with: fetch-depth: 1 lfs: false - name: Bump Version (Pre-hook) run: | echo "🔄 Running pre-deploy version bump..." ./tools/deploy/bump-version.sh - name: Push Version Bump run: | echo "📤 Pushing version bump to remote..." git push echo "✅ Version bump pushed" - name: Build Web App working-directory: mnemo_cards_web_v2 env: # Memory optimization for increased container limits DART_VM_OPTIONS: "--old-gen-heap-size=1024 --max-old-space-size=1024 --gc-on-threshold --low-memory-mode --enable-isolate-groups --use-slow-path" # Minimal Node.js memory NODE_OPTIONS: "--max-old-space-size=256" # Limit parallel compilation to reduce memory pressure FLUTTER_BUILD_PARALLEL: "1" # Disable analytics to save memory FLUTTER_ANALYTICS_DISABLED: "true" # Reduce GC pressure DART_FLAGS: "--disable-dart-dev --no-background-compilation" # Additional memory optimization FLUTTER_WEB_USE_SKIA: "false" # Disable web security for faster builds FLUTTER_WEB_DISABLE_SECURITY: "true" run: | echo "🔍 Проверяем Flutter..." which flutter || echo "Flutter not found in PATH" flutter --version || echo "Flutter command failed" echo "📊 Текущее состояние памяти:" free -h || true echo "🧹 Очищаем кэш и временные файлы для экономии памяти..." flutter clean || true # Clear additional caches rm -rf ~/.pub-cache/hosted/pub.dev/.cache || true rm -rf ~/.dartServer || true rm -rf ~/.flutter-devtools || true rm -rf ~/.flutter/bin/cache/dart-sdk/bin/snapshots/*.snapshot || true rm -rf /tmp/dart* || true rm -rf /tmp/flutter* || true rm -rf .dart_tool/cache || true # Drop caches to free memory (if available) echo 3 > /proc/sys/vm/drop_caches 2>/dev/null || true # Kill any lingering Dart/Flutter processes pkill -f dart || true pkill -f flutter || true sleep 2 # Sync memory to disk to free up RAM sync || true echo "📦 Получаем зависимости..." timeout 300 flutter pub get || (echo "❌ Flutter pub get failed" && exit 1) # Free memory after pub get echo 3 > /proc/sys/vm/drop_caches 2>/dev/null || true sync || true # Final memory cleanup before build echo "🧹 Финальная очистка памяти перед сборкой..." echo 3 > /proc/sys/vm/drop_caches 2>/dev/null || true sync || true sleep 2 echo "📊 Память перед сборкой:" free -h || true # Use HTML renderer instead of CanvasKit for better memory efficiency export FLUTTER_WEB_USE_SKIA=false echo "🔨 Собираем веб-приложение (оптимизировано для 2GB памяти)..." # Try multiple build modes from least to most memory intensive echo "🔄 Пробуем разные режимы сборки по возрастанию сложности..." # First try debug mode (least memory intensive) echo "🐛 Попытка 1: Debug mode..." if timeout 1800 flutter build web --debug \ --dart-define=API_BASE_URL=https://api.mnemo-cards.online \ --no-tree-shake-icons \ --no-pub \ --suppress-analytics; then echo "✅ Debug сборка успешна!" else echo "⚠️ Debug провалился, попытка 2: Profile mode..." # Try profile mode if timeout 2400 flutter build web --profile \ --dart-define=API_BASE_URL=https://api.mnemo-cards.online \ --no-tree-shake-icons \ --no-pub \ --suppress-analytics; then echo "✅ Profile сборка успешна!" else echo "❌ Все режимы сборки провалились!" exit 1 fi fi echo "✅ Сборка завершена" echo "📊 Финальное состояние памяти:" free -h || true - name: Deploy Web App run: | echo "📦 Копируем веб-приложение..." timeout 120 rsync -avz --delete mnemo_cards_web_v2/build/web/ \ ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:/var/www/mnemo_cards/ || (echo "❌ Rsync failed" && exit 1) echo "✅ Веб-приложение скопировано" - name: Fix Permissions and Reload Nginx run: | ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -o ConnectTimeout=30 -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'ENDSSH' set -e echo "🔧 Setting correct permissions for web files..." sudo chown -R www-data:www-data /var/www/mnemo_cards sudo chmod -R 755 /var/www/mnemo_cards echo "✅ Permissions fixed" echo "🔄 Reloading nginx to serve new web app..." if sudo nginx -t 2>&1; then echo "✅ nginx configuration is valid" sudo systemctl reload nginx echo "✅ nginx reloaded successfully" # Basic verification sleep 2 if sudo systemctl is-active --quiet nginx; then echo "✅ nginx is running" else echo "❌ nginx failed to reload" sudo systemctl status nginx --no-pager || true exit 1 fi echo "✅ Web app deployment completed" else echo "❌ nginx configuration test failed!" sudo nginx -t || true exit 1 fi ENDSSH final-verification: name: Final Verification runs-on: ubuntu-latest needs: [deploy-backend, deploy-web] if: always() steps: - name: Setup SSH run: | mkdir -p ~/.ssh echo "${{ secrets.SSH_KEY }}" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa ssh-keyscan -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts - name: Wait and Verify All Services run: | echo "⏳ Ждем завершения всех операций..." sleep 10 echo "🔍 Финальная проверка доступности всех сайтов..." ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -o ConnectTimeout=30 -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} << 'ENDSSH' set -e echo "📊 Статус всех сервисов:" # Проверяем nginx if sudo systemctl is-active --quiet nginx; then echo "✅ nginx: работает" else echo "❌ nginx: НЕ работает!" sudo systemctl status nginx --no-pager || true fi # Проверяем backend if sudo systemctl is-active --quiet mnemo_cards_server; then echo "✅ backend: работает" else echo "❌ backend: НЕ работает!" sudo systemctl status mnemo_cards_server --no-pager --lines=3 2>/dev/null || echo "Could not get backend status" fi echo "" echo "🔐 Проверяем SSL сертификаты:" # Run SSL check script if it exists if [ -f "/root/mnemo_cards/tools/ssl/check_ssl.sh" ]; then bash /root/mnemo_cards/tools/ssl/check_ssl.sh | head -20 else echo "SSL check script not found" fi echo "" echo "🌐 Тестируем доступность сайтов:" # Тестируем все сайты sites=("https://mnemo-cards.online/" "https://admin.mnemo-cards.online/" "https://api.mnemo-cards.online/" "https://code.mnemo-cards.online/" "https://vscode.mnemo-cards.online/") for site in "${sites[@]}"; do if curl -I --max-time 10 "$site" 2>/dev/null | grep -q "200\|301\|302"; then echo "✅ $site доступен" else echo "❌ $site НЕДОСТУПЕН!" curl -I --max-time 5 "$site" || true fi done echo "" echo "🎉 Проверка завершена!" ENDSSH