├── .gitignore ├── LICENSE ├── README.md ├── supabase.sh └── volumes ├── api └── kong.yml └── db └── init ├── 00-initial-schema.sql ├── 01-auth-schema.sql ├── 02-storage-schema.sql └── 03-post-setup.sql /.gitignore: -------------------------------------------------------------------------------- 1 | volumes/db/data 2 | volumes/db/init/data.sql 3 | volumes/storage 4 | .env -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Christopher Talke 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Supabase Docker Script 2 | -------------------------------------------------------------------------------- /supabase.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ########################################################################## 4 | # Control Flags 5 | ########################################################################## 6 | 7 | flag=$1 8 | 9 | ########################################################################## 10 | # Global Variables 11 | ########################################################################## 12 | RED="\u001b[31;1m" 13 | GREEN="\033[0;32m" 14 | NC="\033[0m" 15 | 16 | if [ -x "$(command -v docker)" ]; then 17 | 18 | ########################################################################## 19 | # Fancy logo Stuff 20 | ########################################################################## 21 | echo -e "....................${GREEN}.${NC}...................."; 22 | echo -e "..................${GREEN},ol${NC}...................."; 23 | echo -e ".................${GREEN}:dxl${NC}...................."; 24 | echo -e "...............${GREEN},lxxxl${NC}...................."; 25 | echo -e "..............${GREEN}:dxxxxl${NC}...................."; 26 | echo -e ".............${GREEN}lxxxxxxo${NC}...................."; 27 | echo -e "...........${GREEN}:dxxxxxxxl${NC}....${GREEN}SUPABASE${NC}........"; 28 | echo -e "..........${GREEN}lxxxxxxxxxl${NC}...................."; 29 | echo -e "........${GREEN};oxxxxxxxxxxo${NC}...................."; 30 | echo -e ".......${GREEN}ldxxxxxxxxxxxdc:ccclllooodddxxl${NC}..."; 31 | echo -e ".....${GREEN};oxxxxxxxxxxxxxdc:cclllooodddddc${NC}...."; 32 | echo -e "....${GREEN}cdxxxxxxxxxxxxxxdlccllloooodddo;${NC}....."; 33 | echo -e "...${GREEN}llllllllllllllllccclllooooddddc${NC}......."; 34 | echo -e ".....................${GREEN}:lllloooddo;${NC}........"; 35 | echo -e ".....................${GREEN}:llloooodc${NC}.........."; 36 | echo -e ".....................${GREEN}:llooooo;${NC}..........."; 37 | echo -e ".....................${GREEN}:lloooc${NC}............."; 38 | echo -e ".....................${GREEN}:oool;${NC}.............."; 39 | echo -e ".....................${GREEN}:ooc${NC}................"; 40 | echo -e ".....................${GREEN}cl;${NC}................."; 41 | echo -e ".....................${GREEN},${NC}..................."; 42 | 43 | echo -e ""; 44 | echo -e "${GREEN}Lets get started, We just need a few details from you${NC} "; 45 | 46 | ########################################################################## 47 | # Installation Directory 48 | ########################################################################## 49 | echo -e ""; 50 | read -p "1. Enter an installation directory (Default: /home/%username%/DEPLOY/supabase) ${RED}[Required]${NC}: " SCRIPT_DIR 51 | if [ -z "$SCRIPT_DIR" ] 52 | then 53 | while [[ -z "$SCRIPT_DIR" ]]; do 54 | read -p "$(echo -e " You forgot to an installation directory: ")" SCRIPT_DIR 55 | done 56 | fi 57 | 58 | ########################################################################## 59 | # Postgres Database Password 60 | ########################################################################## 61 | read -sp "2. Enter a password for your Postgres Database (If left blank, it will be autogenerated): " POSTGRES_PASSWORD 62 | 63 | ########################################################################## 64 | # JWT Secret (Will be used to sign Anon Role and Service Role keys) 65 | ########################################################################## 66 | echo -e ""; 67 | read -sp "3. Enter a JWT Secret to be used by Supabase (If left blank, it will be autogenerated): " JWT_SECRET 68 | 69 | ########################################################################## 70 | # SUPABASE URL (STUDIO, POSTGRES, KONG ETC) 71 | ########################################################################## 72 | echo -e ""; 73 | read -p "$(echo -e "4. Enter the domain you will use to access Supabase Studio ${RED}[Required]${NC}: https://")" domain 74 | if [ -z "$domain" ] 75 | then 76 | while [[ -z "$domain" ]]; do 77 | read -p "$(echo -e " You forgot to pick a domain for your Supabase instance, try again ${RED}[Required]${NC}: https://")" domain 78 | done 79 | fi 80 | 81 | ########################################################################## 82 | # EMAIL SIGN UPS 83 | ########################################################################## 84 | read -p "$(echo -e "5. Do you wish to enable Email Signups? ${RED}[You will require a custom SMTP Server]${NC} [y/n]: ")" enable_email_signup 85 | if [[ $enable_email_signup == "Y" || $enable_email_signup == "y" ]] 86 | then 87 | enable_email_signup=true 88 | 89 | ########################################################################## 90 | # EMAIL AUTO CONFIRMATION 91 | ########################################################################## 92 | read -p "$(echo -e " Do you wish to enable Email Auto Confirmation? [Y/N]: ")" ENABLE_EMAIL_AUTOCONFIRM 93 | if [[ -z "$ENABLE_EMAIL_AUTOCONFIRM" || ENABLE_EMAIL_AUTOCONFIRM == "n" || ENABLE_EMAIL_AUTOCONFIRM == "N" ]] 94 | then 95 | ENABLE_EMAIL_AUTOCONFIRM="false" 96 | else 97 | ENABLE_EMAIL_AUTOCONFIRM="true" 98 | fi 99 | 100 | ########################################################################## 101 | # SMTP HOST 102 | ########################################################################## 103 | read -p "$(echo -e " Enter your SMTP Host: ")" SMTP_HOST 104 | if [ -z "$SMTP_HOST" ] 105 | then 106 | while [[ -z "$SMTP_HOST" ]]; do 107 | read -p "$(echo -e " ${RED}Invalid input, try again:${NC} ")" SMTP_HOST 108 | done 109 | fi 110 | 111 | ########################################################################## 112 | # SMTP PORT 113 | ########################################################################## 114 | read -p "$(echo -e " Enter your SMTP Port: ")" SMTP_PORT 115 | if [ -z "$SMTP_PORT" ] 116 | then 117 | while [[ -z "$SMTP_PORT" ]]; do 118 | read -p "$(echo -e " ${RED}Invalid input, try again:${NC} ")" SMTP_PORT 119 | done 120 | fi 121 | 122 | ########################################################################## 123 | # SMTP USERNAME 124 | ########################################################################## 125 | read -p "$(echo -e " Enter your SMTP Username: ")" SMTP_USER 126 | if [ -z "$SMTP_USER" ] 127 | then 128 | while [[ -z "$SMTP_USER" ]]; do 129 | read -p "$(echo -e " ${RED}Invalid input, try again:${NC} ")" SMTP_USER 130 | done 131 | fi 132 | 133 | ########################################################################## 134 | # SMTP PASSWORD 135 | ########################################################################## 136 | read -p "$(echo -e " Enter your SMTP Password: ")" SMTP_PASS 137 | if [ -z "$SMTP_PASS" ] 138 | then 139 | while [[ -z "$SMTP_PASS" ]]; do 140 | read -p "$(echo -e " ${RED}Invalid input, try again:${NC} ")" SMTP_PASS 141 | done 142 | fi 143 | 144 | ########################################################################## 145 | # SMTP SENDER EMAIL 146 | ########################################################################## 147 | read -p "$(echo -e " Enter your SMTP Sender Name: ")" smtp_sender 148 | if [ -z "$smtp_sender" ] 149 | then 150 | while [[ -z "$smtp_sender" ]]; do 151 | read -p "$(echo -e " ${RED}Invalid input, try again:${NC} ")" smtp_sender 152 | done 153 | fi 154 | else 155 | ENABLE_EMAIL_SIGNUP=false 156 | ENABLE_EMAIL_AUTOCONFIRM=false 157 | SMTP_ADMIN_EMAIL=some-fake-email 158 | SMTP_HOST=some-fake-host 159 | SMTP_PORT=1337 160 | SMTP_USER=some-fake-email 161 | SMTP_PASS=some-fake-password 162 | SMTP_SENDER_NAME=noreply 163 | fi 164 | 165 | ########################################################################## 166 | # Generate random password if blank 167 | ########################################################################## 168 | if [ -z "$POSTGRES_PASSWORD" ] 169 | then 170 | POSTGRES_PASSWORD=`cat /dev/urandom | tr -dc "a-zA-Z0-9!@#\-$%^&_" | fold -w 64 | head -n 1` 171 | fi 172 | 173 | ########################################################################## 174 | # Generate random JWT_SECRET if blank 175 | ########################################################################## 176 | if [ -z "$JWT_SECRET" ] 177 | then 178 | JWT_SECRET=`cat /dev/urandom | tr -dc "a-zA-Z0-9!@#\-$%^&" | fold -w 64 | head -n 1` 179 | fi 180 | 181 | ########################################################################## 182 | # Default Variables: GO TRUE 183 | ########################################################################## 184 | SITE_URL="http://localhost:3000" 185 | ADDITIONAL_REDIRECT_URLS= 186 | JWT_EXPIRY=3600 187 | DISABLE_SIGNUP=false 188 | ENABLE_PHONE_SIGNUP=false 189 | ENABLE_PHONE_AUTOCONFIRM=false 190 | 191 | ########################################################################## 192 | # Default Variables: Ports 193 | ########################################################################## 194 | STUDIO_PORT=3000 195 | KONG_HTTP_PORT=8000 196 | KONG_HTTPS_PORT=8443 197 | POSTGRES_PORT=5432 198 | 199 | ########################################################################## 200 | # Default Variables: Postgres Defaults 201 | ########################################################################## 202 | POSTGRES_USER="postgres" 203 | POSTGRES_DB="supabase" 204 | 205 | ########################################################################## 206 | # GENERATE ANON & SERVICE ROLE JWT KEYS 207 | ########################################################################## 208 | base64_encode() { 209 | declare input=${1:-$(> /dev/null 247 | fi 248 | 249 | if [[ ! -d "${SCRIPT_DIR}/volumes/db" && ! -d "${SCRIPT_DIR}/volumes/api" ]] 250 | then 251 | mkdir -p "${SCRIPT_DIR}/volumes/db/init" >> /dev/null 252 | curl -s "https://raw.githubusercontent.com/christopher-talke/docker-cli-supabase/main/volumes/db/init/00-initial-schema.sql" > "${SCRIPT_DIR}/volumes/db/init/00-initial-schema.sql" 253 | curl -s "https://raw.githubusercontent.com/christopher-talke/docker-cli-supabase/main/volumes/db/init/01-auth-schema.sql" > "${SCRIPT_DIR}/volumes/db/init/01-auth-schema.sql" 254 | curl -s "https://raw.githubusercontent.com/christopher-talke/docker-cli-supabase/main/volumes/db/init/02-storage-schema.sql" > "${SCRIPT_DIR}/volumes/db/init/02-storage-schema.sql" 255 | curl -s "https://raw.githubusercontent.com/christopher-talke/docker-cli-supabase/main/volumes/db/init/03-post-setup.sql" > "${SCRIPT_DIR}/volumes/db/init/03-post-setup.sql" 256 | 257 | mkdir -p "${SCRIPT_DIR}/volumes/api" >> /dev/null 258 | curl -s "https://raw.githubusercontent.com/christopher-talke/docker-cli-supabase/main/volumes/api/kong.yml" > "${SCRIPT_DIR}/volumes/api/kong.yml" 259 | fi 260 | 261 | sed -i "s/anon-role-replace/${ANON_KEY}/" "${SCRIPT_DIR}/volumes/api/kong.yml" >> /dev/null 262 | sed -i "s/service-role-replace/${SERVICE_ROLE_KEY}/" "${SCRIPT_DIR}/volumes/api/kong.yml" >> /dev/null 263 | 264 | #################################################################################################################################################### 265 | # Start Of Docker Processing 266 | #################################################################################################################################################### 267 | 268 | echo "" 269 | if [[ $flag == '--reset' ]] 270 | then 271 | echo ">>> Starting cleanup process" 272 | echo ">>>>>> Removing docker containers from supabase-network..." 273 | docker network disconnect $NETWORK_NAME supabase-meta &> /dev/null 274 | docker network disconnect $NETWORK_NAME supabase-storage &> /dev/null 275 | docker network disconnect $NETWORK_NAME supabase-rest &> /dev/null 276 | docker network disconnect $NETWORK_NAME supabase-auth &> /dev/null 277 | docker network disconnect $NETWORK_NAME supabase-studio &> /dev/null 278 | docker network disconnect $NETWORK_NAME supabase-db &> /dev/null 279 | 280 | echo ">>>>>> Removing supabase-network..." 281 | docker network rm $NETWORK_NAME &> /dev/null 282 | 283 | echo ">>>>>> Cleaning up existing docker containers..." 284 | docker rm -f supabase-meta &> /dev/null && 285 | docker rm -f supabase-storage &> /dev/null && 286 | docker rm -f supabase-rest &> /dev/null && 287 | docker rm -f supabase-auth &> /dev/null && 288 | docker rm -f supabase-studio &> /dev/null && 289 | docker rm -f supabase-realtime &> /dev/null && 290 | docker rm -f supabase-db &> /dev/null 291 | 292 | echo ">>>>>> All cleaned up..." 293 | fi 294 | 295 | # Docker Network 296 | NETWORK_NAME="supabase-network" 297 | 298 | echo "" 299 | echo ">>> Creating Network '$NETWORK_NAME'..." 300 | docker network rm $NETWORK_NAME &> /dev/null 301 | docker network create $NETWORK_NAME &> /dev/null 302 | echo ">>>>>> Network Created!" 303 | echo "" 304 | 305 | # Database Service 306 | DB_CONTAINER_NAME="supabase-db" 307 | 308 | echo ">>> Creating Postgres Database '$DB_CONTAINER_NAME'..." 309 | docker stop $DB_CONTAINER_NAME &> /dev/null 310 | docker kill $DB_CONTAINER_NAME &> /dev/null 311 | docker rm $DB_CONTAINER_NAME &> /dev/null 312 | 313 | docker run -d \ 314 | --name=$DB_CONTAINER_NAME \ 315 | -e POSTGRES_PASSWORD=$POSTGRES_PASSWORD \ 316 | -e POSTGRES_USER=$POSTGRES_USER \ 317 | -e POSTGRES_DB=$POSTGRES_DB \ 318 | -v ${SCRIPT_DIR}/volumes/db/data:/var/lib/postgresql/data \ 319 | -v ${SCRIPT_DIR}/volumes/db/init:/docker-entrypoint-initdb.d \ 320 | -p 5432:5432 \ 321 | --restart unless-stopped \ 322 | --network $NETWORK_NAME \ 323 | supabase/postgres:latest &> /dev/null 324 | 325 | echo ">>>>>> Waiting for database to finish setting itself up..." 326 | sleep 120 327 | echo ">>>>>> Excuting some commands against the database... gimme a sec..." 328 | sleep 30 329 | docker exec -u root $DB_CONTAINER_NAME bash -c 'su postgres -c postgres -c config_file=/etc/postgresql/postgresql.conf' &> /dev/null 330 | echo ">>>>>> Finished setting up database!" 331 | 332 | 333 | # Studio Service 334 | STUDIO_CONTAINER_NAME="supabase-studio" 335 | 336 | echo "" 337 | echo ">>> Creating Web UI for Supabase '$STUDIO_CONTAINER_NAME'..." 338 | docker stop $STUDIO_CONTAINER_NAME &> /dev/null 339 | docker kill $STUDIO_CONTAINER_NAME &> /dev/null 340 | docker rm $STUDIO_CONTAINER_NAME &> /dev/null 341 | 342 | docker run -d \ 343 | --name=$STUDIO_CONTAINER_NAME \ 344 | -e SUPABASE_URL="https://supabase.talke.dev" \ 345 | -e STUDIO_PG_META_URL="http://supabase-meta:8080" \ 346 | -e SUPABASE_ANON_KEY=$ANON_KEY \ 347 | -e SUPABASE_SERVICE_KEY=$SERVICE_ROLE_KEY \ 348 | -p 3000:3000 \ 349 | --restart unless-stopped \ 350 | --network $NETWORK_NAME \ 351 | supabase/studio:latest &> /dev/null 352 | echo ">>>>>> Finished setting up Web UI!" 353 | 354 | # Kong Service 355 | KONG_CONTAINER_NAME="supabase-kong" 356 | 357 | docker stop $KONG_CONTAINER_NAME &> /dev/null 358 | docker kill $KONG_CONTAINER_NAME &> /dev/null 359 | docker rm $KONG_CONTAINER_NAME &> /dev/null 360 | 361 | echo "" 362 | echo ">>> Creating API Gateway '$KONG_CONTAINER_NAME'..." 363 | docker run -d \ 364 | --name=$KONG_CONTAINER_NAME \ 365 | -e KONG_DATABASE="off" \ 366 | -e KONG_DECLARATIVE_CONFIG="/var/lib/kong/kong.yml" \ 367 | -e KONG_DNS_ORDER="LAST,A,CNAME" \ 368 | -e KONG_PLUGINS="request-transformer,cors,key-auth,acl" \ 369 | -v ${SCRIPT_DIR}/volumes/api/kong.yml:/var/lib/kong/kong.yml \ 370 | -p 8000:8000 \ 371 | -p 8443:8443 \ 372 | --restart unless-stopped \ 373 | --network $NETWORK_NAME \ 374 | kong:latest &> /dev/null 375 | echo ">>>>>> Finished setting up API Gateway!" 376 | 377 | # Auth Service 378 | AUTH_CONTAINER_NAME="supabase-auth" 379 | 380 | docker stop $AUTH_CONTAINER_NAME &> /dev/null 381 | docker kill $AUTH_CONTAINER_NAME &> /dev/null 382 | docker rm $AUTH_CONTAINER_NAME &> /dev/null 383 | 384 | echo "" 385 | echo ">>> Creating Authentication Service '$AUTH_CONTAINER_NAME'..." 386 | docker run -d \ 387 | --name=$AUTH_CONTAINER_NAME \ 388 | -e GOTRUE_API_HOST=0.0.0.0 \ 389 | -e GOTRUE_API_PORT=9999 \ 390 | -e GOTRUE_DB_DRIVER="postgres" \ 391 | -e GOTRUE_DB_DATABASE_URL="postgres://$POSTGRES_USER:$POSTGRES_PASSWORD@supabase-db:5432/$POSTGRES_DB?search_path=auth" \ 392 | -e GOTRUE_SITE_URL=$SITE_URL \ 393 | -e GOTRUE_URI_ALLOW_LIST=$ADDITIONAL_REDIRECT_URLS \ 394 | -e GOTRUE_DISABLE_SIGNUP=$DISABLE_SIGNUP \ 395 | -e GOTRUE_JWT_SECRET=$JWT_SECRET \ 396 | -e GOTRUE_JWT_EXP=$JWT_EXPIRY \ 397 | -e GOTRUE_JWT_DEFAULT_GROUP_NAME="authenticated" \ 398 | -e GOTRUE_EXTERNAL_EMAIL_ENABLED=$ENABLE_EMAIL_SIGNUP \ 399 | -e GOTRUE_MAILER_AUTOCONFIRM=$ENABLE_EMAIL_AUTOCONFIRM \ 400 | -e GOTRUE_SMTP_ADMIN_EMAIL=$SMTP_ADMIN_EMAIL \ 401 | -e GOTRUE_SMTP_HOST=$SMTP_HOST \ 402 | -e GOTRUE_SMTP_PORT=$SMTP_PORT \ 403 | -e GOTRUE_SMTP_USER=$SMTP_USER \ 404 | -e GOTRUE_SMTP_PASS=$SMTP_PASS \ 405 | -e GOTRUE_SMTP_SENDER_NAME=$SMTP_SENDER_NAME \ 406 | -e GOTRUE_MAILER_URLPATHS_INVITE="/auth/v1/verify" \ 407 | -e GOTRUE_MAILER_URLPATHS_CONFIRMATION="/auth/v1/verify" \ 408 | -e GOTRUE_MAILER_URLPATHS_RECOVERY="/auth/v1/verify" \ 409 | -e GOTRUE_MAILER_URLPATHS_EMAIL_CHANGE="/auth/v1/verify" \ 410 | -e GOTRUE_EXTERNAL_PHONE_ENABLED=$ENABLE_PHONE_SIGNUP \ 411 | -e GOTRUE_SMS_AUTOCONFIRM=$ENABLE_PHONE_AUTOCONFIRM \ 412 | --restart unless-stopped \ 413 | --network $NETWORK_NAME \ 414 | supabase/gotrue:latest &> /dev/null 415 | echo ">>>>>> Finished setting up Authentication Service!" 416 | 417 | 418 | # Auth Service 419 | REST_CONTAINER_NAME="supabase-rest" 420 | 421 | docker stop $REST_CONTAINER_NAME &> /dev/null 422 | docker kill $REST_CONTAINER_NAME &> /dev/null 423 | docker rm $REST_CONTAINER_NAME &> /dev/null 424 | 425 | echo "" 426 | echo ">>> Creating REST API '$REST_CONTAINER_NAME'..." 427 | docker run -d \ 428 | --name=$REST_CONTAINER_NAME \ 429 | -e PGRST_DB_URI="postgres://$POSTGRES_USER:$POSTGRES_PASSWORD@supabase-db:5432/$POSTGRES_DB" \ 430 | -e PGRST_DB_SCHEMA="public,storage" \ 431 | -e PGRST_DB_ANON_ROLE="anon" \ 432 | -e PGRST_JWT_SECRET=$JWT_SECRET \ 433 | -e PGRST_DB_USE_LEGACY_GUCS="false" \ 434 | --restart unless-stopped \ 435 | --network $NETWORK_NAME \ 436 | postgrest/postgrest:latest &> /dev/null 437 | echo ">>>>>> Finished setting up REST API!" 438 | 439 | # Realtime Service 440 | REALTIME_CONTAINER_NAME="supabase-realtime" 441 | 442 | docker stop $REALTIME_CONTAINER_NAME &> /dev/null 443 | docker kill $REALTIME_CONTAINER_NAME &> /dev/null 444 | docker rm $REALTIME_CONTAINER_NAME &> /dev/null 445 | 446 | echo "" 447 | echo ">>> Creating Realtime Service '$REALTIME_CONTAINER_NAME'..." 448 | docker run -d \ 449 | --name=$REALTIME_CONTAINER_NAME \ 450 | -e DB_HOST="supabase-db" \ 451 | -e DB_PORT=5432 \ 452 | -e DB_NAME=$POSTGRES_DB \ 453 | -e DB_USER=$POSTGRES_USER \ 454 | -e DB_PASSWORD=$POSTGRES_PASSWORD \ 455 | -e DB_SSL="false" \ 456 | -e PORT=4000 \ 457 | -e JWT_SECRET=$JWT_SECRET \ 458 | -e REPLICATION_MODE="RLS" \ 459 | -e REPLICATION_POLL_INTERVAL=100 \ 460 | -e SECURE_CHANNELS="true" \ 461 | -e SLOT_NAME="supabase_realtime_rls" \ 462 | -e TEMPORARY_SLOT="true" \ 463 | --restart unless-stopped \ 464 | --network $NETWORK_NAME \ 465 | supabase/realtime:latest &> /dev/null 466 | echo ">>>>>> Finished setting up Realtime Service!" 467 | echo ">>>>>> Excuting some commands against the database... gimme a sec..." 468 | sleep 30 469 | docker exec $REALTIME_CONTAINER_NAME bash -c './prod/rel/realtime/bin/realtime eval Realtime.Release.migrate && ./prod/rel/realtime/bin/realtime start' &> /dev/null 470 | echo ">>>>>> Finished setting up database!" 471 | 472 | # Storage Service 473 | STORAGE_CONTAINER_NAME="supabase-storage" 474 | 475 | docker stop $STORAGE_CONTAINER_NAME &> /dev/null 476 | docker kill $STORAGE_CONTAINER_NAME &> /dev/null 477 | docker rm $STORAGE_CONTAINER_NAME &> /dev/null 478 | 479 | echo "" 480 | echo ">>> Creating Storage Service '$STORAGE_CONTAINER_NAME'..." 481 | docker run -d \ 482 | --name=$STORAGE_CONTAINER_NAME \ 483 | -e ANON_KEY=$ANON_KEY \ 484 | -e SERVICE_KEY=$SERVICE_ROLE_KEY \ 485 | -e POSTGREST_URL="http://supabase-rest:3000" \ 486 | -e PGRST_JWT_SECRET=$JWT_SECRET \ 487 | -e DATABASE_URL="postgres://$POSTGRES_USER:$POSTGRES_PASSWORD@supabase-db:5432/$POSTGRES_DB" \ 488 | -e PGOPTIONS="-c search_path=storage,public" \ 489 | -e FILE_SIZE_LIMIT=52428800 \ 490 | -e STORAGE_BACKEND="file" \ 491 | -e FILE_STORAGE_BACKEND_PATH="/var/lib/storage" \ 492 | -e TENANT_ID="stub" \ 493 | -e REGION="stub" \ 494 | -e GLOBAL_S3_BUCKET="stub" \ 495 | --restart unless-stopped \ 496 | --network $NETWORK_NAME \ 497 | -v ${SCRIPT_DIR}/volumes/storage:/var/lib/storage \ 498 | supabase/storage-api:latest &> /dev/null 499 | echo ">>>>>> Finished setting up Storage Service!" 500 | 501 | # Meta Service 502 | META_CONTAINER_NAME="supabase-meta" 503 | 504 | docker stop $META_CONTAINER_NAME &> /dev/null 505 | docker kill $META_CONTAINER_NAME &> /dev/null 506 | docker rm $META_CONTAINER_NAME &> /dev/null 507 | 508 | echo "" 509 | echo ">>> Creating Meta Service '$META_CONTAINER_NAME'..." 510 | docker run -d \ 511 | --name=$META_CONTAINER_NAME \ 512 | -e PG_META_PORT=8080 \ 513 | -e PG_META_DB_HOST="supabase-db" \ 514 | -e PG_META_DB_PASSWORD=$POSTGRES_PASSWORD \ 515 | --restart unless-stopped \ 516 | --network $NETWORK_NAME \ 517 | -v ${SCRIPT_DIR}/volumes/storage:/var/lib/storage \ 518 | supabase/postgres-meta:latest &> /dev/null 519 | echo ">>>>>> Finished setting up Meta Service!" 520 | 521 | #################################################################################################################################################### 522 | # End Of Docker Processing 523 | #################################################################################################################################################### 524 | 525 | ########################################################################## 526 | # Final output 527 | ########################################################################## 528 | 529 | echo -e ""; 530 | echo -e "---------------------------------------------------------------------------"; 531 | echo -e "${GREEN}All set you are ready to go! See below for your Supabase details:${NC}"; 532 | echo -e ""; 533 | echo -e "Postgres Password: ${POSTGRES_PASSWORD}"; 534 | echo -e "JWT Secret: ${JWT_SECRET}"; 535 | echo -e "Supabase URL: https://${domain}"; 536 | echo -e "Postgres URL: postgres://${domain}:5432"; 537 | echo -e ""; 538 | echo -e "${RED}[Please keep this information somewhere safe]${NC}"; 539 | echo -e "---------------------------------------------------------------------------"; 540 | 541 | ########################################################################## 542 | # Error Output for Docker Check 543 | ########################################################################## 544 | 545 | else 546 | echo -e ""; 547 | echo -e "---------------------------------------------------------------------------"; 548 | echo -e "${RED}[Error]${NC}"; 549 | echo -e "Install Docker: https://docs.docker.com/engine/install/"; 550 | echo -e "---------------------------------------------------------------------------"; 551 | fi -------------------------------------------------------------------------------- /volumes/api/kong.yml: -------------------------------------------------------------------------------- 1 | _format_version: '1.1' 2 | 3 | ### 4 | ### Consumers / Users 5 | ### 6 | consumers: 7 | - username: anon 8 | keyauth_credentials: 9 | - key: anon-role-replace 10 | - username: service_role 11 | keyauth_credentials: 12 | - key: service-role-replace 13 | 14 | ### 15 | ### Access Control List 16 | ### 17 | acls: 18 | - consumer: anon 19 | group: anon 20 | - consumer: service_role 21 | group: admin 22 | 23 | ### 24 | ### API Routes 25 | ### 26 | services: 27 | ## Open Auth routes 28 | - name: auth-v1-open 29 | url: http://supabase-auth:9999/verify 30 | routes: 31 | - name: auth-v1-open 32 | strip_path: true 33 | paths: 34 | - /auth/v1/verify 35 | plugins: 36 | - name: cors 37 | - name: auth-v1-open-callback 38 | url: http://supabase-auth:9999/callback 39 | routes: 40 | - name: auth-v1-open-callback 41 | strip_path: true 42 | paths: 43 | - /auth/v1/callback 44 | plugins: 45 | - name: cors 46 | - name: auth-v1-open-authorize 47 | url: http://supabase-auth:9999/authorize 48 | routes: 49 | - name: auth-v1-open-authorize 50 | strip_path: true 51 | paths: 52 | - /auth/v1/authorize 53 | plugins: 54 | - name: cors 55 | 56 | ## Secure Auth routes 57 | - name: auth-v1 58 | _comment: 'GoTrue: /auth/v1/* -> http://supabase-auth:9999/*' 59 | url: http://supabase-auth:9999/ 60 | routes: 61 | - name: auth-v1-all 62 | strip_path: true 63 | paths: 64 | - /auth/v1/ 65 | plugins: 66 | - name: cors 67 | - name: key-auth 68 | config: 69 | hide_credentials: false 70 | - name: acl 71 | config: 72 | hide_groups_header: true 73 | allow: 74 | - admin 75 | - anon 76 | 77 | ## Secure REST routes 78 | - name: rest-v1 79 | _comment: 'PostgREST: /rest/v1/* -> http://supabase-rest:3000/*' 80 | url: http://supabase-rest:3000/ 81 | routes: 82 | - name: rest-v1-all 83 | strip_path: true 84 | paths: 85 | - /rest/v1/ 86 | plugins: 87 | - name: cors 88 | - name: key-auth 89 | config: 90 | hide_credentials: true 91 | - name: acl 92 | config: 93 | hide_groups_header: true 94 | allow: 95 | - admin 96 | - anon 97 | 98 | ## Secure Realtime routes 99 | - name: realtime-v1 100 | _comment: 'Realtime: /realtime/v1/* -> ws://supabase-realtime:4000/socket/*' 101 | url: http://supabase-realtime:4000/socket/ 102 | routes: 103 | - name: realtime-v1-all 104 | strip_path: true 105 | paths: 106 | - /realtime/v1/ 107 | plugins: 108 | - name: cors 109 | - name: key-auth 110 | config: 111 | hide_credentials: false 112 | - name: acl 113 | config: 114 | hide_groups_header: true 115 | allow: 116 | - admin 117 | - anon 118 | 119 | ## Storage routes: the storage server manages its own auth 120 | - name: storage-v1 121 | _comment: 'Storage: /storage/v1/* -> http://supabase-storage:5000/*' 122 | url: http://supabase-storage:5000/ 123 | routes: 124 | - name: storage-v1-all 125 | strip_path: true 126 | paths: 127 | - /storage/v1/ 128 | plugins: 129 | - name: cors 130 | 131 | ## Secure Database routes 132 | - name: meta 133 | _comment: 'pg-meta: /pg/* -> http://supabase-meta:8080/*' 134 | url: http://supabase-meta:8080/ 135 | routes: 136 | - name: meta-all 137 | strip_path: true 138 | paths: 139 | - /pg/ 140 | plugins: 141 | - name: key-auth 142 | config: 143 | hide_credentials: false 144 | - name: acl 145 | config: 146 | hide_groups_header: true 147 | allow: 148 | - admin 149 | -------------------------------------------------------------------------------- /volumes/db/init/00-initial-schema.sql: -------------------------------------------------------------------------------- 1 | -- Set up realtime 2 | create schema if not exists realtime; 3 | -- create publication supabase_realtime; -- defaults to empty publication 4 | create publication supabase_realtime; 5 | 6 | -- Supabase super admin 7 | create user supabase_admin; 8 | alter user supabase_admin with superuser createdb createrole replication bypassrls; 9 | 10 | -- Extension namespacing 11 | create schema if not exists extensions; 12 | create extension if not exists "uuid-ossp" with schema extensions; 13 | create extension if not exists pgcrypto with schema extensions; 14 | create extension if not exists pgjwt with schema extensions; 15 | 16 | -- Set up auth roles for the developer 17 | create role anon nologin noinherit; 18 | create role authenticated nologin noinherit; -- "logged in" user: web_user, app_user, etc 19 | create role service_role nologin noinherit bypassrls; -- allow developers to create JWT's that bypass their policies 20 | 21 | create user authenticator noinherit; 22 | grant anon to authenticator; 23 | grant authenticated to authenticator; 24 | grant service_role to authenticator; 25 | grant supabase_admin to authenticator; 26 | 27 | grant usage on schema public to postgres, anon, authenticated, service_role; 28 | alter default privileges in schema public grant all on tables to postgres, anon, authenticated, service_role; 29 | alter default privileges in schema public grant all on functions to postgres, anon, authenticated, service_role; 30 | alter default privileges in schema public grant all on sequences to postgres, anon, authenticated, service_role; 31 | 32 | -- Allow Extensions to be used in the API 33 | grant usage on schema extensions to postgres, anon, authenticated, service_role; 34 | 35 | -- Set up namespacing 36 | alter user supabase_admin SET search_path TO public, extensions; -- don't include the "auth" schema 37 | 38 | -- These are required so that the users receive grants whenever "supabase_admin" creates tables/function 39 | alter default privileges for user supabase_admin in schema public grant all 40 | on sequences to postgres, anon, authenticated, service_role; 41 | alter default privileges for user supabase_admin in schema public grant all 42 | on tables to postgres, anon, authenticated, service_role; 43 | alter default privileges for user supabase_admin in schema public grant all 44 | on functions to postgres, anon, authenticated, service_role; 45 | 46 | -- Set short statement/query timeouts for API roles 47 | alter role anon set statement_timeout = '3s'; 48 | alter role authenticated set statement_timeout = '8s'; 49 | -------------------------------------------------------------------------------- /volumes/db/init/01-auth-schema.sql: -------------------------------------------------------------------------------- 1 | 2 | CREATE SCHEMA IF NOT EXISTS auth AUTHORIZATION supabase_admin; 3 | 4 | -- auth.users definition 5 | 6 | CREATE TABLE auth.users ( 7 | instance_id uuid NULL, 8 | id uuid NOT NULL UNIQUE, 9 | aud varchar(255) NULL, 10 | "role" varchar(255) NULL, 11 | email varchar(255) NULL UNIQUE, 12 | encrypted_password varchar(255) NULL, 13 | confirmed_at timestamptz NULL, 14 | invited_at timestamptz NULL, 15 | confirmation_token varchar(255) NULL, 16 | confirmation_sent_at timestamptz NULL, 17 | recovery_token varchar(255) NULL, 18 | recovery_sent_at timestamptz NULL, 19 | email_change_token varchar(255) NULL, 20 | email_change varchar(255) NULL, 21 | email_change_sent_at timestamptz NULL, 22 | last_sign_in_at timestamptz NULL, 23 | raw_app_meta_data jsonb NULL, 24 | raw_user_meta_data jsonb NULL, 25 | is_super_admin bool NULL, 26 | created_at timestamptz NULL, 27 | updated_at timestamptz NULL, 28 | CONSTRAINT users_pkey PRIMARY KEY (id) 29 | ); 30 | CREATE INDEX users_instance_id_email_idx ON auth.users USING btree (instance_id, email); 31 | CREATE INDEX users_instance_id_idx ON auth.users USING btree (instance_id); 32 | comment on table auth.users is 'Auth: Stores user login data within a secure schema.'; 33 | 34 | -- auth.refresh_tokens definition 35 | 36 | CREATE TABLE auth.refresh_tokens ( 37 | instance_id uuid NULL, 38 | id bigserial NOT NULL, 39 | "token" varchar(255) NULL, 40 | user_id varchar(255) NULL, 41 | revoked bool NULL, 42 | created_at timestamptz NULL, 43 | updated_at timestamptz NULL, 44 | CONSTRAINT refresh_tokens_pkey PRIMARY KEY (id) 45 | ); 46 | CREATE INDEX refresh_tokens_instance_id_idx ON auth.refresh_tokens USING btree (instance_id); 47 | CREATE INDEX refresh_tokens_instance_id_user_id_idx ON auth.refresh_tokens USING btree (instance_id, user_id); 48 | CREATE INDEX refresh_tokens_token_idx ON auth.refresh_tokens USING btree (token); 49 | comment on table auth.refresh_tokens is 'Auth: Store of tokens used to refresh JWT tokens once they expire.'; 50 | 51 | -- auth.instances definition 52 | 53 | CREATE TABLE auth.instances ( 54 | id uuid NOT NULL, 55 | uuid uuid NULL, 56 | raw_base_config text NULL, 57 | created_at timestamptz NULL, 58 | updated_at timestamptz NULL, 59 | CONSTRAINT instances_pkey PRIMARY KEY (id) 60 | ); 61 | comment on table auth.instances is 'Auth: Manages users across multiple sites.'; 62 | 63 | -- auth.audit_log_entries definition 64 | 65 | CREATE TABLE auth.audit_log_entries ( 66 | instance_id uuid NULL, 67 | id uuid NOT NULL, 68 | payload json NULL, 69 | created_at timestamptz NULL, 70 | CONSTRAINT audit_log_entries_pkey PRIMARY KEY (id) 71 | ); 72 | CREATE INDEX audit_logs_instance_id_idx ON auth.audit_log_entries USING btree (instance_id); 73 | comment on table auth.audit_log_entries is 'Auth: Audit trail for user actions.'; 74 | 75 | -- auth.schema_migrations definition 76 | 77 | CREATE TABLE auth.schema_migrations ( 78 | "version" varchar(255) NOT NULL, 79 | CONSTRAINT schema_migrations_pkey PRIMARY KEY ("version") 80 | ); 81 | comment on table auth.schema_migrations is 'Auth: Manages updates to the auth system.'; 82 | 83 | INSERT INTO auth.schema_migrations (version) 84 | VALUES ('20171026211738'), 85 | ('20171026211808'), 86 | ('20171026211834'), 87 | ('20180103212743'), 88 | ('20180108183307'), 89 | ('20180119214651'), 90 | ('20180125194653'); 91 | 92 | create or replace function auth.uid() 93 | returns uuid 94 | language sql stable 95 | as $$ 96 | select 97 | coalesce( 98 | current_setting('request.jwt.claim.sub', true), 99 | (current_setting('request.jwt.claims', true)::jsonb ->> 'sub') 100 | )::uuid 101 | $$; 102 | 103 | create or replace function auth.role() 104 | returns text 105 | language sql stable 106 | as $$ 107 | select 108 | coalesce( 109 | current_setting('request.jwt.claim.role', true), 110 | (current_setting('request.jwt.claims', true)::jsonb ->> 'role') 111 | )::text 112 | $$; 113 | 114 | create or replace function auth.email() 115 | returns text 116 | language sql stable 117 | as $$ 118 | select 119 | coalesce( 120 | current_setting('request.jwt.claim.email', true), 121 | (current_setting('request.jwt.claims', true)::jsonb ->> 'email') 122 | )::text 123 | $$; 124 | 125 | -- usage on auth functions to API roles 126 | GRANT USAGE ON SCHEMA auth TO anon, authenticated, service_role; 127 | 128 | -- Supabase super admin 129 | CREATE USER supabase_auth_admin NOINHERIT CREATEROLE LOGIN NOREPLICATION; 130 | GRANT ALL PRIVILEGES ON SCHEMA auth TO supabase_auth_admin; 131 | GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA auth TO supabase_auth_admin; 132 | GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA auth TO supabase_auth_admin; 133 | ALTER USER supabase_auth_admin SET search_path = "auth"; 134 | ALTER table "auth".users OWNER TO supabase_auth_admin; 135 | ALTER table "auth".refresh_tokens OWNER TO supabase_auth_admin; 136 | ALTER table "auth".audit_log_entries OWNER TO supabase_auth_admin; 137 | ALTER table "auth".instances OWNER TO supabase_auth_admin; 138 | ALTER table "auth".schema_migrations OWNER TO supabase_auth_admin; 139 | 140 | ALTER FUNCTION "auth"."uid" OWNER TO supabase_auth_admin; 141 | ALTER FUNCTION "auth"."role" OWNER TO supabase_auth_admin; 142 | ALTER FUNCTION "auth"."email" OWNER TO supabase_auth_admin; 143 | GRANT EXECUTE ON FUNCTION "auth"."uid"() TO PUBLIC; 144 | GRANT EXECUTE ON FUNCTION "auth"."role"() TO PUBLIC; 145 | GRANT EXECUTE ON FUNCTION "auth"."email"() TO PUBLIC; 146 | -------------------------------------------------------------------------------- /volumes/db/init/02-storage-schema.sql: -------------------------------------------------------------------------------- 1 | CREATE SCHEMA IF NOT EXISTS storage AUTHORIZATION supabase_admin; 2 | 3 | grant usage on schema storage to postgres, anon, authenticated, service_role; 4 | alter default privileges in schema storage grant all on tables to postgres, anon, authenticated, service_role; 5 | alter default privileges in schema storage grant all on functions to postgres, anon, authenticated, service_role; 6 | alter default privileges in schema storage grant all on sequences to postgres, anon, authenticated, service_role; 7 | 8 | CREATE TABLE "storage"."buckets" ( 9 | "id" text not NULL, 10 | "name" text NOT NULL, 11 | "owner" uuid, 12 | "created_at" timestamptz DEFAULT now(), 13 | "updated_at" timestamptz DEFAULT now(), 14 | CONSTRAINT "buckets_owner_fkey" FOREIGN KEY ("owner") REFERENCES "auth"."users"("id"), 15 | PRIMARY KEY ("id") 16 | ); 17 | CREATE UNIQUE INDEX "bname" ON "storage"."buckets" USING BTREE ("name"); 18 | 19 | CREATE TABLE "storage"."objects" ( 20 | "id" uuid NOT NULL DEFAULT extensions.uuid_generate_v4(), 21 | "bucket_id" text, 22 | "name" text, 23 | "owner" uuid, 24 | "created_at" timestamptz DEFAULT now(), 25 | "updated_at" timestamptz DEFAULT now(), 26 | "last_accessed_at" timestamptz DEFAULT now(), 27 | "metadata" jsonb, 28 | CONSTRAINT "objects_bucketId_fkey" FOREIGN KEY ("bucket_id") REFERENCES "storage"."buckets"("id"), 29 | CONSTRAINT "objects_owner_fkey" FOREIGN KEY ("owner") REFERENCES "auth"."users"("id"), 30 | PRIMARY KEY ("id") 31 | ); 32 | CREATE UNIQUE INDEX "bucketid_objname" ON "storage"."objects" USING BTREE ("bucket_id","name"); 33 | CREATE INDEX name_prefix_search ON storage.objects(name text_pattern_ops); 34 | 35 | ALTER TABLE storage.objects ENABLE ROW LEVEL SECURITY; 36 | 37 | CREATE FUNCTION storage.foldername(name text) 38 | RETURNS text[] 39 | LANGUAGE plpgsql 40 | AS $function$ 41 | DECLARE 42 | _parts text[]; 43 | BEGIN 44 | select string_to_array(name, '/') into _parts; 45 | return _parts[1:array_length(_parts,1)-1]; 46 | END 47 | $function$; 48 | 49 | CREATE FUNCTION storage.filename(name text) 50 | RETURNS text 51 | LANGUAGE plpgsql 52 | AS $function$ 53 | DECLARE 54 | _parts text[]; 55 | BEGIN 56 | select string_to_array(name, '/') into _parts; 57 | return _parts[array_length(_parts,1)]; 58 | END 59 | $function$; 60 | 61 | CREATE FUNCTION storage.extension(name text) 62 | RETURNS text 63 | LANGUAGE plpgsql 64 | AS $function$ 65 | DECLARE 66 | _parts text[]; 67 | _filename text; 68 | BEGIN 69 | select string_to_array(name, '/') into _parts; 70 | select _parts[array_length(_parts,1)] into _filename; 71 | -- @todo return the last part instead of 2 72 | return split_part(_filename, '.', 2); 73 | END 74 | $function$; 75 | 76 | CREATE FUNCTION storage.search(prefix text, bucketname text, limits int DEFAULT 100, levels int DEFAULT 1, offsets int DEFAULT 0) 77 | RETURNS TABLE ( 78 | name text, 79 | id uuid, 80 | updated_at TIMESTAMPTZ, 81 | created_at TIMESTAMPTZ, 82 | last_accessed_at TIMESTAMPTZ, 83 | metadata jsonb 84 | ) 85 | LANGUAGE plpgsql 86 | AS $function$ 87 | DECLARE 88 | _bucketId text; 89 | BEGIN 90 | -- will be replaced by migrations when server starts 91 | -- saving space for cloud-init 92 | END 93 | $function$; 94 | 95 | -- create migrations table 96 | -- https://github.com/ThomWright/postgres-migrations/blob/master/src/migrations/0_create-migrations-table.sql 97 | -- we add this table here and not let it be auto-created so that the permissions are properly applied to it 98 | CREATE TABLE IF NOT EXISTS storage.migrations ( 99 | id integer PRIMARY KEY, 100 | name varchar(100) UNIQUE NOT NULL, 101 | hash varchar(40) NOT NULL, -- sha1 hex encoded hash of the file name and contents, to ensure it hasn't been altered since applying the migration 102 | executed_at timestamp DEFAULT current_timestamp 103 | ); 104 | 105 | CREATE USER supabase_storage_admin NOINHERIT CREATEROLE LOGIN NOREPLICATION; 106 | GRANT ALL PRIVILEGES ON SCHEMA storage TO supabase_storage_admin; 107 | GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA storage TO supabase_storage_admin; 108 | GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA storage TO supabase_storage_admin; 109 | ALTER USER supabase_storage_admin SET search_path = "storage"; 110 | ALTER table "storage".objects owner to supabase_storage_admin; 111 | ALTER table "storage".buckets owner to supabase_storage_admin; 112 | ALTER table "storage".migrations OWNER TO supabase_storage_admin; 113 | ALTER function "storage".foldername(text) owner to supabase_storage_admin; 114 | ALTER function "storage".filename(text) owner to supabase_storage_admin; 115 | ALTER function "storage".extension(text) owner to supabase_storage_admin; 116 | ALTER function "storage".search(text,text,int,int,int) owner to supabase_storage_admin; 117 | -------------------------------------------------------------------------------- /volumes/db/init/03-post-setup.sql: -------------------------------------------------------------------------------- 1 | ALTER ROLE postgres SET search_path TO "\$user",public,extensions; 2 | CREATE OR REPLACE FUNCTION extensions.notify_api_restart() 3 | RETURNS event_trigger 4 | LANGUAGE plpgsql 5 | AS $$ 6 | BEGIN 7 | NOTIFY ddl_command_end; 8 | END; 9 | $$; 10 | CREATE EVENT TRIGGER api_restart ON ddl_command_end 11 | EXECUTE PROCEDURE extensions.notify_api_restart(); 12 | COMMENT ON FUNCTION extensions.notify_api_restart IS 'Sends a notification to the API to restart. If your database schema has changed, this is required so that Supabase can rebuild the relationships.'; 13 | 14 | -- Trigger for pg_cron 15 | CREATE OR REPLACE FUNCTION extensions.grant_pg_cron_access() 16 | RETURNS event_trigger 17 | LANGUAGE plpgsql 18 | AS $$ 19 | DECLARE 20 | schema_is_cron bool; 21 | BEGIN 22 | schema_is_cron = ( 23 | SELECT n.nspname = 'cron' 24 | FROM pg_event_trigger_ddl_commands() AS ev 25 | LEFT JOIN pg_catalog.pg_namespace AS n 26 | ON ev.objid = n.oid 27 | ); 28 | 29 | IF schema_is_cron 30 | THEN 31 | grant usage on schema cron to postgres with grant option; 32 | 33 | alter default privileges in schema cron grant all on tables to postgres with grant option; 34 | alter default privileges in schema cron grant all on functions to postgres with grant option; 35 | alter default privileges in schema cron grant all on sequences to postgres with grant option; 36 | 37 | alter default privileges for user supabase_admin in schema cron grant all 38 | on sequences to postgres with grant option; 39 | alter default privileges for user supabase_admin in schema cron grant all 40 | on tables to postgres with grant option; 41 | alter default privileges for user supabase_admin in schema cron grant all 42 | on functions to postgres with grant option; 43 | 44 | grant all privileges on all tables in schema cron to postgres with grant option; 45 | 46 | END IF; 47 | 48 | END; 49 | $$; 50 | CREATE EVENT TRIGGER issue_pg_cron_access ON ddl_command_end WHEN TAG in ('CREATE SCHEMA') 51 | EXECUTE PROCEDURE extensions.grant_pg_cron_access(); 52 | COMMENT ON FUNCTION extensions.grant_pg_cron_access IS 'Grants access to pg_cron'; 53 | 54 | -- Supabase dashboard user 55 | CREATE ROLE dashboard_user NOSUPERUSER CREATEDB CREATEROLE REPLICATION; 56 | GRANT ALL ON DATABASE postgres TO dashboard_user; 57 | GRANT ALL ON SCHEMA auth TO dashboard_user; 58 | GRANT ALL ON SCHEMA extensions TO dashboard_user; 59 | GRANT ALL ON SCHEMA storage TO dashboard_user; 60 | GRANT ALL ON ALL TABLES IN SCHEMA auth TO dashboard_user; 61 | GRANT ALL ON ALL TABLES IN SCHEMA extensions TO dashboard_user; 62 | -- GRANT ALL ON ALL TABLES IN SCHEMA storage TO dashboard_user; 63 | GRANT ALL ON ALL SEQUENCES IN SCHEMA auth TO dashboard_user; 64 | GRANT ALL ON ALL SEQUENCES IN SCHEMA storage TO dashboard_user; 65 | GRANT ALL ON ALL SEQUENCES IN SCHEMA extensions TO dashboard_user; 66 | GRANT ALL ON ALL ROUTINES IN SCHEMA auth TO dashboard_user; 67 | GRANT ALL ON ALL ROUTINES IN SCHEMA storage TO dashboard_user; 68 | GRANT ALL ON ALL ROUTINES IN SCHEMA extensions TO dashboard_user; 69 | --------------------------------------------------------------------------------