#!/bin/bash set -e # Exit immediately if a command exits with a non-zero status. echo "--- Script Start ---" echo "Running as user: $(whoami) (UID: $(id -u), GID: $(id -g))" # ... (rest of initial echos and directory setup remains the same) ... # --- Persistent Data Setup --- N8N_DATA_DIR="/data/.n8n" POSTGRES_DATA_DIR="/data/postgres" # Should be owned by n8nuser (UID 1000) QDRANT_DATA_DIR="/data/qdrant_storage" # Should be owned by n8nuser OLLAMA_MODELS_DIR="/data/.ollama" # Should be owned by n8nuser echo "Ensuring application data directories exist..." mkdir -p "$N8N_DATA_DIR" "$POSTGRES_DATA_DIR" "$QDRANT_DATA_DIR" "$OLLAMA_MODELS_DIR" echo "Permissions of data directories in /data (should be owned by $(whoami)):" ls -ld "$N8N_DATA_DIR" "$POSTGRES_DATA_DIR" "$QDRANT_DATA_DIR" "$OLLAMA_MODELS_DIR" ln -sfn "$N8N_DATA_DIR" /home/n8nuser/.n8n export OLLAMA_MODELS="$OLLAMA_MODELS_DIR" # --- PostgreSQL Setup & Start (as n8nuser) --- echo "--- PostgreSQL Setup (running as $(whoami)) ---" echo "PGDATA is set to: $POSTGRES_DATA_DIR" POSTGRES_PORT="${DB_POSTGRESDB_PORT:-5432}" # Define port for consistency # Ensure n8nuser has rwx permissions on its own PGDATA. chmod u+rwx "$POSTGRES_DATA_DIR" if [ ! -d "$POSTGRES_DATA_DIR/base" ]; then echo "Initializing PostgreSQL database in $POSTGRES_DATA_DIR as user $(whoami)..." /usr/lib/postgresql/14/bin/initdb -D "$POSTGRES_DATA_DIR" --username=$(whoami) --no-locale --encoding=UTF8 if [ $? -ne 0 ]; then echo "ERROR: PostgreSQL initdb failed."; ls -ld "$POSTGRES_DATA_DIR"; exit 1; fi echo "PostgreSQL Initialized. Ownership/permissions of $POSTGRES_DATA_DIR after initdb:" ls -ld "$POSTGRES_DATA_DIR" echo "Temporarily starting PostgreSQL to create database role and database..." # For pg_ctl, it's good practice to point to the PGDATA explicitly. # pg_ctl will find postgresql.conf within PGDATA. /usr/lib/postgresql/14/bin/pg_ctl -D "$POSTGRES_DATA_DIR" -o "-p $POSTGRES_PORT -c listen_addresses='localhost'" -w start PG_ROLE_NAME="${DB_POSTGRESDB_USER:-n8n}" PG_PASSWORD="${DB_POSTGRESDB_PASSWORD}" PG_DB_NAME="${DB_POSTGRESDB_DATABASE:-n8n}" if [ -z "$PG_PASSWORD" ]; then echo "ERROR: DB_POSTGRESDB_PASSWORD is not set."; exit 1; fi echo "Creating PostgreSQL role '$PG_ROLE_NAME' and database '$PG_DB_NAME'..." psql -v ON_ERROR_STOP=1 --username=$(whoami) --port="$POSTGRES_PORT" --host=localhost postgres <<-EOSQL CREATE ROLE "$PG_ROLE_NAME" WITH LOGIN PASSWORD '$PG_PASSWORD'; CREATE DATABASE "$PG_DB_NAME" OWNER "$PG_ROLE_NAME"; EOSQL echo "PostgreSQL role and database created." /usr/lib/postgresql/14/bin/pg_ctl -D "$POSTGRES_DATA_DIR" -m fast -w stop echo "Temporary PostgreSQL server stopped." else echo "PostgreSQL database found in $POSTGRES_DATA_DIR." fi echo "Starting PostgreSQL server for application use (as $(whoami))..." # The postgres command will use the postgresql.conf found within $POSTGRES_DATA_DIR # We don't need to specify -c config_file if it's inside PGDATA. # Just ensure the port is correctly passed if not default. /usr/lib/postgresql/14/bin/postgres -D "$POSTGRES_DATA_DIR" -p "$POSTGRES_PORT" & PG_PID=$! echo "Waiting for PostgreSQL to start (PID: $PG_PID)..." max_wait=30 count=0 until pg_isready -h localhost -p "$POSTGRES_PORT" -U $(whoami) -q || [ $count -eq $max_wait ]; do echo -n "." sleep 1 count=$((count+1)) done if [ $count -eq $max_wait ]; then echo "ERROR: PostgreSQL timed out waiting to start." PG_LOG_DIR_GUESS="$POSTGRES_DATA_DIR/log" if [ -d "$PG_LOG_DIR_GUESS" ]; then echo "PostgreSQL logs from $PG_LOG_DIR_GUESS:" # List log files before cat'ing, and cat only the latest ones if possible or just one ls -lt "$PG_LOG_DIR_GUESS" cat "$PG_LOG_DIR_GUESS"/postgresql-*.log 2>/dev/null || echo "No standard log files found or readable." else echo "$PG_LOG_DIR_GUESS not found." fi exit 1 fi echo "PostgreSQL started successfully on port $POSTGRES_PORT." # --- Qdrant Setup & Start (as n8nuser) --- # (This section remains the same) echo "--- Qdrant Setup (running as $(whoami)) ---" QDRANT_CONFIG_DIR="/qdrant/config" QDRANT_STORAGE_PATH_IN_CONFIG="/qdrant/storage" ln -sfn "$QDRANT_DATA_DIR" "$QDRANT_STORAGE_PATH_IN_CONFIG" echo "Starting Qdrant..." /usr/local/bin/qdrant --config-path "$QDRANT_CONFIG_DIR/config.yaml" & QDRANT_PID=$! echo "Waiting for Qdrant to start (PID: $QDRANT_PID)..." until curl -sf http://localhost:6333/readyz > /dev/null; do echo -n "." sleep 1 if ! ps -p $QDRANT_PID > /dev/null; then echo "Qdrant process died."; exit 1; fi done echo "Qdrant started." # --- Ollama Start (as n8nuser) --- # (This section remains the same) echo "--- Ollama Setup (running as $(whoami)) ---" echo "Ollama models will be stored in: $OLLAMA_MODELS_DIR" echo "Starting Ollama server..." ollama serve & OLLAMA_PID=$! echo "Waiting for Ollama to start (PID: $OLLAMA_PID)..." until curl -sf http://localhost:11434/api/tags > /dev/null 2>&1 ; do echo -n "." sleep 1 if ! ps -p $OLLAMA_PID > /dev/null; then echo "Ollama process died."; exit 1; fi done echo "Ollama started." DEFAULT_MODEL="${DEFAULT_OLLAMA_MODEL:-llama3.2}" echo "Checking for default Ollama model: $DEFAULT_MODEL" if ! ollama show "$DEFAULT_MODEL" > /dev/null 2>&1; then echo "Pulling $DEFAULT_MODEL... This may take a while." ollama pull "$DEFAULT_MODEL" if [ $? -ne 0 ]; then echo "Warning: Failed to pull $DEFAULT_MODEL"; else echo "$DEFAULT_MODEL pulled."; fi else echo "$DEFAULT_MODEL already present." fi # --- n8n Start (as n8nuser) --- echo "--- n8n Setup (running as $(whoami)) ---" if [ -z "$N8N_ENCRYPTION_KEY" ]; then echo "ERROR: N8N_ENCRYPTION_KEY is not set. Please set it as a Space secret." exit 1 fi if [ -z "$DB_POSTGRESDB_PASSWORD" ]; then echo "ERROR: DB_POSTGRESDB_PASSWORD is not set. Please set it as a Space secret." exit 1 fi export N8N_USER_FOLDER="/home/n8nuser/.n8n" export GENAI_MODELS_N8N_DEFAULT_MODEL="$DEFAULT_MODEL" export DB_POSTGRESDB_PORT="$POSTGRES_PORT" # --- MOST PERMISSIVE EMBEDDING CONFIGURATION FOR DIAGNOSIS --- echo "WARNING: USING HIGHLY PERMISSIVE (INSECURE) EMBEDDING SETTINGS FOR DIAGNOSIS!" export N8N_SEC_EMBEDDER_HEADER_MODE="allowAll" # The mode "allowAll" should theoretically make n8n send headers that allow embedding from anywhere. # This is a simpler way to test than just relying on the regex if there's any doubt. # If "allowAll" doesn't work, then N8N_SEC_EMBEDDER_HEADER_ALLOW_FROM_REGEX=".*" is the next most forceful. # We'll also set the regex to ".*" just in case "allowAll" isn't picked up or is deprecated. export N8N_SEC_EMBEDDER_HEADER_ALLOW_FROM_REGEX=".*" # --- End Embedding Configuration --- export N8N_SEC_ALLOW_ALL_ORIGINS_FOR_WEBHOOKS="true" export N8N_RUNNERS_ENABLED="true" # As per n8n deprecation warning # Ensure URLs are set, as this can sometimes affect header generation or self-referencing if [ -n "$SPACE_HOST" ]; then # Assuming SPACE_HOST is like 'username-spacename.hf.space' DERIVED_URL="https://$SPACE_HOST/" export N8N_EDITOR_BASE_URL="$DERIVED_URL" export WEBHOOK_URL="$DERIVED_URL" echo "N8N URLs derived from SPACE_HOST: $N8N_EDITOR_BASE_URL" elif [ -n "$HF_SPACE_PUBLIC_URL" ]; then # Another possible HF env var export N8N_EDITOR_BASE_URL="$HF_SPACE_PUBLIC_URL" export WEBHOOK_URL="$HF_SPACE_PUBLIC_URL" echo "N8N URLs set from HF_SPACE_PUBLIC_URL: $N8N_EDITOR_BASE_URL" else FALLBACK_URL="http://localhost:${N8N_PORT:-5678}/" export N8N_EDITOR_BASE_URL="$FALLBACK_URL" export WEBHOOK_URL="$FALLBACK_URL" echo "Warning: Specific Hugging Face URL environment variables not found. Using fallback: $FALLBACK_URL" fi # Optional: Increase n8n log level for more startup details # export N8N_LOG_LEVEL="debug" export N8N_PROXY_HOPS=1 echo "Starting n8n with highly permissive (INSECURE) embedding rules for diagnosis..." exec n8n start