Created
January 27, 2025 07:54
-
-
Save robertsinfosec/f26bd919ed0c896e55f22befccf0e5d6 to your computer and use it in GitHub Desktop.
Script to easily set up an instance of Supabase with a Reverse Proxy and FQDN.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Supabase Setup Script | |
# This script sets up a fresh machine with Supabase by asking configuration questions. | |
# This script will perform the following actions: | |
# 1. Install Docker and Docker Compose. | |
# 2. Create an unprivileged 'supabase' user with appropriate permissions. | |
# 3. Clone the Supabase repository into /opt/supabase/. | |
# 4. Configure environment variables with provided values. | |
# 5. Generate secure JWT keys for Supabase authentication. | |
# 6. Set up a systemd service to manage Supabase with start/stop capabilities. | |
# 7. Ensure correct file permissions and ownership. | |
# 8. Enable and start the Supabase service. | |
# Define color codes | |
Black='\033[0;30m' | |
DarkGray='\033[1;30m' | |
Red='\033[0;31m' | |
LightRed='\033[1;31m' | |
Green='\033[0;32m' | |
LightGreen='\033[1;32m' | |
Brown='\033[0;33m' | |
Yellow='\033[1;33m' | |
Blue='\033[0;34m' | |
LightBlue='\033[1;34m' | |
Purple='\033[0;35m' | |
LightPurple='\033[1;35m' | |
Cyan='\033[0;36m' | |
LightCyan='\033[1;36m' | |
LightGray='\033[0;37m' | |
White='\033[1;37m' | |
NC='\033[0m' # No Color | |
function setStatus(){ | |
description=$1 | |
severity=$2 | |
case "$severity" in | |
s) | |
echo -e "[${LightGreen}+${NC}] ${LightGreen}${description}${NC}" | |
;; | |
f) | |
echo -e "[${LightRed}-${NC}] ${LightRed}${description}${NC}" | |
;; | |
w) | |
echo -e "[${Brown}-${NC}] ${Brown}${description}${NC}" | |
;; | |
q) | |
echo -e "[${LightPurple}?${NC}] ${LightPurple}${description}${NC}" | |
;; | |
*) | |
echo -e "[${LightCyan}*${NC}] ${LightCyan}${description}${NC}" | |
;; | |
esac | |
} | |
function show_help() { | |
echo -e "${LightCyan}Supabase Setup Script${NC}" | |
echo "Usage: $0 [--install|--uninstall|--help]" | |
echo "" | |
echo "Options:" | |
echo " --install Install and configure Supabase." | |
echo " --uninstall Remove Supabase and all related configurations." | |
echo " --help Show this help message." | |
exit 0 | |
} | |
if [[ $EUID -ne 0 ]]; then | |
echo -e "${LightRed}[-] This script must be run as the root account or via sudo.${NC}" | |
exit 1 | |
fi | |
if [[ "$1" == "--help" ]]; then | |
show_help | |
elif [[ "$1" == "--uninstall" ]]; then | |
setStatus "Enter the FQDN of this host (e.g., supabase.example.com):" "q" | |
read DOMAIN_NAME | |
setStatus " - Stopping and disabling the 'supabase' service..." "*" | |
sudo systemctl stop supabase | |
sudo systemctl disable supabase | |
setStatus " - Removing /opt/supabase/ and /etc/systemd/system/supabase.service..." "*" | |
sudo rm -rf /opt/supabase | |
sudo rm -f /etc/systemd/system/supabase.service | |
sudo systemctl daemon-reload | |
setStatus " - Removing the 'supabase' user..." "*" | |
sudo userdel -r supabase | |
setStatus " - Removing Nginx Reverse Proxy..." "*" | |
rm /etc/nginx/sites-available/$DOMAIN_NAME | |
rm /etc/nginx/sites-enabled/$DOMAIN_NAME | |
systemctl restart nginx | |
setStatus "Supabase successfully uninstalled." "s" | |
exit 0 | |
elif [[ "$1" != "--install" ]]; then | |
echo -e "${LightRed}[-] Invalid option. Use --help for usage instructions.${NC}" | |
exit 1 | |
fi | |
function generate_random_string() { | |
openssl rand -base64 32 | tr -d '=+/' | cut -c1-32 | |
} | |
function generate_jwt_key() { | |
local ROLE=$1 | |
local IAT=$(date +%s) | |
local EXP=$((IAT + 157680000)) # 5 years later | |
echo -n '{"role":"'$ROLE'","iss":"supabase","iat":'$IAT',"exp":'$EXP'}' | openssl enc -base64 -A | |
} | |
function validate_passphrase() { | |
if [[ ${#1} -lt 32 ]]; then | |
setStatus "Password must be at least 32 characters long." "f" | |
return 1 | |
fi | |
return 0 | |
} | |
setStatus "Starting Supabase setup..." "*" | |
while true; do | |
# Prompt for the domain name | |
setStatus "Enter the FQDN of this host (e.g., supabase.example.com):" "q" | |
read DOMAIN_NAME | |
# Prompt for PostgreSQL password | |
setStatus "Enter your PostgreSQL password or <ENTER> to have one generated:" "q" | |
read -s POSTGRES_PASSWORD | |
if [[ "$POSTGRES_PASSWORD" == "" ]]; then | |
POSTGRES_PASSWORD=$(generate_random_string) | |
setStatus " - Generated a random PostgreSQL password." "s" | |
fi | |
validate_passphrase "$POSTGRES_PASSWORD" || continue | |
# Prompt for JWT secret | |
setStatus "Enter your >=32 character JWT secret or <ENTER> to have one generated:" "q" | |
read -s JWT_SECRET | |
if [[ "$JWT_SECRET" == "" ]]; then | |
JWT_SECRET=$(generate_random_string) | |
setStatus " - Generated a random JWT secret." "s" | |
fi | |
validate_passphrase "$JWT_SECRET" || continue | |
# Show user input and confirm | |
setStatus "Please review your input:" "*" | |
echo "" | |
echo -e "Domain...............: ${LightCyan}$DOMAIN_NAME${NC}" | |
echo -e "PostgreSQL Password..: ${LightCyan}[HIDDEN]${NC}" | |
echo -e "JWT Secret...........: ${LightCyan}[HIDDEN]${NC}" | |
echo "" | |
echo "This script will perform the following actions:" | |
echo "" | |
echo " 1. Install Docker and Docker Compose." | |
echo " 2. Create an unprivileged 'supabase' user with appropriate permissions." | |
echo " 3. Clone the Supabase repository into: /opt/supabase/." | |
echo " 4. Configure environment variables with provided values." | |
echo " 5. Generate secure JWT keys for Supabase authentication." | |
echo " 6. Set up a systemd service in /etc/systemd/system/supabase.service to manage Supabase with start/stop capabilities." | |
echo " 7. Ensure correct file permissions and ownership in /opt/supabase/." | |
echo " 8. Enable and start the Supabase service." | |
echo "" | |
setStatus "WARNING: Is this correct and do you want to continue? (Y to continue, R to restart, any other key to quit)" "q" | |
read -n 1 -s CONFIRMATION | |
echo "" | |
case "$CONFIRMATION" in | |
[Yy]) | |
break | |
;; | |
[Rr]) | |
continue | |
;; | |
*) | |
setStatus "Exiting setup." "f" | |
exit 1 | |
;; | |
esac | |
done | |
setStatus "Installing required dependencies..." "*" | |
sudo apt update | |
sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release git nginx certbot python3-certbot-nginx | |
setStatus "Adding Docker GPG key and repository..." "*" | |
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg | |
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null | |
setStatus "Installing Docker and Docker Compose..." "*" | |
sudo apt update | |
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin | |
setStatus " - Done." "s" | |
setStatus "Creating 'supabase' user..." "*" | |
if id "supabase" &>/dev/null; then | |
setStatus " - User 'supabase' already exists." "w" | |
else | |
sudo useradd -m -s /bin/bash supabase | |
sudo usermod -aG docker supabase | |
echo "supabase ALL=(ALL) NOPASSWD: /bin/systemctl start supabase, /bin/systemctl stop supabase, /bin/systemctl restart supabase" | sudo tee /etc/sudoers.d/supabase | |
setStatus " - User 'supabase' created and configured." "s" | |
fi | |
setStatus "Cloning Supabase repository to /opt/supabase/..." "*" | |
sudo git clone --depth 1 https://github.com/supabase/supabase /opt/supabase | |
cp /opt/supabase/docker/.env.example /opt/supabase/docker/.env | |
setStatus " - Done." "s" | |
setStatus "Setting folder persmissions and ownership for /opt/supabase/" "*" | |
sudo chown -R supabase:supabase /opt/supabase | |
sudo chmod -R 770 /opt/supabase | |
setStatus " - Done." "s" | |
setStatus "Setting up systemd service..." "*" | |
echo "[Unit] | |
Description=Supabase Service | |
After=network.target | |
[Service] | |
User=supabase | |
WorkingDirectory=/opt/supabase/docker | |
ExecStart=/usr/bin/docker compose up -d | |
ExecStop=/usr/bin/docker compose down | |
User=supabase | |
Restart=always | |
[Install] | |
WantedBy=multi-user.target" | sudo tee /etc/systemd/system/supabase.service | |
setStatus " - Done." "s" | |
setStatus "Reloading Systemd and setting 'supabase' to start on book, and start now..." "*" | |
sudo systemctl daemon-reload | |
sudo systemctl enable supabase | |
sudo systemctl start supabase | |
setStatus " - Done." "s" | |
setStatus "Setting up NGinx Reverse Proxy..." "*" | |
echo "server { | |
listen 80 | |
server_name $DOMAIN_NAME; | |
resolver 127.0.0.53 valid=30s; | |
set \$upstream_backend http://localhost:8000; | |
set \$upstream_frontend http://localhost:3000; | |
location /rest/v1/ { | |
proxy_pass \$upstream_backend; | |
} | |
location /auth/v1/ { | |
proxy_pass \$upstream_backend; | |
} | |
location /realtime/v1/ { | |
proxy_pass \$upstream_backend; | |
} | |
location /storage/v1/ { | |
proxy_pass \$upstream_backend; | |
} | |
location / { | |
proxy_pass \$upstream_frontend; | |
} | |
# Set headers globally for all proxy_pass requests | |
proxy_set_header Host \$host; | |
proxy_set_header X-Real-IP \$remote_addr; | |
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; | |
proxy_set_header X-Forwarded-Proto \$scheme; | |
}" | sudo tee /etc/nginx/sites-available/$DOMAIN_NAME | |
ln -s /etc/nginx/sites-available/$DOMAIN_NAME /etc/nginx/sites-enabled/$DOMAIN_NAME | |
systemctl enable nginx | |
systemctl start nginx | |
setStatus " - Done." "s" | |
setStatus "Generating new ANON and SERVICE keys..." "*" | |
ANON_KEY=$(generate_jwt_key "anon") | |
SERVICE_KEY=$(generate_jwt_key "service_role") | |
setStatus " - Done." "s" | |
setStatus "Replacing values in the .env file..." "*" | |
sudo sed -i "s|YOUR_POSTGRES_PASSWORD|$POSTGRES_PASSWORD|g" /opt/supabase/docker/.env | |
sudo sed -i "s|YOUR_JWT_SECRET|$JWT_SECRET|g" /opt/supabase/docker/.env | |
sudo sed -i "s|YOUR_ANON_KEY|$ANON_KEY|g" /opt/supabase/docker/.env | |
sudo sed -i "s|YOUR_SERVICE_KEY|$SERVICE_KEY|g" /opt/supabase/docker/.env | |
sudo sed -i "s|YOUR_DOMAIN|$DOMAIN_NAME|g" /opt/supabase/docker/.env | |
sudo sed -i "s|YOUR_API_EXTERNAL_URL|https://$DOMAIN_NAME|g" /opt/supabase/docker/.env | |
sudo sed -i "s|YOUR_SUPABASE_PUBLIC_URL|https://$DOMAIN_NAME|g" /opt/supabase/docker/.env | |
sudo sed -i "s|YOUR_SITE_URL|https://$DOMAIN_NAME|g" /opt/supabase/docker/.env | |
setStatus " - Done." "s" | |
setStatus "Supabase setup complete. Access it at https://$DOMAIN_NAME" "s" | |
echo "" | |
echo "For client access, your keys are below:" | |
echo "" | |
echo " - ANON Key......: $ANON_KEY" | |
echo " - SERVICE Key...: $SERVICE_KEY" | |
echo "" | |
echo "These are also available in /opt/supabase/docker/.env" | |
echo "" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment