This script automates the self-hosted deployment of the
supabase stack on Fly.io. It clones
the supabase repository, sets up the
necessary configurations, and generates fly.toml files for each service
defined in the docker-compose.yml file.
- Node.js >= 21
- yarn
- Fly.io CLI
- Docker
- git
- Clone this repository and navigate to the project directory:
git clone https://github.com/SupaAutoFly/SupaAutoFly
cd SupaAutoFly- Install necessary dependencies:
yarnThe supabase deployment is configured by environment variables in a .env file.
Start with the .env.example file as reference:
cp .env.example .envMake sure to set up secure secrets.
- Run the script:
./makeFly.tsor npx tsx makeFly.ts if your shell cannot process shebangs.
-
The script will generate a
flydirectory containingfly.tomlfiles for each service and deployment scripts. -
To deploy all services, run:
fly/deploy-all.ts(or npx tsx fly/deploy-all.ts)
- To destroy all services, run:
fly/destroy-all.ts(or npx tsx fly/destroy-all.ts)
The edge functions to deploy are configured by the FUNCTIONS_DIR variable and
deployed along with the app initially.
To deploy updated edge functions, you can either destroy the functions app and
deploy it anew, or use the deployFunctions.ts script to deploy only the edge
functions without redeploying the entire app:
- Make sure, the edge function server is deployed and running, e.g. by running
the
deploy-all.tsscript. - Navigate to the generated app directory for the edge function server,
typically
fly/functions. - Run:
npx tsx deployFunctions.tsThe script will connect to the Fly.io app for the edge functions, upload the new
function definitions to the app's volume and set up the necessary secrets from
the .env file in the specified directory.
You can also point the script to a different functions directory (e.g.
volumes/functions to redeploy the originally deployed functions) by passing
the functions-dir as an argument:
npx tsx deployFunctions.ts <my-functions-dir>If you need to change the Postgres password after the initial deployment, you can do so by running the following command:
cd fly
./passwdDb.tsThis will query for a new password (minimum 16 characters, can only contain [a-zA-Z0-9_])
twice, install it in the db container and save it to the .env file.
Important: You will need to copy the new .env file to the SupaAutoFly root
directory and run ./makeFly.ts and ./fly/deploy-all.ts again to update all
dependent services with the new password as well!
You can optionally configure WAL-G for backups: Use either SSH or S3 for backups, but not both at the same time. (If both are configured, the S3 configuration will be used.) S3 configuration has been tested with Tigris object storage as offered via fly.io.
When configured, Postgres will automatically archive WAL segments at a configurable maximum interval (default: 2 minutes).
For creating base-backups, /usr/local/bin/make-base-backup.sh is added to the
db service and accessible via the shell (to be run as user postgres) and the
backup.make_base_backup() postgres function. The intent is to set up a pg_cron
job in supabase to run this function periodically, e.g. every 24 hours. To run a
nightly base-backup at 04:17 UTC, you could use:
CREATE EXTENSION IF NOT EXISTS pg_cron;
SELECT cron.schedule('WAL-G base backup', '17 04 * * *', 'SELECT backup.make_base_backup()');make-base-backup.sh will also delete old base backups to keep the number of
backups within the configured limit (default: 7).
WAL-G logs are stored persistently at /var/log/wal-g.
Do try this out before you need it in production!
Base reference: Continuous PostgreSQL Backups using WAL-G
cd fly/db- Add the following to the
fly.tomlfile:
[[files]]
local_path = "/dev/null"
guest_path = "/etc/maintenance_mode"./deploy.ts: This will start the app in maintenance mode in which postgres will not be started immediately.fly ssh consolesu postgresrm -r ~/data/*(⚠️ this deletes your database but it's broken anyway, right!?)wal-g backup-fetch ~/data LATEST(or specify an earlier backup listed bywal-g backup-listif you need to roll back past the latest backup)touch ~/data/recovery.signalexit(back to root)- Optional: Configure point-in-time recovery (otherwise the latest point in
time will be restored):
apt update && apt install nanonano /etc/postgresql-custom/wal-g.conf- Uncomment and set
recovery_target_time
rm /etc/maintenance_modewill end maintenance mode and start the postgres service. Startup checks for/etc/maintenance_modeonly once per minute. A delay is expected.- Wait for postgres to complete recovery (see
fly logs). During this time, WAL-G will retrieve needed WAL segments from the backup storage. psql -U postgresand inspect the restored databaseexitthe ssh console- Remove the maintenance mode
[[files]]section fromfly.toml ./deploy.tsagain to restart the app without maintenance mode.
If you use supabase storage, you should also back up the storage data. As supabase storage uses Postgres only for metadata, the above Postgres backup will not include storage payload.
For storage backups, SupaAutoFly uses
S3ResticBackup.
To use it, configure the target S3 storage in the .env file and set a
backup schedule. You can also configure retention and pruning of old backups and
adjust some Restic internals like compression.
The storage-backup app contains four fly "processes":
-
backup: This process machine performs a single backup run and then exits. It is scheduled usingfly machine update --scheduleas configured. -
prune: This process machine performs pruning of old backups according to the retention policy configured. It is scheduled usingfly machine update --scheduleas configured. -
check: This process machine performs integrity checks of the restic repository. It is scheduled usingfly machine update --scheduleas configured. -
maintenance: This process machine is usually stopped. It can be started manually usingfly machine startand picking themaintenancemachine. This machine will start up and be idle such that you canfly ssh consoleinto it. There, you can usebackup.py mount target-primaryto mount the restic backups.Don't forget to
fly machine stopthe maintenance machine again to avoid unnecessary costs.If
resticfails due to memory exhaustion, please increase the memory of the VMs inmakeFly.ts(see comments there).Do try this out before you need it in production!
You can customize the deployment by modifying the makeMetadata function and
the extraServices object in the makeFly.ts script.
Because this is focussed on deploying Supabase, the script is not designed to be a generic docker-compose to fly.io converter. Docker-compose is way too rich in features to make this feasible in the scope of this project.
- The script currently does not convert health checks from the
docker-compose.ymlfile. - The dependency resolution is simplistic.
- Edge functions currently do not support the
config.tomlfile. There is just a globalVERIFY_JWTvariable for all functions.
This project is licensed under the MIT License.