MicProtocol / deploy /start.sh
Benaah's picture
Upload deploy/start.sh with huggingface_hub
6093ec3 verified
Raw History Blame Contribute Delete
7.72 kB
#!/bin/sh
# ══════════════════════════════════════════════════════════════
# MicProtocol HF Space entrypoint β€” starts the full stack in one
# container, then runs nginx in the foreground on APP_PORT.
# ══════════════════════════════════════════════════════════════
set -e
APP_PORT="${APP_PORT:-7860}"
API_PORT="${API_PORT:-4000}"
WEB_PORT="${WEB_PORT:-3000}"
ADMIN_PORT="${ADMIN_PORT:-3006}"
MIC_REALTIME_PORT="${MIC_REALTIME_PORT:-4001}"
POSTGRES_PORT="${POSTGRES_PORT:-5432}"
REDIS_PORT="${REDIS_PORT:-6379}"
MEILISEARCH_PORT="${MEILISEARCH_PORT:-7700}"
# ─── Required secrets with stable fallbacks ────────────────────
: "${POSTGRES_USER:=micprotocol}"
: "${POSTGRES_PASSWORD:=micprotocol_secret}"
: "${POSTGRES_DB:=micprotocol}"
: "${REDIS_PASSWORD:=redis_secret}"
: "${MEILISEARCH_API_KEY:=masterKey}"
: "${COOKIE_SECRET:=$(openssl rand -hex 32)}"
: "${BETTER_AUTH_SECRET:=$(openssl rand -base64 32)}"
: "${MIC_REALTIME_INTERNAL_TOKEN:=$(openssl rand -hex 32)}"
: "${MIC_REALTIME_SHARED_SECRET:=$(openssl rand -hex 32)}"
export POSTGRES_USER POSTGRES_PASSWORD POSTGRES_DB
export REDIS_PASSWORD REDIS_HOST=localhost REDIS_PORT=$REDIS_PORT
export MEILISEARCH_API_KEY MEILISEARCH_HOST=http://localhost:$MEILISEARCH_PORT
export COOKIE_SECRET BETTER_AUTH_SECRET
export MIC_REALTIME_INTERNAL_TOKEN MIC_REALTIME_SHARED_SECRET
# Derived URLs
export DATABASE_URL="postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:${POSTGRES_PORT}/${POSTGRES_DB}?schema=public"
export REDIS_URL="redis://:${REDIS_PASSWORD}@localhost:${REDIS_PORT}"
export API_URL="http://localhost:${API_PORT}"
export WEB_URL="http://localhost:${WEB_PORT}"
export BETTER_AUTH_URL="http://localhost:${API_PORT}"
export MIC_REALTIME_URL="http://localhost:${MIC_REALTIME_PORT}"
export MIC_REALTIME_PUBLIC_URL="http://localhost:${MIC_REALTIME_PORT}"
export INTERNAL_API_TOKEN="${MIC_REALTIME_INTERNAL_TOKEN}"
export NODE_ENV="${NODE_ENV:-production}"
export DEV_AUTH_BYPASS_ENABLED="${DEV_AUTH_BYPASS_ENABLED:-true}"
# Public URLs the browser sees (overridable via HF space variables)
: "${NEXT_PUBLIC_API_URL:=http://localhost:${APP_PORT}/api}"
: "${NEXT_PUBLIC_MIC_REALTIME_URL:=ws://localhost:${APP_PORT}/ws}"
: "${NEXT_PUBLIC_ROOT_DOMAIN:=localhost}"
export NEXT_PUBLIC_API_URL NEXT_PUBLIC_MIC_REALTIME_URL NEXT_PUBLIC_ROOT_DOMAIN
log() { echo "[entrypoint] $*"; }
wait_for_port() {
local host="$1" port="$2" name="$3"
log "Waiting for $name at $host:$port ..."
for i in $(seq 1 60); do
if nc -z "$host" "$port" 2>/dev/null; then
log "$name is ready."
return 0
fi
sleep 0.5
done
log "WARNING: $name at $host:$port did not become ready."
}
# ─── 1. PostgreSQL ─────────────────────────────────────────────
log "Initialising PostgreSQL ..."
# Locate the postgres binary directory (Debian installs versioned dirs)
PG_BIN_DIR=$(ls -d /usr/lib/postgresql/*/bin 2>/dev/null | head -1)
if [ -z "$PG_BIN_DIR" ]; then
log "ERROR: postgres binaries not found"
exit 1
fi
PG_INITDB="$PG_BIN_DIR/initdb"
PG_CTL="$PG_BIN_DIR/pg_ctl"
PG_POSTGRES="$PG_BIN_DIR/postgres"
mkdir -p /var/lib/postgresql/data /var/run/postgresql /var/log
chown -R postgres:postgres /var/lib/postgresql/data /var/run/postgresql
chmod 700 /var/lib/postgresql/data
# Initialize data directory if empty
if [ -z "$(ls -A /var/lib/postgresql/data 2>/dev/null)" ]; then
su postgres -c "$PG_INITDB -D /var/lib/postgresql/data -U ${POSTGRES_USER} --auth=trust" >/var/log/initdb.log 2>&1 || true
fi
# Start postgres directly in the background (more reliable than pg_ctl in containers)
rm -f /tmp/.s.PGSQL.* /var/run/postgresql/.s.PGSQL.*
su postgres -c "$PG_POSTGRES -D /var/lib/postgresql/data -c listen_addresses=localhost -c port=${POSTGRES_PORT} -c unix_socket_directories=/var/run/postgresql" >/var/log/postgresql.log 2>&1 &
PG_PID=$!
# Wait for postgres to accept connections
for i in $(seq 1 30); do
if su postgres -c "$PG_CTL -D /var/lib/postgresql/data status" >/dev/null 2>&1; then
break
fi
if nc -z localhost "$POSTGRES_PORT" 2>/dev/null; then
break
fi
sleep 1
done
wait_for_port localhost "$POSTGRES_PORT" postgres
# Configure password + database (trust auth means any password works, but set it anyway)
su postgres -c "psql -tAc \"SELECT 1 FROM pg_database WHERE datname='${POSTGRES_DB}'\"" 2>/dev/null | grep -q 1 \
|| su postgres -c "createdb ${POSTGRES_DB}" 2>/dev/null || true
su postgres -c "psql -c \"ALTER USER ${POSTGRES_USER} WITH PASSWORD '${POSTGRES_PASSWORD}';\"" 2>/dev/null || true
# ─── 2. Redis ──────────────────────────────────────────────────
log "Starting Redis ..."
redis-server --daemonize yes --port "$REDIS_PORT" --requirepass "$REDIS_PASSWORD" >/dev/null 2>&1 || true
wait_for_port localhost "$REDIS_PORT" redis
# ─── 3. Meilisearch ────────────────────────────────────────────
log "Starting Meilisearch ..."
mkdir -p /app/meili_data
MEILISEARCH_MASTER_KEY="$MEILISEARCH_API_KEY" nohup meilisearch \
--http-addr "localhost:${MEILISEARCH_PORT}" \
--env production \
--data-path /app/meili_data \
--no-analytics >/var/log/meilisearch.log 2>&1 &
wait_for_port localhost "$MEILISEARCH_PORT" meilisearch
# ─── 4. Database schema (push, idempotent) ─────────────────────
log "Pushing Prisma schema ..."
cd /app/apps/api
npx prisma db push --accept-data-loss >/var/log/prisma-push.log 2>&1 || log "prisma db push completed with warnings (see /var/log/prisma-push.log)"
cd /app
# ─── 5. mic-realtime (Erlang) ──────────────────────────────────
log "Starting mic-realtime ..."
export MIC_REALTIME_PORT MIC_REALTIME_HOST=0.0.0.0 \
MICPROTOCOL_API_URL="http://localhost:${API_PORT}" \
REDIS_HOST=localhost REDIS_PORT="$REDIS_PORT" REDIS_PASSWORD="$REDIS_PASSWORD"
nohup /opt/mic-realtime/_build/default/rel/mic_realtime/bin/mic_realtime foreground \
>/var/log/mic-realtime.log 2>&1 &
wait_for_port localhost "$MIC_REALTIME_PORT" mic-realtime
# ─── 6. API (serves HTTP + BullMQ workers) ─────────────────────
log "Starting MicProtocol API ..."
nohup node /app/apps/api/dist/main.js >/var/log/api.log 2>&1 &
wait_for_port localhost "$API_PORT" api
# ─── 7. Web (Next.js standalone) ───────────────────────────────
log "Starting MicProtocol Web ..."
export HOSTNAME=0.0.0.0 PORT=3000
( cd /app/apps/web && node server.js ) 2>&1 &
wait_for_port localhost "$WEB_PORT" web
# ─── 8. Admin (Next.js standalone) ─────────────────────────────
log "Starting MicProtocol Admin ..."
export HOSTNAME=0.0.0.0 PORT=3006
( cd /app/apps/admin && node server.js ) 2>&1 &
wait_for_port localhost "$ADMIN_PORT" admin
# ─── 9. Nginx (foreground, entrypoint) ─────────────────────────
log "All services up. Starting nginx on port ${APP_PORT} ..."
exec nginx -g 'daemon off;'