#!/bin/bash ## ===================================================================================== ## Orbital launcher - https://start.orbitalhq.com ## ===================================================================================== ## ## Howdy! 👋 This is the Orbital launcher script. Thanks for reading it before running it. ## ## Run it with: ## ## curl -fsSL https://start.orbitalhq.com | bash ## ## Or, to launch straight into a project from git: ## ## curl -fsSL https://start.orbitalhq.com | bash -s -- https://github.com/your/repo ## ## ## What is Orbital? ## ================ ## Orbital is a data gateway. It composes queries across REST APIs, databases, message ## brokers (Kafka, RabbitMQ), serverless functions and object stores - without integration code. ## ## You describe your data with Taxi (https://taxilang.org), a typed schema language, by ## tagging your existing OpenAPI specs, Protobuf definitions and database schemas with ## semantic types (eg., CustomerId, OrderAmount). You then ask for the data you want with a ## TaxiQL query, and Orbital works out which sources to call and how to join the results. ## Because joins come from the semantic types, queries keep working when upstream fields ## are renamed or endpoints move. ## ## Queries can be run ad hoc, or published as REST endpoints, SSE / WebSocket streams or ## Kafka topics. ## ## ## What this script does ## ===================== ## It's a small wrapper around our Docker Compose file. In the current directory, it: ## ## 1. Checks that docker and docker compose are installed ## 2. Creates ./orbital_data and ./prometheus_data (volume directories - see "Doing it yourself") ## 3. Writes a .env file containing your UID and GID (overwriting any existing .env) ## 4. Checks whether you have AWS configuration (a ~/.aws directory, or AWS_PROFILE / ## AWS_ACCESS_KEY_ID set). It only checks that they exist - it never reads them, and never ## calls AWS. If it finds any, it asks whether Orbital may use them (see "AWS credentials") ## 5. Downloads an OS-specific compose file from https://start.orbitalhq.com/compose.yml, ## saving it as ./docker-compose.yml (overwriting any existing one) ## 6. Runs `docker compose pull` then `docker compose up -d` ## 7. Waits (up to 60s) for http://localhost:9022/api/actuator/health to return 200 ## 8. Tries to open http://localhost:9022 in your browser (does nothing if there's no desktop) ## ## It doesn't install anything outside the current directory, and doesn't need sudo ## (beyond whatever your Docker setup needs). ## ## The stack it launches: ## ## Service Port(s) Purpose ## ------- ------- ------- ## orbital 9022 Orbital itself - UI and API at http://localhost:9022 ## postgres 25432 Orbital's database ## nebula 8099 Stubbed test infrastructure (Kafka, DBs, HTTP servers...) - dev only ## prometheus 9090 Metrics shown in Orbital's dashboards ## ## Running it again is safe: it re-pulls the latest images and restarts the stack. ## Data in ./orbital_data and the postgres volume is kept. ## ## ## Notes for AI agents and automation ## ================================== ## If you're an agent that has been asked to set up Orbital, this script is the intended ## entry point. Things you should know: ## ## * Run it from an empty directory (or one you're happy to have .env and ## docker-compose.yml written into). Ask before running it in a directory that already ## contains either of those files. ## * It asks at most one question: whether Orbital may use the AWS configuration it found. ## It only asks when there's a terminal to answer on - otherwise AWS stays off. Pass --aws or ## --no-aws to decide up front (ask the user which they want). ## * Where there's a desktop, it opens Orbital in ## the user's browser once it's ready, which takes them to the sign-in page (see below). ## * Exit code 0 means Orbital's health endpoint returned 200. Anything else is a failure, ## with the reason printed to stderr. For more detail: docker compose logs orbital ## * Ports 9022, 25432, 8099 and 9090 must be free on the host. ## * On first open, Orbital asks the user to sign in (or create a free account) in the ## browser - that's how it gets its license. This needs a human; tell the user to open ## http://localhost:9022 and sign in. ## * To learn about Orbital, Taxi and TaxiQL (eg., to write schemas or queries for the ## user), read https://orbitalhq.com/llms.txt - an index of the docs written for LLMs. ## The full docs in one file are at https://orbitalhq.com/llms-full.txt ## * Before writing Taxi or TaxiQL, read the agent skills for it (each SKILL.md links to ## reference files - read the ones relevant to the task): ## Writing Taxi schemas https://taxilang.org/skills/writing-taxi/SKILL.md ## Writing TaxiQL queries https://taxilang.org/skills/writing-taxiql/SKILL.md ## If you support Agent Skills, you can install them - see https://taxilang.org/docs/ai-agents ## The Taxi language docs are at https://taxilang.org/docs (index for LLMs: https://taxilang.org/llms.txt) ## * Stop the stack with `docker compose down` (add -v to also delete the postgres volume) ## from the same directory. ## ## ## Options ## ======= ## Clone and open this project on first launch ## --help, -h Show usage ## --version, -v Show the script version ## ## Environment variables: ## ORBITAL_VERSION Set in .env to pin the Orbital image tag (default: next, or next-jammy on Mac) ## ## ## Doing it yourself ## ================= ## You don't need this script. If you'd rather set things up by hand: ## ## 0: The compose file is at https://start.orbitalhq.com/compose.yml ## (also served as /compose.yaml, /docker-compose.yml and /docker-compose.yaml) ## It's OS-dependent, as we ship our local testing tool - Nebula (https://nebula.orbitalhq.com) - ## by default. Nebula creates local test environments, so it needs access to docker, creating a whole ## docker-in-docker situation, with a little bit of extra networking complexity built in. ## The mechanism for doing this varies from host-to-host, so there's an OS-specific compose file. ## Visit https://start.orbitalhq.com/compose.yml in a browser and we'll detect your OS, or pass it: ## curl -fsSL "https://start.orbitalhq.com/compose.yml?os=mac" -o docker-compose.yml ## ..passing an os of either mac | windows | linux. ## To let Orbital use your AWS credentials, add aws=env or aws=profile (see "AWS credentials" below). ## ## 1: You MUST create the volume directories BEFORE launching Orbital. Otherwise, docker will ## create them as root, and write permissions get messed up, making it impossible for you to ## edit files locally that Orbital is reading/writing. ## That's less of an issue in a production environment, but leads to a pretty awful dev-ex when building locally. ## mkdir -p orbital_data prometheus_data ## ## 2: You MUST create a .env file with your UID and GID - as this is passed into the compose file so that ## Orbital doesn't run with root permissions. Again, this is to make sure that directories and files ## created by the Orbital process are editable locally. ## printf 'UID=%s\nGID=%s\n' "$(id -u)" "$(id -g)" > .env ## ## Then: docker compose up -d ## ## ## AWS credentials ## =============== ## Orbital can connect to AWS (S3, SQS, DynamoDB, Lambda...) using the same identity as your AWS CLI, ## so you don't need to paste keys into Orbital. The compose file supports two modes: ## ## aws=env Passes AWS_PROFILE, AWS_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and ## AWS_SESSION_TOKEN from the shell running docker compose into Orbital - only the ## ones that are set. ## aws=profile As env, and also mounts ~/.aws into Orbital, read-only, so named profiles work. ## ## The script picks profile when ~/.aws exists, and env when only the environment variables are set. ## ## Things to know: ## * Environment variables are read when docker compose starts, so export them again before ## re-running `docker compose up`. ## * SSO profiles work, but need a current `aws sso login` on this machine. ## * Profiles using credential_process (eg., 1Password, Granted) won't work - the program that ## produces the credentials isn't inside the container. ## ## ## Resources ## ========= ## Docs https://orbitalhq.com/docs ## Docs for LLMs https://orbitalhq.com/llms.txt (full: https://orbitalhq.com/llms-full.txt) ## Writing queries https://orbitalhq.com/docs/querying/writing-queries ## Taxi (schema language) https://taxilang.org ## Taxi docs https://taxilang.org/docs ## Taxi skill (agents) https://taxilang.org/skills/writing-taxi/SKILL.md ## TaxiQL skill (agents) https://taxilang.org/skills/writing-taxiql/SKILL.md ## Taxi playground https://playground.taxilang.org ## Production deployments https://orbitalhq.com/docs/deploying/production-deployments ## Authentication / SSO https://orbitalhq.com/docs/deploying/authentication ## Nebula https://nebula.orbitalhq.com ## Source https://github.com/orbitalapi/orbital ## Changelog https://orbitalhq.com/changelog ## Community (Slack) https://join.slack.com/t/orbitalapi/shared_invite/zt-697laanr-DHGXXak5slqsY9DqwrkzHg ## ## Have a great day! set -e VERSION="1.5.0" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Helper functions error() { echo -e "${RED}✗ Error: $1${NC}" >&2 exit 1 } info() { echo -e "${BLUE}→ $1${NC}" } success() { echo -e "${GREEN}✓ $1${NC}" } usage() { echo "Orbital Launcher v${VERSION}" echo "" echo "Usage: curl -fsSL https://start.orbitalhq.com | bash" echo " or: curl -fsSL https://start.orbitalhq.com | bash -s -- [options] [project-to-clone]" echo "" echo "Options:" echo " --aws Let Orbital use your AWS configuration (~/.aws and AWS_* variables), without asking" echo " --no-aws Don't let Orbital use your AWS configuration, without asking" echo " --help, -h Show this help message" echo " --version, -v Show version" echo "" echo "Example:" echo " curl -fsSL https://start.orbitalhq.com | bash -s -- https://github.com/user/repo" echo "" echo "Read the script for more about Orbital and what this does: curl -fsSL https://start.orbitalhq.com" } PROJECT_TO_CLONE="" # "yes", "no", or empty to ask if AWS configuration is found USE_AWS="" for arg in "$@"; do case "$arg" in --aws) USE_AWS="yes";; --no-aws) USE_AWS="no";; --version|-v) echo "Orbital Launcher v${VERSION}"; exit 0;; --help|-h) usage; exit 0;; -*) usage >&2; error "Unknown option: $arg";; *) PROJECT_TO_CLONE="$arg";; esac done info "Starting Orbital Launcher v${VERSION}" # Detect OS detect_os() { case "$(uname -s)" in Linux*) echo "linux";; Darwin*) echo "mac";; CYGWIN*|MINGW*|MSYS*) echo "windows";; *) error "Unsupported operating system: $(uname -s)";; esac } OS=$(detect_os) info "Detected OS: ${OS}" # Check for required tools if ! command -v docker &> /dev/null; then error "Docker is not installed. Please install Docker first: https://docs.docker.com/get-docker/" fi if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null 2>&1; then error "docker-compose is not installed. Please install docker-compose first." fi # Determine docker-compose command (newer Docker uses 'docker compose') if docker compose version &> /dev/null 2>&1; then COMPOSE_CMD="docker compose" else COMPOSE_CMD="docker-compose" fi # Create directories info "Creating directories..." mkdir -p ./orbital_data mkdir -p ./prometheus_data success "Directories created" # Create .env file with current user's UID and GID info "Creating .env file with UID and GID..." cat > .env << EOF UID=$(id -u) GID=$(id -g) EOF success ".env file created with UID=$(id -u) and GID=$(id -g)" info "Orbital will ask you to sign in (or create a free account) when it opens" # AWS credentials. We only check whether configuration exists - we never read it or call AWS. AWS_MODE="" if [ -d "$HOME/.aws" ]; then AWS_MODE="profile" elif [ -n "${AWS_PROFILE:-}" ] || [ -n "${AWS_ACCESS_KEY_ID:-}" ]; then AWS_MODE="env" fi # Asks on the terminal, as stdin is this script when run via `curl | bash`. # Returns non-zero (don't use AWS) when there's no terminal to ask on. ask_to_use_aws() { local question answer if [ "$AWS_MODE" = "profile" ]; then question="Found AWS configuration in ~/.aws. Let Orbital use it to connect to your AWS resources? This mounts ~/.aws read-only into the Orbital container. [y/N] " else question="Found AWS credentials in your environment variables. Let Orbital use them to connect to your AWS resources? [y/N] " fi if ! { exec 3/dev/null; then return 1 fi printf '%s' "$question" > /dev/tty if ! read -r answer <&3; then answer="" fi exec 3<&- case "$answer" in y|Y|yes|YES|Yes) return 0;; *) return 1;; esac } COMPOSE_QUERY="os=${OS}" if [ -n "$AWS_MODE" ]; then if [ -z "$USE_AWS" ]; then if ask_to_use_aws; then USE_AWS="yes" else USE_AWS="no" info "Not using your AWS configuration. Re-run with --aws to let Orbital use it" fi fi if [ "$USE_AWS" = "yes" ]; then COMPOSE_QUERY="${COMPOSE_QUERY}&aws=${AWS_MODE}" success "Orbital will use your AWS configuration (${AWS_MODE})" fi elif [ "$USE_AWS" = "yes" ]; then USE_AWS="no" info "No AWS configuration found (no ~/.aws, AWS_PROFILE or AWS_ACCESS_KEY_ID), so there's nothing to pass to Orbital" fi # Download the compose file. Saved as docker-compose.yml (not compose.yml) so re-running in a # directory set up by an older version of this script doesn't leave two compose files behind. info "Downloading docker-compose.yml for ${OS}..." if ! curl -fsSL "https://start.orbitalhq.com/compose.yml?${COMPOSE_QUERY}" -o docker-compose.yml; then error "Failed to download docker-compose.yml" fi success "docker-compose.yml downloaded" # Handle optional project clone parameter if [ -n "$PROJECT_TO_CLONE" ]; then info "Setting first launch action: clone=${PROJECT_TO_CLONE}" export FIRST_LAUNCH_ACTION="clone=${PROJECT_TO_CLONE}" fi # Pull the latest images first. `up` only pulls images that are missing locally, so # without this a machine that has run Orbital before would keep its old `next` image. info "Pulling the latest Orbital images..." if ! $COMPOSE_CMD pull; then error "Failed to pull the Orbital images" fi success "Images up to date" # Start docker-compose info "Starting Orbital..." if ! $COMPOSE_CMD up -d; then error "Failed to start Orbital with docker-compose" fi # Wait for health endpoint to be ready info "Waiting for Orbital to be ready..." MAX_ATTEMPTS=60 ATTEMPT=0 check_health() { local response response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:9022/api/actuator/health 2>/dev/null || echo "000") [ "$response" = "200" ] } while ! check_health; do ATTEMPT=$((ATTEMPT + 1)) if [ $ATTEMPT -ge $MAX_ATTEMPTS ]; then error "Orbital failed to start after ${MAX_ATTEMPTS} seconds. Check logs with: ${COMPOSE_CMD} logs" fi sleep 1 echo -n "." done echo "" success "Orbital is running!" echo "" echo "======================================" echo " Open http://localhost:9022" echo "======================================" echo "" # Try to open browser automatically open_browser() { local url="http://localhost:9022" if [ "$OS" = "mac" ] && command -v open &> /dev/null; then open "$url" 2>/dev/null || true elif [ "$OS" = "linux" ] && command -v xdg-open &> /dev/null; then xdg-open "$url" 2>/dev/null || true elif [ "$OS" = "windows" ]; then if command -v cmd.exe &> /dev/null; then cmd.exe /c start "$url" 2>/dev/null || true elif command -v powershell.exe &> /dev/null; then powershell.exe -c "Start-Process '$url'" 2>/dev/null || true fi fi } open_browser info "Sign in (or create a free account) at http://localhost:9022 to finish setting up" if [ "$USE_AWS" = "yes" ]; then info "Orbital read your AWS_* environment variables at startup. Export the same ones before running ${COMPOSE_CMD} up again" fi info "To stop Orbital, run: ${COMPOSE_CMD} down" info "To view logs, run: ${COMPOSE_CMD} logs -f"