#!/bin/bash #
curl -fsSL https://get.firebolt.io/ | bash
set -e
# Parse command line arguments
AUTO_RUN=false
if [ "$1" = "--auto-run" ]; then
AUTO_RUN=true
elif [ -n "$1" ]; then
echo "Unknown option: $1"
echo "Usage: $0 [--auto-run]" 1>&2
exit 1
fi
# When the script is piped in (e.g. 'curl | bash'), stdin is not a terminal
# and the user cannot answer prompts through it, so run without prompting.
if [ ! -t 0 ]; then
AUTO_RUN=true
fi
banner() {
echo -e "\e[31m"
echo "███████╗██╗██████╗ ███████╗██████╗ ██████╗ ██╗ ████████╗"
echo "██╔════╝██║██╔══██╗██╔════╝██╔══██╗██╔═══██╗██║ ╚══██╔══╝"
echo "█████╗ ██║██████╔╝█████╗ ██████╔╝██║ ██║██║ ██║ "
echo "██╔══╝ ██║██╔══██╗██╔══╝ ██╔══██╗██║ ██║██║ ██║ "
echo "██║ ██║██║ ██║███████╗██████╔╝╚██████╔╝███████╗██║ "
echo "╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═════╝ ╚═════╝ ╚══════╝╚═╝ "
echo -e "\e[0m"
echo " The Analytical Database for Engineers"
echo " © 2026 Firebolt Analytics Inc (https://firebolt.io)"
echo ""
echo " 🔥🔥🔥 Setup script for Firebolt 🔥🔥🔥"
echo ""
}
IS_MACOS=0
if [ "$(uname)" = "Darwin" ]; then
IS_MACOS=1
fi
# Docker image to pull - allow specifying overrides via env variables
ENGINE_REPO="${ENGINE_REPO:-ghcr.io/firebolt-db/engine}"
ENGINE_TAG="${ENGINE_TAG:-dev}"
DOCKER_IMAGE="${ENGINE_REPO}:${ENGINE_TAG}"
EXTERNAL_PORT=3473
# Generated engine config, dropped into the data directory (used on macOS only,
# see below). It is auto-loaded by the engine as /var/lib/firebolt/config.yaml.
CONFIG_FILE="firebolt-data/config.yaml"
DOCKER_CONTAINER_NAME="firebolt"
DOCKER_RUN_ARGS=(
-i
--name $DOCKER_CONTAINER_NAME
--rm
--ulimit memlock=8589934592:8589934592
--security-opt seccomp=unconfined
-v "$(pwd)/firebolt-data:/var/lib/firebolt"
-p "$EXTERNAL_PORT:3473"
)
# On macOS the Docker Desktop file-sharing backend cannot stat the engine's Unix
# domain socket when it lives on the bind-mounted data directory, so Firebolt
# fails to start. Keep the socket off the shared filesystem: put it on an
# in-memory tmpfs at /run/firebolt and relocate it there via the generated
# config file. Mirror the ownership/permissions the image ships /run/firebolt
# with (firebolt:root, mode 2770) so both root and the non-root firebolt user
# (uid 3473, group 0) can create the socket.
if [ $IS_MACOS -eq 1 ]; then
DOCKER_RUN_ARGS+=( --tmpfs /run/firebolt:rw,mode=2770,uid=3473,gid=0 )
fi
DOCKER_RUN_ARGS+=( "$DOCKER_IMAGE" )
# Engine config that moves the query Unix socket onto the tmpfs while keeping the
# HTTP endpoint on TCP 3473. Used on macOS only.
read -r -d '' CONFIG_YAML <<'EOF' || true
schema_version: "1.0"
endpoints:
http:
listeners:
- type: tcp
port: 3473
- type: unix
path: /run/firebolt/query_endpoint
EOF
write_firebolt_config() {
printf '%s\n' "$CONFIG_YAML" > "$CONFIG_FILE"
}
ensure_docker_is_installed() {
if docker info >/dev/null 2>&1; then
echo "[🐳] Docker is present and works ✅"
return 0
fi
if [ $IS_MACOS -eq 1 ]; then
echo "[🐳] Docker needs to be installed: https://docs.docker.com/desktop/setup/install/mac-install/ ❌"
else
echo "[🐳] Docker needs to be installed: https://docs.docker.com/desktop/setup/install/linux/ ❌"
fi
return 1
}
check_docker_version() {
# Explicitly inform the user about the known io_uring issue in Docker Desktop for Mac
# See also:
# * https://github.com/docker/for-mac/issues/7707
if [ $IS_MACOS -eq 1 ]; then
version=$(docker version | sed -n 's/.*Docker Desktop \([0-9.]*\).*/\1/p')
if [ "$version" = "4.42.1" ] || [ "$version" = "4.43.0" ] || [ "$version" = "4.43.1" ]; then
echo "[❌] Firebolt cannot run with Docker Desktop version ${version} on Mac, as it contains a known io_uring issue; please use version 4.43.2+"
return 1
fi
fi
}
pull_docker_image() {
echo "[🐳] Pulling Firebolt Docker image '$DOCKER_IMAGE'"
# Check the pull inline rather than through '$?': 'set -e' would abort the script on a
# failed pull before any separate check could report it, leaving the user with docker's
# raw error and none of the context below.
if docker pull --quiet "$DOCKER_IMAGE"; then
echo "[🐳] Docker image '$DOCKER_IMAGE' pulled successfully ✅"
else
echo "[🐳] Failed to pull Docker image '$DOCKER_IMAGE' ❌"
return 1
fi
}
DEFAULT_RUN_USER=""
detect_firebolt_user() {
if [ $IS_MACOS -eq 1 ]; then
DEFAULT_RUN_USER=root
else
DEFAULT_RUN_USER="firebolt"
fi
# set FIREBOLT_USER, unless already set by user
FIREBOLT_USER="${FIREBOLT_USER:-$DEFAULT_RUN_USER}"
}
wait_for_firebolt_to_be_ready() {
# If curl is not installed, we can't check if Firebolt is ready
if ! command -v curl >/dev/null 2>&1; then
return 0
fi
echo -n "[🔥] Wait for Firebolt to be ready"
# Try for ~10 seconds to get a valid response from Firebolt
timeout=10
RESPONSE="Unknown error"
while [ $timeout -gt 0 ]; do
set +e
RESPONSE=$(curl -s 'http://localhost:3473/?output_format=TabSeparatedWithNamesAndTypes' --data-binary "SELECT 42;")
set -e
if [ "$RESPONSE" = $'?column?\nint\n42' ]; then
echo " ✅"
return 0
fi
sleep 1
timeout=$((timeout - 1))
echo -n "."
done
echo " ❌"
echo "[❌] Firebolt failed to start. This is unexpected, please submit a bug report on Github https://github.com/firebolt-db/firebolt-core/issues"
echo "[❌] Error: $RESPONSE"
return 1
}
run_docker_image() {
echo "[⚠️] Note: a local 'firebolt-data directory' with permissions 0777 will be created."
if [ $IS_MACOS -eq 1 ]; then
echo "[⚠️] Note: on macOS a '$CONFIG_FILE' file will be created and the socket will run on an in-memory tmpfs."
fi
if [ "$AUTO_RUN" = true ]; then
answer="y"
else
prompt="[🔥] Everything is set up and you are ready to go! Do you want to run the Firebolt image? (use --auto-run to skip this prompt) [y/N]: "
if ! { printf "%s" "$prompt" > /dev/tty && read -r answer < /dev/tty; } 2>/dev/null; then
answer=""
fi
fi
case "$answer" in
[yY])
if [ ! -d firebolt-data ]; then
mkdir -p -m 777 firebolt-data
fi
if [ $IS_MACOS -eq 1 ]; then
write_firebolt_config
fi
echo -n "[🔥] Starting the Firebolt Docker container"
CID="$(docker run --detach --user $FIREBOLT_USER "${DOCKER_RUN_ARGS[@]}")"
trap "docker kill $CID" EXIT
echo " ✅"
wait_for_firebolt_to_be_ready
# stdin may be the script itself (e.g. 'curl | bash'), so attach the
# CLI to the controlling terminal instead; without one, leave the
# container running in the background.
#
# The image ships no separate CLI binary: `firebolt` is both the server and the
# client. The `client` subcommand is what connects to the server already running
# in the container (localhost:3473, database "firebolt") — a bare `firebolt`
# would start a second, embedded one instead.
if { : < /dev/tty; } 2>/dev/null; then
echo "[🔥] Running Firebolt CLI"
docker exec -ti $CID firebolt client < /dev/tty
else
trap - EXIT
echo "[🔥] No terminal available, leaving Firebolt running in the background."
echo "[🔥] Connect to it with: docker exec -ti $DOCKER_CONTAINER_NAME firebolt client"
echo "[🔥] Stop it with: docker kill $DOCKER_CONTAINER_NAME"
fi
;;
*)
echo "[🔥] Firebolt is ready to be executed, you can do this by running the following commands:"
echo
echo "mkdir -m 777 firebolt-data"
if [ $IS_MACOS -eq 1 ]; then
echo "cat > $CONFIG_FILE <<'EOF'"
printf '%s\n' "$CONFIG_YAML"
echo "EOF"
fi
# Print the arguments one by one with '%q' so the line stays copy-pasteable: it
# quotes whatever needs quoting, e.g. the bind-mount path when the current
# directory contains spaces.
printf 'docker run --user %q' "$FIREBOLT_USER"
printf ' %q' "${DOCKER_RUN_ARGS[@]}"
printf '\n'
echo
echo "And then in another terminal:"
echo
echo "docker exec -ti $DOCKER_CONTAINER_NAME firebolt client"
echo
;;
esac
}
# Main script execution
banner
ensure_docker_is_installed
check_docker_version
pull_docker_image
detect_firebolt_user
run_docker_image