mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
feat(self-hosted): add setup.sh and run.sh scripts for self-hosted supabase (#45603)
This commit is contained in:
1 parent
6f88585a7e
commit
fcb8ee0412
4 files changed
+647
-2
No files matched your search
+15
-1
@@ -1,3 +1,16 @@
|
||||
############
|
||||
# Docker compose override files to layer on top of docker-compose.yml.
|
||||
# Native docker compose COMPOSE_FILE: colon-separated list, base file first.
|
||||
# Manage with: ./run.sh config add|remove <name>
|
||||
#
|
||||
# Examples:
|
||||
# COMPOSE_FILE=docker-compose.yml
|
||||
# COMPOSE_FILE=docker-compose.yml:docker-compose.pg17.yml
|
||||
#
|
||||
############
|
||||
COMPOSE_FILE=docker-compose.yml
|
||||
|
||||
|
||||
############
|
||||
# Secrets
|
||||
#
|
||||
@@ -8,7 +21,8 @@
|
||||
# https://supabase.com/docs/guides/self-hosting/docker#configuring-and-securing-supabase
|
||||
#
|
||||
# To generate secrets and API keys:
|
||||
# sh ./utils/generate-keys.sh
|
||||
# 1. sh utils/generate-keys.sh
|
||||
# 2. sh utils/add-new-auth-keys.sh
|
||||
#
|
||||
############
|
||||
|
||||
|
||||
+5
-1
@@ -13,7 +13,11 @@ See per-service updates below for details.
|
||||
|
||||
## Unreleased
|
||||
|
||||
⚠️ **Upcoming default changes:** In a future release, several defaults will change: Postgres 15 → 17, Kong → Envoy, MinIO → RustFS, Analytics/Vector removed from the default stack, and the new API keys and authentication replacing the "legacy" architecture. Most of these are already available as optional configurations.
|
||||
⚠️ **Upcoming changes:** Check the main Supabase [changelog](https://github.com/orgs/supabase/discussions/categories/changelog?discussions_q=is%3Aopen+category%3AChangelog+label%3Aself-hosted) for updates:
|
||||
|
||||
- [Making Analytics and Vector opt-in](https://github.com/orgs/supabase/discussions/46084)
|
||||
- [Upgrading from PG 15 to 17 (breaking change)](https://github.com/orgs/supabase/discussions/46080)
|
||||
- [Switching Studio from `supabase_admin` to `postgres` (breaking change)](https://github.com/orgs/supabase/discussions/46081)
|
||||
|
||||
---
|
||||
|
||||
|
||||
Executable
+297
@@ -0,0 +1,297 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Manage the self-hosted Supabase docker compose stack.
|
||||
#
|
||||
# Override files are layered via docker compose's native COMPOSE_FILE env
|
||||
# var in .env. Format: colon-separated list with docker-compose.yml first.
|
||||
#
|
||||
# Examples in .env:
|
||||
# COMPOSE_FILE=docker-compose.yml
|
||||
# COMPOSE_FILE=docker-compose.yml:docker-compose.pg17.yml
|
||||
#
|
||||
# Manage with: ./run.sh config add <name> | config remove <name>
|
||||
# (accepts either a short name like 'pg17' or 'docker-compose.pg17.yml')
|
||||
#
|
||||
# Usage:
|
||||
# ./run.sh start # docker compose up -d --wait
|
||||
# ./run.sh stop # docker compose down
|
||||
# ./run.sh restart [service] # restart the stack (or named services)
|
||||
# ./run.sh restart --except <svc>... # restart all services except the named ones
|
||||
# ./run.sh recreate [service] # stop then start (or force-recreate one service)
|
||||
# ./run.sh recreate --except <svc>... # force-recreate all services except the named ones
|
||||
# ./run.sh status # docker compose ps
|
||||
# ./run.sh logs [service] # follow logs (all or one service)
|
||||
# ./run.sh inspect <service> # docker inspect on a service's container
|
||||
# ./run.sh printenv <service> # print a service's environment variables
|
||||
# ./run.sh pull # pull images
|
||||
# ./run.sh config # show the active COMPOSE_FILE list
|
||||
# ./run.sh config add <name> # add an override to COMPOSE_FILE in .env
|
||||
# ./run.sh config remove <name> # remove an override from COMPOSE_FILE in .env
|
||||
# ./run.sh compose-config # dump fully-resolved docker compose config
|
||||
# ./run.sh secrets # print key passwords and API keys from .env
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
if [ ! -f docker-compose.yml ]; then
|
||||
echo "ERROR: docker-compose.yml not found in $(pwd)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Normalize an override argument:
|
||||
# pg17 -> docker-compose.pg17.yml
|
||||
# docker-compose.pg17.yml -> docker-compose.pg17.yml
|
||||
# ./docker-compose.pg17.yml -> docker-compose.pg17.yml
|
||||
# docker-compose.yml -> error (base file, always implicit)
|
||||
normalize_override() {
|
||||
arg="${1#./}"
|
||||
case "$arg" in
|
||||
docker-compose.yml)
|
||||
echo "ERROR: docker-compose.yml is the base file, always included" >&2
|
||||
return 1
|
||||
;;
|
||||
docker-compose.*.yml)
|
||||
echo "$arg"
|
||||
;;
|
||||
*)
|
||||
echo "docker-compose.${arg}.yml"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Read COMPOSE_FILE from .env (stripping quotes and CR).
|
||||
read_compose_file() {
|
||||
[ -f .env ] || return 0
|
||||
grep '^COMPOSE_FILE=' .env | head -n1 | cut -d= -f2- | tr -d "\r\"'"
|
||||
}
|
||||
|
||||
# Pretty-print the effective compose file list.
|
||||
print_config() {
|
||||
val="$1"
|
||||
[ -z "$val" ] && val="docker-compose.yml"
|
||||
echo "COMPOSE_FILE=$val"
|
||||
echo "compose files:"
|
||||
OLD_IFS=$IFS
|
||||
IFS=:
|
||||
for f in $val; do
|
||||
echo " $f"
|
||||
done
|
||||
IFS=$OLD_IFS
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Update or append COMPOSE_FILE in .env.
|
||||
write_compose_file() {
|
||||
new_value="$1"
|
||||
if [ ! -f .env ]; then
|
||||
echo "ERROR: .env not found in $(pwd)" >&2
|
||||
exit 1
|
||||
fi
|
||||
new_line="COMPOSE_FILE=$new_value"
|
||||
if grep -q '^COMPOSE_FILE=' .env; then
|
||||
sed -i.old -e "s|^COMPOSE_FILE=.*$|$new_line|" .env
|
||||
rm -f .env.old
|
||||
else
|
||||
cat >> .env <<EOF
|
||||
|
||||
############
|
||||
# Docker compose override files to layer on top of docker-compose.yml.
|
||||
# Colon-separated list. Manage with ./run.sh config add|remove <name>.
|
||||
#
|
||||
# Examples:
|
||||
# COMPOSE_FILE=docker-compose.yml
|
||||
# COMPOSE_FILE=docker-compose.yml:docker-compose.pg17.yml
|
||||
############
|
||||
$new_line
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
# Echoes the list of services (one per line) minus those passed as args.
|
||||
# Warns on unknown names; returns 1 if no services remain.
|
||||
services_except() {
|
||||
all_services=$(docker compose config --services)
|
||||
filtered="$all_services"
|
||||
for ex in "$@"; do
|
||||
echo "$all_services" | grep -qFx "$ex" \
|
||||
|| echo "Warning: '$ex' is not a service in this project" >&2
|
||||
filtered=$(echo "$filtered" | grep -vFx "$ex" || true)
|
||||
done
|
||||
if [ -z "$filtered" ]; then
|
||||
echo "No services left after applying --except" >&2
|
||||
return 1
|
||||
fi
|
||||
printf '%s\n' "$filtered"
|
||||
}
|
||||
|
||||
CMD="${1:-help}"
|
||||
[ "$#" -gt 0 ] && shift
|
||||
|
||||
case "$CMD" in
|
||||
start|up)
|
||||
exec docker compose up -d --wait "$@"
|
||||
;;
|
||||
stop|down)
|
||||
exec docker compose down "$@"
|
||||
;;
|
||||
restart)
|
||||
if [ "${1:-}" = "--except" ]; then
|
||||
shift
|
||||
[ $# -eq 0 ] && { echo "Usage: $(basename "$0") restart --except <svc>..." >&2; exit 1; }
|
||||
services=$(services_except "$@") || exit 1
|
||||
# shellcheck disable=SC2086
|
||||
exec docker compose restart $services
|
||||
fi
|
||||
exec docker compose restart "$@"
|
||||
;;
|
||||
recreate)
|
||||
if [ "${1:-}" = "--except" ]; then
|
||||
shift
|
||||
[ $# -eq 0 ] && { echo "Usage: $(basename "$0") recreate --except <svc>..." >&2; exit 1; }
|
||||
services=$(services_except "$@") || exit 1
|
||||
# shellcheck disable=SC2086
|
||||
exec docker compose up -d --wait --force-recreate --no-deps $services
|
||||
fi
|
||||
if [ $# -eq 0 ]; then
|
||||
docker compose down
|
||||
exec docker compose up -d --wait
|
||||
fi
|
||||
# Single-service recreate: force-recreate the named services only,
|
||||
# leave their dependencies running.
|
||||
exec docker compose up -d --wait --force-recreate --no-deps "$@"
|
||||
;;
|
||||
status|ps)
|
||||
exec docker compose ps "$@"
|
||||
;;
|
||||
logs)
|
||||
exec docker compose logs -f "$@"
|
||||
;;
|
||||
inspect)
|
||||
[ $# -eq 0 ] && { echo "Usage: $(basename "$0") inspect <service> [docker-inspect-args]" >&2; exit 1; }
|
||||
svc="$1"; shift
|
||||
cid=$(docker compose ps -q "$svc")
|
||||
[ -z "$cid" ] && { echo "Service '$svc' is not running" >&2; exit 1; }
|
||||
exec docker inspect "$cid" "$@"
|
||||
;;
|
||||
printenv)
|
||||
[ $# -eq 0 ] && { echo "Usage: $(basename "$0") printenv <service>" >&2; exit 1; }
|
||||
svc="$1"
|
||||
cid=$(docker compose ps -q "$svc")
|
||||
[ -z "$cid" ] && { echo "Service '$svc' is not running" >&2; exit 1; }
|
||||
exec docker inspect --format='{{range .Config.Env}}{{println .}}{{end}}' "$cid"
|
||||
;;
|
||||
pull)
|
||||
exec docker compose pull "$@"
|
||||
;;
|
||||
compose-config)
|
||||
exec docker compose config "$@"
|
||||
;;
|
||||
config)
|
||||
sub="${1:-show}"
|
||||
[ "$#" -gt 0 ] && shift
|
||||
current=$(read_compose_file)
|
||||
case "$sub" in
|
||||
show)
|
||||
print_config "$current"
|
||||
;;
|
||||
add)
|
||||
[ $# -eq 0 ] && { echo "Usage: $(basename "$0") config add <name>..." >&2; exit 1; }
|
||||
new_value="${current:-docker-compose.yml}"
|
||||
changed=false
|
||||
for arg in "$@"; do
|
||||
file=$(normalize_override "$arg") || exit 1
|
||||
if [ ! -f "$file" ]; then
|
||||
echo "ERROR: $file not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
case ":$new_value:" in
|
||||
*":$file:"*) echo "Already present: $file" ;;
|
||||
*) new_value="$new_value:$file"; changed=true ;;
|
||||
esac
|
||||
done
|
||||
[ "$changed" = true ] && write_compose_file "$new_value"
|
||||
print_config "$new_value"
|
||||
;;
|
||||
remove|rm)
|
||||
[ $# -eq 0 ] && { echo "Usage: $(basename "$0") config remove <name>..." >&2; exit 1; }
|
||||
new_value="${current:-docker-compose.yml}"
|
||||
changed=false
|
||||
for arg in "$@"; do
|
||||
file=$(normalize_override "$arg") || exit 1
|
||||
case ":$new_value:" in
|
||||
*":$file:"*)
|
||||
# Drop $file by rebuilding the colon list
|
||||
tmp=""
|
||||
OLD_IFS=$IFS
|
||||
IFS=:
|
||||
for tok in $new_value; do
|
||||
[ "$tok" = "$file" ] || tmp="${tmp:+$tmp:}$tok"
|
||||
done
|
||||
IFS=$OLD_IFS
|
||||
new_value="$tmp"
|
||||
changed=true
|
||||
;;
|
||||
*) echo "Not present: $file" ;;
|
||||
esac
|
||||
done
|
||||
[ "$changed" = true ] && write_compose_file "$new_value"
|
||||
print_config "$new_value"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown config subcommand: $sub" >&2
|
||||
echo "Use: config | config add <name>... | config remove <name>..." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
secrets)
|
||||
if [ ! -f .env ]; then
|
||||
echo "ERROR: .env not found in $(pwd)" >&2
|
||||
exit 1
|
||||
fi
|
||||
for var in POSTGRES_PASSWORD DASHBOARD_PASSWORD \
|
||||
SUPABASE_PUBLISHABLE_KEY SUPABASE_SECRET_KEY \
|
||||
S3_PROTOCOL_ACCESS_KEY_ID S3_PROTOCOL_ACCESS_KEY_SECRET; do
|
||||
line=$(grep "^${var}=" .env | head -n1)
|
||||
if [ -n "$line" ]; then
|
||||
echo "$line"
|
||||
else
|
||||
echo "${var}="
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
;;
|
||||
help|-h|--help)
|
||||
cat <<EOF
|
||||
Usage: $(basename "$0") <command>
|
||||
|
||||
Commands:
|
||||
start Start the stack (docker compose up -d --wait)
|
||||
stop Stop the stack (docker compose down)
|
||||
restart [service] Restart the stack (or named services)
|
||||
restart --except <svc>...
|
||||
Restart all services except the named ones
|
||||
recreate [service] Stop then start, or force-recreate one service (--no-deps)
|
||||
recreate --except <svc>...
|
||||
Force-recreate all services except the named ones (--no-deps)
|
||||
status Show service status
|
||||
logs [service] Follow logs (optionally for a single service)
|
||||
inspect <service> Inspect a service's container (forwards extra args to docker inspect)
|
||||
printenv <service> Print a service's environment variables (one per line)
|
||||
pull Pull all images
|
||||
config Show the active COMPOSE_FILE list
|
||||
config add <name> Add an override to COMPOSE_FILE in .env (short name or full filename)
|
||||
config remove <name> Remove an override from COMPOSE_FILE in .env
|
||||
compose-config Dump the fully-resolved docker compose config
|
||||
secrets Show key passwords and API keys from .env
|
||||
|
||||
EOF
|
||||
;;
|
||||
*)
|
||||
echo "Unknown command: $CMD" >&2
|
||||
echo "Run '$0 help' for usage." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Executable
+330
@@ -0,0 +1,330 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Bootstrap a self-hosted Supabase project on Linux (Debian/Ubuntu or RHEL/CentOS/Fedora).
|
||||
#
|
||||
# What it does:
|
||||
# 1. Installs prerequisites: git, curl, openssl, jq, ca-certificates
|
||||
# 2. Installs Docker Engine + Compose plugin (if missing)
|
||||
# 3. Optionally installs the AWS CLI v2 (--with-aws)
|
||||
# 4. Sparse-clones the repo to extract the contents of ./docker
|
||||
# 5. Creates a project directory in CWD and copies docker/* into it
|
||||
# 6. Prompts for the main URLs and writes them to .env
|
||||
# 7. Generates secrets and asymmetric API keys via utils/*.sh
|
||||
#
|
||||
# Usage:
|
||||
# sh setup.sh # interactive
|
||||
# sh setup.sh -y # accept defaults, no prompts
|
||||
# sh setup.sh --project-dir my-supabase # name the project directory
|
||||
# sh setup.sh --skip-deps # skip system-package installation
|
||||
# sh setup.sh --with-aws # also install the AWS CLI v2
|
||||
#
|
||||
# curl -fsSL <url-to-this-script> | sh # bootstrap from scratch in CWD
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
PROJECT_DIR="supabase-project"
|
||||
SKIP_DEPS=0
|
||||
WITH_AWS=0
|
||||
ASSUME_YES=0
|
||||
|
||||
print_help() {
|
||||
cat <<EOF
|
||||
Usage: setup.sh [options]
|
||||
|
||||
Options:
|
||||
-p, --project-dir <name> Name of the project directory (default: supabase-project)
|
||||
--skip-deps Skip installation of system packages
|
||||
--with-aws Install the AWS CLI v2
|
||||
-y, --yes Non-interactive: accept defaults, no prompts
|
||||
-h, --help Show this help and exit
|
||||
EOF
|
||||
}
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
-p|--project-dir) PROJECT_DIR="$2"; shift 2 ;;
|
||||
--skip-deps) SKIP_DEPS=1; shift ;;
|
||||
--with-aws) WITH_AWS=1; shift ;;
|
||||
-y|--yes) ASSUME_YES=1; shift ;;
|
||||
-h|--help) print_help; exit 0 ;;
|
||||
*) echo "Unknown option: $1" >&2; print_help; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$(id -u)" = "0" ]; then
|
||||
SUDO=""
|
||||
else
|
||||
SUDO="sudo"
|
||||
fi
|
||||
|
||||
log() { printf "===> %s\n" "$*"; }
|
||||
warn() { printf "WARNING: %s\n" "$*" >&2; }
|
||||
die() { printf "ERROR: %s\n" "$*" >&2; exit 1; }
|
||||
|
||||
# Prompt with a default; echoes the chosen value on stdout.
|
||||
# Reads from /dev/tty so prompts work even when stdin is a pipe (curl | sh).
|
||||
# Falls back to the default with -y or when no controlling terminal exists.
|
||||
ask() {
|
||||
# ask <prompt> <default> -> echoes chosen value
|
||||
if [ "$ASSUME_YES" = "1" ] || ! { : > /dev/tty; } 2>/dev/null; then
|
||||
printf '%s' "$2"
|
||||
return
|
||||
fi
|
||||
printf "%s [%s]: " "$1" "$2" > /dev/tty
|
||||
read -r reply < /dev/tty
|
||||
[ -z "$reply" ] && reply="$2"
|
||||
printf '%s' "$reply"
|
||||
}
|
||||
|
||||
OS_FAMILY=""
|
||||
OS_ID=""
|
||||
OS_CODENAME=""
|
||||
|
||||
detect_os() {
|
||||
[ -f /etc/os-release ] || die "Cannot detect OS: /etc/os-release missing. Linux only."
|
||||
# shellcheck disable=SC1091
|
||||
. /etc/os-release
|
||||
OS_ID="$ID"
|
||||
OS_CODENAME="${VERSION_CODENAME:-}"
|
||||
case "$ID" in
|
||||
ubuntu|debian) OS_FAMILY="debian" ;;
|
||||
centos|rhel|fedora|rocky|almalinux|ol|amzn) OS_FAMILY="rhel" ;;
|
||||
*)
|
||||
case "${ID_LIKE:-}" in
|
||||
*debian*|*ubuntu*) OS_FAMILY="debian" ;;
|
||||
*rhel*|*fedora*|*centos*) OS_FAMILY="rhel" ;;
|
||||
*) die "Unsupported distribution: $ID" ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
log "Detected OS: $ID ($OS_FAMILY)"
|
||||
}
|
||||
|
||||
pkg_update() {
|
||||
if [ "$OS_FAMILY" = "debian" ]; then
|
||||
$SUDO apt-get update -qq -y
|
||||
else
|
||||
$SUDO dnf makecache -q -y || true
|
||||
fi
|
||||
}
|
||||
|
||||
pkg_install() {
|
||||
if [ "$OS_FAMILY" = "debian" ]; then
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
$SUDO apt-get install -qq -y "$@"
|
||||
else
|
||||
$SUDO dnf install -q -y "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
install_base_packages() {
|
||||
log "Installing base packages: git, curl, openssl, jq, ca-certificates"
|
||||
pkg_update
|
||||
if [ "$OS_FAMILY" = "debian" ]; then
|
||||
pkg_install git curl openssl jq ca-certificates \
|
||||
apt-transport-https gnupg lsb-release
|
||||
else
|
||||
pkg_install git curl openssl jq ca-certificates dnf-plugins-core
|
||||
fi
|
||||
}
|
||||
|
||||
docker_present() {
|
||||
command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1
|
||||
}
|
||||
|
||||
install_docker() {
|
||||
if docker_present; then
|
||||
log "Docker already installed: $(docker --version)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log "Installing Docker Engine and Compose plugin"
|
||||
if [ "$OS_FAMILY" = "debian" ]; then
|
||||
$SUDO install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL "https://download.docker.com/linux/${OS_ID}/gpg" \
|
||||
| $SUDO gpg --dearmor --yes -o /etc/apt/keyrings/docker.gpg
|
||||
$SUDO chmod a+r /etc/apt/keyrings/docker.gpg
|
||||
codename="${OS_CODENAME:-$(lsb_release -cs 2>/dev/null || echo stable)}"
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/${OS_ID} ${codename} stable" \
|
||||
| $SUDO tee /etc/apt/sources.list.d/docker.list >/dev/null
|
||||
$SUDO apt-get update -y
|
||||
pkg_install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
else
|
||||
repo_distro="centos"
|
||||
case "$OS_ID" in
|
||||
fedora) repo_distro="fedora" ;;
|
||||
rhel) repo_distro="rhel" ;;
|
||||
esac
|
||||
$SUDO dnf config-manager --add-repo "https://download.docker.com/linux/${repo_distro}/docker-ce.repo" 2>/dev/null \
|
||||
|| $SUDO dnf-3 config-manager --add-repo "https://download.docker.com/linux/${repo_distro}/docker-ce.repo"
|
||||
pkg_install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
fi
|
||||
|
||||
log "Enabling and starting docker service"
|
||||
$SUDO systemctl enable --now docker || warn "Could not enable docker via systemctl; start it manually."
|
||||
|
||||
docker_present || die "Docker installation finished but 'docker compose' is still unavailable."
|
||||
}
|
||||
|
||||
install_aws() {
|
||||
if command -v aws >/dev/null 2>&1; then
|
||||
log "AWS CLI already installed: $(aws --version 2>&1)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
arch=$(uname -m)
|
||||
case "$arch" in
|
||||
x86_64|amd64) aws_arch="x86_64" ;;
|
||||
aarch64|arm64) aws_arch="aarch64" ;;
|
||||
*) die "Unsupported architecture for AWS CLI: $arch" ;;
|
||||
esac
|
||||
|
||||
log "Installing AWS CLI v2 (${aws_arch})"
|
||||
command -v unzip >/dev/null 2>&1 || pkg_install unzip
|
||||
tmp=$(mktemp -d)
|
||||
(
|
||||
cd "$tmp"
|
||||
curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-${aws_arch}.zip" -o awscliv2.zip
|
||||
unzip -q -o awscliv2.zip
|
||||
$SUDO ./aws/install --bin-dir /usr/local/bin --install-dir /usr/local/aws-cli --update
|
||||
)
|
||||
rm -rf "$tmp"
|
||||
}
|
||||
|
||||
SRC_DIR=""
|
||||
SRC_TMP=""
|
||||
|
||||
prepare_source() {
|
||||
log "Sparse-cloning supabase repo"
|
||||
SRC_TMP=$(mktemp -d) || return 1
|
||||
git clone --filter=blob:none --no-checkout --depth=1 --quiet \
|
||||
https://github.com/supabase/supabase "$SRC_TMP/supabase" 2>/dev/null || \
|
||||
{ rm -rf "$SRC_TMP"; return 1; }
|
||||
|
||||
cd "$SRC_TMP/supabase" || { rm -rf "$SRC_TMP"; return 1; }
|
||||
git sparse-checkout init --cone && \
|
||||
git sparse-checkout set docker && \
|
||||
git checkout --quiet 2>/dev/null
|
||||
SRC_DIR="$PWD/docker"
|
||||
cd - > /dev/null
|
||||
}
|
||||
|
||||
cleanup_src_tmp() {
|
||||
if [ -n "$SRC_TMP" ] && [ -d "$SRC_TMP" ]; then
|
||||
rm -rf "$SRC_TMP"
|
||||
fi
|
||||
}
|
||||
trap cleanup_src_tmp EXIT
|
||||
|
||||
read_env() {
|
||||
grep "^$1=" .env 2>/dev/null | head -n1 | cut -d= -f2-
|
||||
}
|
||||
|
||||
# --- Main ---
|
||||
|
||||
log "Setup starting in $(pwd)"
|
||||
log "This may take several minutes..."
|
||||
|
||||
if [ "$SKIP_DEPS" = "1" ]; then
|
||||
log "Skipping system-package installation (--skip-deps)"
|
||||
else
|
||||
detect_os
|
||||
install_base_packages
|
||||
install_docker
|
||||
fi
|
||||
|
||||
if [ "$WITH_AWS" = "1" ]; then
|
||||
install_aws
|
||||
fi
|
||||
|
||||
# Idempotent re-run: if CWD is already a set-up project, skip bootstrap.
|
||||
# A clone has docker-compose.yml + utils/ but only .env.example;
|
||||
# a set-up project also has a real .env.
|
||||
if [ -f .env ] && [ -f docker-compose.yml ] && [ -d utils ]; then
|
||||
log "Already in a Supabase project directory; skipping bootstrap."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
prepare_source
|
||||
|
||||
target="$(pwd)/$PROJECT_DIR"
|
||||
if [ -e "$target" ]; then
|
||||
die "Target $target already exists. Pick a different name with --project-dir"
|
||||
fi
|
||||
|
||||
log "Creating project at $target"
|
||||
mkdir -p "$target"
|
||||
cp -rf "$SRC_DIR/." "$target/"
|
||||
if [ -f "$target/.env.example" ] && [ ! -f "$target/.env" ]; then
|
||||
cp "$target/.env.example" "$target/.env"
|
||||
fi
|
||||
|
||||
cd "$target"
|
||||
|
||||
current_public_url=$(read_env SUPABASE_PUBLIC_URL)
|
||||
current_api_url=$(read_env API_EXTERNAL_URL)
|
||||
current_site_url=$(read_env SITE_URL)
|
||||
|
||||
[ -z "$current_public_url" ] && current_public_url="http://localhost:8000"
|
||||
[ -z "$current_api_url" ] && current_api_url="$current_public_url"
|
||||
[ -z "$current_site_url" ] && current_site_url="http://localhost:3000"
|
||||
|
||||
if [ "$ASSUME_YES" = "1" ] || ! { : > /dev/tty; } 2>/dev/null; then
|
||||
log "Non-interactive: keeping default URLs (edit .env to change)"
|
||||
else
|
||||
echo ""
|
||||
echo "Configure the main URLs (press Enter to accept the default)."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
public_url=$(ask "SUPABASE_PUBLIC_URL (Studio + APIs)" "$current_public_url")
|
||||
api_url=$(ask "API_EXTERNAL_URL (Auth callbacks)" "$public_url")
|
||||
site_url=$(ask "SITE_URL (default Auth redirect)" "$current_site_url")
|
||||
|
||||
# Suggest PROXY_DOMAIN from the public_url host (unless it's localhost-ish)
|
||||
public_host=$(printf '%s' "$public_url" | sed -e 's|^https*://||' -e 's|/.*$||' -e 's|:.*$||')
|
||||
case "$public_host" in
|
||||
localhost|127.*|"") current_proxy_domain=$(read_env PROXY_DOMAIN) ;;
|
||||
*) current_proxy_domain="$public_host" ;;
|
||||
esac
|
||||
[ -z "$current_proxy_domain" ] && current_proxy_domain="your-domain.example.com"
|
||||
|
||||
proxy_domain=$(ask "PROXY_DOMAIN (for nginx/caddy HTTPS proxy)" "$current_proxy_domain")
|
||||
|
||||
# Derive CERTBOT_EMAIL = admin@<last-two-labels-of-proxy-domain>.
|
||||
# Naive: doesn't handle ccTLDs like .co.uk; user can edit .env after.
|
||||
domain_root=$(printf '%s' "$proxy_domain" | awk -F. 'NF>=2 { print $(NF-1)"."$NF; next } { print }')
|
||||
certbot_email="admin@${domain_root}"
|
||||
log "Setting CERTBOT_EMAIL=${certbot_email}"
|
||||
|
||||
sed -i.old \
|
||||
-e "s|^SUPABASE_PUBLIC_URL=.*$|SUPABASE_PUBLIC_URL=${public_url}|" \
|
||||
-e "s|^API_EXTERNAL_URL=.*$|API_EXTERNAL_URL=${api_url}|" \
|
||||
-e "s|^SITE_URL=.*$|SITE_URL=${site_url}|" \
|
||||
-e "s|^PROXY_DOMAIN=.*$|PROXY_DOMAIN=${proxy_domain}|" \
|
||||
-e "s|^CERTBOT_EMAIL=.*$|CERTBOT_EMAIL=${certbot_email}|" \
|
||||
.env
|
||||
rm -f .env.old
|
||||
|
||||
log "Generating secrets and legacy API keys"
|
||||
sh utils/generate-keys.sh --update-env
|
||||
|
||||
log "Generating asymmetric key pair and opaque API keys"
|
||||
sh utils/add-new-auth-keys.sh --update-env
|
||||
|
||||
log "Pulling Docker images"
|
||||
docker compose pull || warn "docker compose pull failed; you can retry later."
|
||||
|
||||
echo ""
|
||||
echo "Setup complete. Project ready at: $(pwd)"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " cd $(pwd)"
|
||||
echo " sh ./run.sh config"
|
||||
echo " sh ./run.sh secrets"
|
||||
echo " sh ./run.sh start"
|
||||
echo ""
|
||||
echo "To enable docker-compose overrides (pg17, envoy, caddy, nginx, rustfs, s3, logs):"
|
||||
echo " sh ./run.sh config add pg17"
|
||||
echo ""
|
||||
Reference in new issue
Block a user