#!/bin/sh # entrypoint.sh — single-container HF Space bootstrap (Alpine) set -eu log() { echo "[entrypoint] $*"; } warn() { echo "[entrypoint][WARN] $*" >&2; } err() { echo "[entrypoint][ERROR] $*" >&2; } # Load .env if present (local dev); HF Space Secrets come as env already if [ -f /app/.env ]; then log "Loading /app/.env" set -a; . /app/.env; set +a fi if [ -f .env ]; then log "Loading ./.env" set -a; . ./.env; set +a fi # Defaults — HF expects 7860 export N8N_PORT=${N8N_PORT:-7860} export N8N_LISTEN_ADDRESS=${N8N_LISTEN_ADDRESS:-0.0.0.0} export N8N_PORT N8N_LISTEN_ADDRESS export DB_TYPE=${DB_TYPE:-postgresdb} export DB_POSTGRESDB_HOST=${DB_POSTGRESDB_HOST:-127.0.0.1} export DB_POSTGRESDB_PORT=${DB_POSTGRESDB_PORT:-5432} export DB_POSTGRESDB_DATABASE=${DB_POSTGRESDB_DATABASE:-n8n} export DB_POSTGRESDB_USER=${DB_POSTGRESDB_USER:-n8n} export PGDATA=${PGDATA:-/data/postgres} export N8N_USER_FOLDER=${N8N_USER_FOLDER:-/data/n8n} export N8N_RUNNERS_ENABLED=${N8N_RUNNERS_ENABLED:-true} export N8N_RUNNERS_MODE=${N8N_RUNNERS_MODE:-external} export N8N_RUNNERS_BROKER_PORT=${N8N_RUNNERS_BROKER_PORT:-5679} export N8N_RUNNERS_BROKER_LISTEN_ADDRESS=${N8N_RUNNERS_BROKER_LISTEN_ADDRESS:-0.0.0.0} export N8N_RUNNERS_TASK_BROKER_URI=${N8N_RUNNERS_TASK_BROKER_URI:-http://127.0.0.1:5679} export N8N_RUNNERS_AUTH_TOKEN=${N8N_RUNNERS_AUTH_TOKEN:-} export N8N_RUNNERS_TASK_TIMEOUT=${N8N_RUNNERS_TASK_TIMEOUT:-300} export N8N_INSTANCE_AI_SANDBOX_ENABLED=${N8N_INSTANCE_AI_SANDBOX_ENABLED:-true} export N8N_INSTANCE_AI_SANDBOX_PROVIDER=${N8N_INSTANCE_AI_SANDBOX_PROVIDER:-n8n-sandbox} export N8N_SANDBOX_SERVICE_URL=${N8N_SANDBOX_SERVICE_URL:-http://127.0.0.1:8080} export GENERIC_TIMEZONE=${GENERIC_TIMEZONE:-Asia/Kolkata} # Secrets persistence: /data/.env.secrets (survives bucket mount, else ephemeral) SECRETS_FILE="/data/.env.secrets" mkdir -p /data/postgres /data/n8n /data/sandbox /var/log/supervisor /var/run/postgresql 2>/dev/null || true chmod 777 /data 2>/dev/null || true chown postgres:postgres /var/run/postgresql 2>/dev/null || true gen_secret() { cat /dev/urandom 2>/dev/null | tr -dc 'a-f0-9' | head -c 64 || openssl rand -hex 32 2>/dev/null || head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \n' | head -c 64; } if [ ! -f "$SECRETS_FILE" ]; then log "Generating $SECRETS_FILE" { echo "# auto-generated $(date -u) — persists on /data bucket, else ephemeral" echo "N8N_ENCRYPTION_KEY=$(gen_secret)" echo "DB_POSTGRESDB_PASSWORD=$(gen_secret | cut -c1-32)" echo "N8N_RUNNERS_AUTH_TOKEN=$(gen_secret)" echo "N8N_USER_MANAGEMENT_JWT_SECRET=$(gen_secret)" echo "SANDBOX_API_KEYS=$(gen_secret | cut -c1-32)" } > "$SECRETS_FILE" chmod 600 "$SECRETS_FILE" fi # Load secrets file, but do not override already-exported env (HF Secrets win) set -a # shellcheck disable=SC1090 while IFS='=' read -r k v; do case "$k" in \#*|"") continue;; esac # only set if not already set if eval "[ -z \"\${$k:-}\" ]"; then # strip possible quotes v=$(printf "%s" "$v" | sed "s/^['\"]//;s/['\"]$//") export "$k=$v" fi done < "$SECRETS_FILE" set +a # Export DB password from file if not set if [ -z "${DB_POSTGRESDB_PASSWORD:-}" ]; then DB_POSTGRESDB_PASSWORD=$(grep '^DB_POSTGRESDB_PASSWORD=' "$SECRETS_FILE" | cut -d= -f2-) export DB_POSTGRESDB_PASSWORD fi if [ -z "${N8N_ENCRYPTION_KEY:-}" ]; then N8N_ENCRYPTION_KEY=$(grep '^N8N_ENCRYPTION_KEY=' "$SECRETS_FILE" | cut -d= -f2-) export N8N_ENCRYPTION_KEY fi if [ -z "${SANDBOX_API_KEYS:-}" ]; then SANDBOX_API_KEYS=$(grep '^SANDBOX_API_KEYS=' "$SECRETS_FILE" | cut -d= -f2-) export SANDBOX_API_KEYS fi export N8N_SANDBOX_SERVICE_API_KEY=${N8N_SANDBOX_SERVICE_API_KEY:-$SANDBOX_API_KEYS} export SANDBOX_API_KEYS N8N_SANDBOX_SERVICE_API_KEY # Also persist PGDATA ownership (fast, avoid chown -R on large /opt/runners) chown postgres:postgres "$PGDATA" 2>/dev/null || true chown node:node /home/node 2>/dev/null || true chown runner:runner /home/runner 2>/dev/null || true mkdir -p /data/n8n && chown node:node /data/n8n 2>/dev/null || true # Init postgres if needed (only if POSTGRES_ENABLED != false and PG_VERSION missing) if [ "${POSTGRES_ENABLED:-true}" != "false" ] && [ ! -f "$PGDATA/PG_VERSION" ]; then log "Initializing postgres PGDATA=$PGDATA" # ensure directory owned chown postgres:postgres "$PGDATA" # initdb as postgres user via su-exec su-exec postgres initdb -D "$PGDATA" -U postgres --no-locale --encoding=UTF8 2>&1 | tail -20 # allow md5 + trust for local cat >> "$PGDATA/pg_hba.conf" <> "$PGDATA/postgresql.conf" </dev/null || true chown node:node "$N8N_USER_FOLDER" 2>/dev/null || true # Export all for supervisord child processes (supervisord inherits env) export N8N_PORT N8N_LISTEN_ADDRESS DB_TYPE DB_POSTGRESDB_HOST DB_POSTGRESDB_PORT DB_POSTGRESDB_DATABASE DB_POSTGRESDB_USER DB_POSTGRESDB_PASSWORD export PGDATA N8N_USER_FOLDER N8N_ENCRYPTION_KEY N8N_RUNNERS_ENABLED N8N_RUNNERS_MODE N8N_RUNNERS_TASK_BROKER_URI N8N_RUNNERS_BROKER_PORT N8N_RUNNERS_BROKER_LISTEN_ADDRESS N8N_RUNNERS_AUTH_TOKEN N8N_RUNNERS_TASK_TIMEOUT export N8N_INSTANCE_AI_SANDBOX_ENABLED N8N_INSTANCE_AI_SANDBOX_PROVIDER N8N_SANDBOX_SERVICE_URL N8N_SANDBOX_SERVICE_API_KEY SANDBOX_API_KEYS export GENERIC_TIMEZONE log "Starting supervisord" exec /usr/bin/supervisord -c /etc/supervisor/supervisord.conf