#!/bin/bash echo "🚀 Starting Dify All-in-One..." set -x cd /app/api # 1. Database Migration (with timeout) echo "🗄️ Database migration..." echo "📊 DB_TYPE=${DB_TYPE:-'not set'}" echo "📊 DB_HOST=${DB_HOST:-'not set'}" echo "📊 SQLALCHEMY_DATABASE_URI is $([ -n \"$SQLALCHEMY_DATABASE_URI\" ] && echo 'SET' || echo 'NOT SET')" flask db upgrade 2>&1 || echo "⚠️ Migration failed or already done" echo "🗄️ Migration attempt complete" # 2. Start Nginx FIRST (port 7860) echo "🚦 Starting Nginx..." nginx # 3. Start API (port 5001) echo "🧠 Starting API..." # ULTIMATE FIX: Disable CSRF and patch cookies at app level cat << 'APPWRAPPER_EOF' > /app/api/app_wrapper.py """ Ultimate HF Spaces Fix: Disable CSRF validation entirely and patch cookie settings. CSRF isn't needed on HF Spaces because: 1. It's a single-user deployment 2. The proxy already handles some security 3. We need the app to work! """ import sys import os # Set environment variables BEFORE importing Flask app os.environ['WTF_CSRF_ENABLED'] = 'false' os.environ['CSRF_ENABLED'] = 'false' os.environ['WTF_CSRF_CHECK_DEFAULT'] = 'false' os.environ['SESSION_COOKIE_SAMESITE'] = 'None' os.environ['SESSION_COOKIE_SECURE'] = 'true' os.environ['CSRF_COOKIE_HTTPONLY'] = 'false' sys.stderr.write("🔧 CSRF DISABLE: Environment variables set\n") sys.stderr.flush() # Now import the Flask app from app import app as flask_app # Patch Flask config directly flask_app.config.update( WTF_CSRF_ENABLED=False, WTF_CSRF_CHECK_DEFAULT=False, CSRF_ENABLED=False, SESSION_COOKIE_SAMESITE='None', SESSION_COOKIE_SECURE=True, SESSION_COOKIE_HTTPONLY=True, CSRF_COOKIE_HTTPONLY=False, REMEMBER_COOKIE_SAMESITE='None', REMEMBER_COOKIE_SECURE=True, ) sys.stderr.write("🔧 CSRF DISABLE: Flask config patched\n") sys.stderr.flush() # Try to disable Flask-WTF CSRF if it exists try: from flask_wtf.csrf import CSRFProtect # Find and disable any CSRF protection instance for key in list(flask_app.extensions.keys()): if 'csrf' in key.lower(): sys.stderr.write(f"🔧 Found CSRF extension: {key}\n") # Disable CSRF for all views flask_app.config['WTF_CSRF_ENABLED'] = False sys.stderr.write("🔧 CSRF DISABLE: Flask-WTF disabled\n") except Exception as e: sys.stderr.write(f"⚠️ Flask-WTF not found or error: {e}\n") sys.stderr.flush() # Try to find and patch Flask-Login cookie settings try: if hasattr(flask_app, 'login_manager'): flask_app.login_manager.session_protection = None sys.stderr.write("🔧 Flask-Login: session_protection disabled\n") except Exception as e: sys.stderr.write(f"⚠️ Flask-Login patch error: {e}\n") sys.stderr.flush() # Cookie patching middleware for responses class CookieFixMiddleware: def __init__(self, app): self.app = app def __call__(self, environ, start_response): def custom_start_response(status, headers, exc_info=None): new_headers = [] for name, value in headers: if name.lower() == 'set-cookie': import re # Remove HttpOnly (so JS can read CSRF token) value = value.replace('; HttpOnly', '').replace(';HttpOnly', '') # Force SameSite=None value = re.sub(r'SameSite=\w+', 'SameSite=None', value) if 'SameSite=' not in value: value += '; SameSite=None' # Add Secure flag (required for SameSite=None) if '; Secure' not in value: value += '; Secure' # CRITICAL: __Host- prefix requires Path=/ if '__Host-' in value and 'Path=' not in value: value += '; Path=/' # Remove any Domain attribute (__Host- prefix requirement) value = re.sub(r'; Domain=[^;]+', '', value) sys.stderr.write(f"🍪 Cookie: {value[:80]}...\n") sys.stderr.flush() new_headers.append((name, value)) return start_response(status, new_headers, exc_info) return self.app(environ, custom_start_response) # Wrap the app app = CookieFixMiddleware(flask_app) sys.stderr.write("✅ APP WRAPPER READY: CSRF disabled + Cookie patching active!\n") sys.stderr.flush() APPWRAPPER_EOF echo "🔧 App wrapper with CSRF disable created!" # Run Gunicorn with the patched app gunicorn --bind 127.0.0.1:5001 --workers 1 --timeout 360 --forwarded-allow-ips='*' app_wrapper:app & API_PID=$! API_PID=$! # 4. Start Web (port 3000) with correct API URLs echo "🌐 Starting Web..." cd /app/web # Critical: Set environment export NODE_ENV=production export PORT=3000 export HOSTNAME=0.0.0.0 # API URLs export NEXT_PUBLIC_API_PREFIX=/console/api export NEXT_PUBLIC_PUBLIC_API_PREFIX=/api export NEXT_PUBLIC_SENTRY_DSN= export NEXT_TELEMETRY_DISABLED=1 # Edition and deploy env export NEXT_PUBLIC_EDITION=${NEXT_PUBLIC_EDITION:-"SELF_HOSTED"} export NEXT_PUBLIC_DEPLOY_ENV=${NEXT_PUBLIC_DEPLOY_ENV:-"PRODUCTION"} export EDITION=${NEXT_PUBLIC_EDITION} export DEPLOY_ENV=${NEXT_PUBLIC_DEPLOY_ENV} # Security / Cookies (Critical for HF Spaces) export SECRET_KEY=${SECRET_KEY:-"dify-secret-key-random-123456"} export SESSION_COOKIE_SAMESITE="None" export SESSION_COOKIE_SECURE="true" export COOKIE_HTTPONLY="false" export SESSION_COOKIE_HTTPONLY="true" export CSRF_COOKIE_HTTPONLY="false" export REMEMBER_COOKIE_SAMESITE="None" export REMEMBER_COOKIE_SECURE="true" export REMEMBER_COOKIE_HTTPONLY="true" export REFRESH_TOKEN_COOKIE_SAMESITE="None" export REFRESH_TOKEN_COOKIE_SECURE="true" export REFRESH_TOKEN_COOKIE_HTTPONLY="true" # Fix for invalid or missing user-agent in some environments export FLASK_RUN_EXTRA_FILES="" # Console URLs - must be set! export CONSOLE_API_URL=${CONSOLE_API_URL:-"https://pommsn-dify.hf.space"} export CONSOLE_WEB_URL=${CONSOLE_WEB_URL:-"https://pommsn-dify.hf.space"} export APP_API_URL=${APP_API_URL:-"https://pommsn-dify.hf.space"} export APP_WEB_URL=${APP_WEB_URL:-"https://pommsn-dify.hf.space"} export SERVICE_API_URL=${SERVICE_API_URL:-"https://pommsn-dify.hf.space"} # Server-side access to URLs (just in case) export NEXT_PUBLIC_API_URL=${CONSOLE_API_URL} # Fix for standalone mode (Required for 1.10.x and 1.11.x) export NEXT_SHARP_PATH=/app/web/node_modules/sharp export __NEXT_PRIVATE_STANDALONE_CONFIG=true # Ensure internal API URL is set for SSR export NEXT_PUBLIC_API_URL=${CONSOLE_API_URL} echo "📊 CONSOLE_API_URL=${CONSOLE_API_URL}" echo "📊 NODE_ENV=${NODE_ENV}" node server.js & WEB_PID=$! echo "✅ All services started!" wait