#!/usr/bin/env sh # Pradra Studio — self-host installer. # # Fetches the compose file, writes .env.selfhost (asking for your license key if # needed), generates a JWT secret, and brings the stack up from Docker Hub. # # Usage: # curl -fsSL https://get.pradra.studio | sh # # non-interactive: # PRADRA_LICENSE_KEY=lic_xxx curl -fsSL https://get.pradra.studio | sh # # Environment overrides: # PRADRA_LICENSE_KEY your license key (else you are prompted) # PRADRA_DIR install dir (default: ./pradra) # PRADRA_VERSION image tag to pin (default: latest) # PRADRA_BASE_URL where to fetch compose/.env from # WEB_PORT host port for the web UI (default: 8080) set -eu BASE_URL="${PRADRA_BASE_URL:-https://raw.githubusercontent.com/pradra/self-host/main}" DIR="${PRADRA_DIR:-pradra}" COMPOSE_FILE="docker-compose.selfhost.yml" ENV_FILE=".env.selfhost" say() { printf '\033[1;36m==>\033[0m %s\n' "$1"; } err() { printf '\033[1;31mError:\033[0m %s\n' "$1" >&2; exit 1; } # 1. Preflight --------------------------------------------------------------- command -v docker >/dev/null 2>&1 || err "Docker is not installed. See https://docs.docker.com/get-docker/" if docker compose version >/dev/null 2>&1; then DC="docker compose" elif command -v docker-compose >/dev/null 2>&1; then DC="docker-compose" else err "Docker Compose is not available. Install Docker Compose v2." fi command -v curl >/dev/null 2>&1 || err "curl is required." say "Installing Pradra Studio into ./$DIR" mkdir -p "$DIR" cd "$DIR" # 2. Fetch the compose file -------------------------------------------------- say "Downloading $COMPOSE_FILE" curl -fsSL "$BASE_URL/$COMPOSE_FILE" -o "$COMPOSE_FILE" \ || err "Could not download $COMPOSE_FILE from $BASE_URL" # 3. Write .env.selfhost (only if absent, so re-runs never clobber it) ------- if [ -f "$ENV_FILE" ]; then say "$ENV_FILE already exists — keeping it" else KEY="${PRADRA_LICENSE_KEY:-}" if [ -z "$KEY" ]; then [ -t 0 ] || err "No license key. Set PRADRA_LICENSE_KEY or run interactively." printf 'Enter your Pradra license key (lic_...): ' # Read from the terminal even when the script itself is piped from curl. read -r KEY < /dev/tty fi [ -n "$KEY" ] || err "A license key is required." # A random JWT secret so sessions are safe by default. JWT="$(head -c 48 /dev/urandom | od -An -tx1 | tr -d ' \n')" say "Writing $ENV_FILE" { echo "AIFORGE_LICENSE_KEY=$KEY" echo "AIFORGE_JWT_SECRET=$JWT" [ -n "${PRADRA_VERSION:-}" ] && echo "PRADRA_VERSION=$PRADRA_VERSION" [ -n "${WEB_PORT:-}" ] && echo "WEB_PORT=$WEB_PORT" } > "$ENV_FILE" chmod 600 "$ENV_FILE" fi # 4. Pull + start ------------------------------------------------------------ say "Pulling images from Docker Hub" $DC --env-file "$ENV_FILE" -f "$COMPOSE_FILE" pull say "Starting the stack" $DC --env-file "$ENV_FILE" -f "$COMPOSE_FILE" up -d PORT="$(grep -E '^WEB_PORT=' "$ENV_FILE" 2>/dev/null | cut -d= -f2)" PORT="${PORT:-${WEB_PORT:-8080}}" say "Done. Pradra Studio is starting." echo echo " Web UI: http://localhost:$PORT" echo " Health: curl -fsS http://localhost:$PORT/healthz (shows license_state)" echo " Logs: (cd $DIR && $DC -f $COMPOSE_FILE logs -f studio)" echo " Stop: (cd $DIR && $DC -f $COMPOSE_FILE down)" echo echo "If the license is valid it serves normally; when the subscription ends it" echo "warns for a grace period, then returns 503 until you renew. Renewing resumes" echo "the running server automatically — no new key, no reinstall."