> Source: https://meetrix.io/blogs/supabase-developer-guide/
> Markdown copy of that page. Cite the URL above, not this file.

Development

# Supabase - Developer Guide

[By Binuka Ranatunga](https://meetrix.io/blogs/authors/binuka-ranatunga/) • October 29, 2026 • 19 min read

Learn how to deploy Supabase on AWS with our step-by-step guide. It walks you through launching the Meetrix Supabase AMI with CloudFormation, choosing an instance type and volume size, pointing your domain at the server, signing in to Studio, finding your API keys, and setting up the daily database backup to S3 that protects your data once the project is live.

[Supabase](https://supabase.com/docs/guides/self-hosting/docker) is the open-source backend built on Postgres: a database, Auth, instant REST APIs, Realtime, Storage and Edge Functions in one project, managed from the Studio dashboard. Self-hosting it in your own AWS account keeps your data on infrastructure you control, and the only limits on database size or API requests are the instance and volume you pick. If you are still weighing it up, our comparison of [Supabase vs Firebase](https://meetrix.io/blogs/supabase-vs-firebase/) covers what you gain and what you give up. The Meetrix image runs Supabase on Ubuntu 26.04 LTS with Postgres 17, and generates a fresh JWT secret, API keys and database password on first boot.

## Video Guide

Prerequisites

Before you get started with the Supabase AMI, ensure you have the following prerequisites:

-   Basic knowledge of AWS services, including EC2 instances and CloudFormation.
-   An active AWS account with permission to create EC2, VPC, IAM and CloudFormation resources.
-   An EC2 key pair in the region you will deploy to.
-   A domain name, ideally with its hosted zone in Route 53 in the same AWS account, so SSL is issued automatically. Without one, Supabase runs on its Elastic IP over HTTP.
-   An existing S3 bucket in the same region for the daily database backups. It is optional, but anything beyond a test deployment should have one.
-   If you encounter a vCPU quota error when launching the stack, follow [https://meetrix.io/blogs/increase-aws-vcpu-quota/](https://meetrix.io/blogs/increase-aws-vcpu-quota/) to increase your vCPU limit.

## Launching the AMI

### Step 1: Find and Select Supabase AMI

1.  Log in to your AWS Management Console.
2.  Navigate to '[Supabase](https://aws.amazon.com/marketplace/pp/prodview-qg3lale77sic4)' in AWS Marketplace.

### Step 2: Initial Setup & Configuration

1.  Click the **"Continue to Subscribe"** button.
2.  After subscribing, accept the terms and click **"Accept Terms"**.
3.  Wait a few minutes until processing completes, then click **"Continue to Configuration"**.
4.  Select **"CloudFormation script to deploy Supabase"** as the fulfillment option and choose your region. Click **"Continue to Launch"**.
5.  From the "Choose Action" dropdown, select **"Launch CloudFormation"** and click **"Launch"**.

## Create CloudFormation Stack

### Step 1: Create a stack

1.  Ensure the **"Template is ready"** option is selected under "Prepare template".
2.  Click "Next".

### Step 2: Specify stack options

1.  Provide a unique **"Stack name"**.
2.  Enter the **"AdminEmail"**. It is used for the Let's Encrypt SSL certificate and as the Auth admin email.
3.  Enter a value for **"DeploymentName"**, such as `prod`. It becomes part of the IAM role and export names, so give each Supabase stack in your AWS account a different one, even in different regions.
4.  Provide a public domain for **"DomainName"**, such as `api.yourdomain.com`. If the domain's hosted zone is in Route 53 in this account, SSL is set up automatically while the stack is created. Leave the default `supabase.example.com` to run Supabase on its Elastic IP over HTTP.
5.  Choose an instance type **"InstanceType"** (Recommended: **t3a.medium**, the default). Supabase needs at least 4 GiB of RAM.
6.  Select your preferred **"KeyName"**.
7.  Enter the name of your S3 bucket for **"S3Bucket"** to turn on daily database backups. Leave the default `yours3bucket` to skip them for now.
8.  Set **"SSHLocation"** to your own IP as `x.x.x.x/32`, or `0.0.0.0/0` to allow SSH from anywhere.
9.  Enter the **"SupabaseDashboardUsername"** and **"SupabaseDashboardPassword"** you will use to sign in to Studio. The password takes 8-64 characters: letters, numbers and `_ . - @ ! % * + =` only.
10.  Set **"VolumeSize"**, the root EBS volume in GiB (see the note below).
11.  Keep **"SubnetCidrBlock"** as 10.0.0.0/24.
12.  Keep **"VpcCidrBlock"** as 10.0.0.0/16.
13.  Click "Next".

Choosing VolumeSize

VolumeSize sets the size of the root gp3 EBS volume, anywhere from 20 to 16,384 GiB, with 30 GiB as the default. Everything Supabase stores lives on it: the Postgres database, files uploaded to Storage, and the Docker images the stack runs from. 30 GiB is plenty to build and test with. For production, size it for your expected database plus uploads, with headroom. You can [increase the volume later](#increase-volume-size), but an EBS volume cannot be made smaller.

### Step 3: Configure stack options

1.  Choose "Roll back all stack resources" and "Delete all newly created resources" under "Stack failure options".
2.  Click "Next".

### Step 4: Review

Review and verify the parameters you've entered.

![CloudFormation Parameters list for the Supabase stack showing AdminEmail, AmiId, DeploymentName, DomainName, InstanceType set to t3a.medium, KeyName, S3Bucket, SSHLocation, the Supabase dashboard username and password, VolumeSize set to 30 and CIDR blocks](https://meetrix.io/blog-images/paas-dev-guides/supabase/supabase-01.png)

1.  Tick **"I acknowledge that AWS CloudFormation might create IAM resources with custom names"**.
2.  Click **"Submit"**.

![CloudFormation capabilities notice for IAM Policy and Role resources with the acknowledgement checkbox ticked](https://meetrix.io/blog-images/paas-dev-guides/supabase/supabase-02.png)

Afterward, you'll be directed to the CloudFormation stacks page. The stack stays in **CREATE\_IN\_PROGRESS** until first boot finishes: the instance generates its secrets, initializes Postgres, starts every Supabase service and requests the SSL certificate, then reports back to CloudFormation. This takes about 5-10 minutes. Once the status shows **CREATE\_COMPLETE**, Supabase is already running.

![Supabase CloudFormation stack Outputs tab listing DashboardUrl, DashboardUrlIp and PublicIp](https://meetrix.io/blog-images/paas-dev-guides/supabase/supabase-03.png)

## Update DNS

### Step 1: Copy IP Address

Copy the public IP labeled **"PublicIp"** in the **"Outputs"** tab. It is an Elastic IP, so it stays the same when the instance stops and starts.

![PublicIp Elastic IP value highlighted in the Supabase stack Outputs tab](https://meetrix.io/blog-images/paas-dev-guides/supabase/supabase-04.png)

### Step 2: Update DNS

1.  Go to AWS Route 53 and navigate to "Hosted Zones".
2.  Click **Create record**.
3.  Add a **record name** matching the DomainName you entered, keep the record type as **A**, and paste the copied **PublicIp** into the **value** textbox.
4.  Click **"Create records"**.

![Route 53 Quick create record form for an A record in the hosted zone](https://meetrix.io/blog-images/paas-dev-guides/supabase/supabase-05.png)

If your domain is managed by another DNS provider, create the same A record there, then follow **Generate SSL Manually** below.

## Access Supabase

Open the **"DashboardUrl"** from the Outputs tab. Until DNS and SSL are in place you can use **"DashboardUrlIp"** instead, which opens Studio on the Elastic IP over plain HTTP.

Studio sits behind HTTP basic auth, so your browser asks for a username and password first. Enter the **SupabaseDashboardUsername** and **SupabaseDashboardPassword** you set in the stack parameters, then click **"Sign in"**.

![Browser sign-in prompt for the Supabase Studio domain asking for a username and password](https://meetrix.io/blog-images/paas-dev-guides/supabase/supabase-06.png)

Note

If you receive a "502 Bad Gateway" error, wait approximately **5 minutes** and refresh the page. The Supabase services may still be starting.

After signing in you land on the home page of the **Default Project**. It shows your project URL, a **Get connected** panel with connection details for client libraries, server code, a direct database connection, ORMs, MCP and API keys, and the advisor's security and performance checks. The Table Editor, SQL Editor, Authentication, Storage and Edge Functions are in the menu on the left.

![Supabase Studio home page for the Default Project showing the project URL, the Get connected panel with Framework, Server, Direct, ORM, MCP and API Keys options, and the advisor reporting no issues](https://meetrix.io/blog-images/paas-dev-guides/supabase/supabase-07.png)

Dashboard login

The dashboard login protects Studio, which has full access to your database. Use a strong password, and keep it separate from the Supabase Auth users your app signs in. Our guide to [Supabase self-hosting security](https://meetrix.io/blogs/supabase-self-hosted-security/) covers what else to lock down before production.

## Get Your API Keys

Your app talks to Supabase through the API URL, which is the same address as your DashboardUrl. REST lives at `/rest/v1/`, Auth at `/auth/v1/`, Storage at `/storage/v1/`, Realtime at `/realtime/v1/` and Edge Functions at `/functions/v1/`.

The keys are generated on first boot and stored in `/opt/supabase/docker/.env`. Log in to the server over SSH:

```bash
ssh -i <your key name> ubuntu@<Public IP address>
```

Then print the keys:

```bash
sudo grep -E '^(ANON_KEY|SERVICE_ROLE_KEY|SUPABASE_PUBLISHABLE_KEY|SUPABASE_SECRET_KEY|POSTGRES_PASSWORD)=' /opt/supabase/docker/.env
```

-   **SUPABASE\_PUBLISHABLE\_KEY** or **ANON\_KEY**: safe to use in client apps. What it can reach is decided by your Row Level Security policies.
-   **SUPABASE\_SECRET\_KEY** or **SERVICE\_ROLE\_KEY**: server-side only. It bypasses Row Level Security, so never ship it in a browser or mobile app.

Edge Functions accept only the newer `sb_publishable_...` and `sb_secret_...` keys in the `apikey` header. The legacy ANON\_KEY and SERVICE\_ROLE\_KEY JWTs still work for REST, Auth, Storage and Realtime.

## Connect to Postgres

The security group opens only ports 22, 80 and 443. Postgres and the connection pooler (5432 and 6543) and the API gateway (8000) listen on localhost only, so they are never exposed to the internet. To reach the database from your machine with psql, a GUI client or a migration tool, open an SSH tunnel:

```bash
ssh -i <your key name> -L 5432:127.0.0.1:5432 ubuntu@<Public IP address>
```

Leave that session open and connect from a second terminal. The user name is `postgres`, a dot, and the pooler tenant ID. Both the tenant ID and the password are in the same `.env` file, as **POOLER\_TENANT\_ID** and **POSTGRES\_PASSWORD**:

```bash
psql "postgres://postgres.<POOLER_TENANT_ID>:<POSTGRES_PASSWORD>@127.0.0.1:5432/postgres"
```

## Configure Email (SMTP)

Auth sign-ups, magic links and password resets need a real SMTP server. Open the environment file:

```bash
sudo nano /opt/supabase/docker/.env
```

Set **SMTP\_HOST**, **SMTP\_PORT**, **SMTP\_USER**, **SMTP\_PASS**, **SMTP\_ADMIN\_EMAIL** and **SMTP\_SENDER\_NAME**, save the file, then apply the change:

```bash
cd /opt/supabase/docker && sudo docker compose up -d
```

Until SMTP is configured, create users from Studio under **Authentication** and **Add user**, or set `ENABLE_EMAIL_AUTOCONFIRM=true` in the same file and run the same command, so sign-ups skip the confirmation email while you test.

## Back Up the Database

If you set **S3Bucket** when creating the stack, backups are already running: every day at 12:00 UTC the instance dumps the whole database and uploads it to your bucket. With the default `yours3bucket` nothing is scheduled, and **Turn On Backups After Launch** below switches it on for an existing deployment.

| Setting | Value |
| --- | --- |
| Schedule | Daily at 12:00 UTC (the instance clock runs in UTC) |
| Cron job file | `/etc/cron.d/supabase-dbbackup` |
| Backup script | `/opt/scripts/dbbackup.sh` |
| Log file | `/var/log/scripts/dbbackup.log` |
| Destination | `s3://<S3Bucket>/supabase-dbbackup/dump_<YYYY-MM-DD-HH-MM-SS>.sql.gz` |

### How the Backup Works

1.  On first boot, the stack writes your bucket name into `/opt/scripts/dbbackup.sh` and, only when S3Bucket is not `yours3bucket`, creates the cron job file.
2.  Every day at 12:00 UTC, cron runs the script as root and appends its output to the log file.
3.  The script runs `pg_dumpall` inside the `supabase-db` container, which captures every database, role and Auth user. It gzips the dump, uploads it to S3 using the instance's IAM role, and deletes the local copy.

On that bucket, the instance role is allowed `s3:PutObject` and nothing else. It can upload backups, but it cannot list, download or delete them. Backups are never deleted automatically either, so add an [S3 lifecycle rule](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html) to the bucket to expire old dumps, for example after 30 days.

Storage files are not in the dump

The backup covers the database only. Files uploaded to Supabase Storage live on the EBS volume at `/opt/supabase/docker/volumes/storage`. To protect them, take [EBS snapshots](https://docs.aws.amazon.com/ebs/latest/userguide/ebs-creating-snapshot.html) of the volume, by hand or on a schedule with Amazon Data Lifecycle Manager.

### Check, Run or Change the Backup

```bash
# Confirm the cron job is installed
cat /etc/cron.d/supabase-dbbackup

# See when cron last ran it
sudo journalctl -u cron | grep dbbackup | tail

# Check the result of the last runs
sudo tail /var/log/scripts/dbbackup.log

# Run a backup now
sudo /opt/scripts/dbbackup.sh
```

To change the time, edit the minute and hour fields (in UTC) in `/etc/cron.d/supabase-dbbackup`, for example `30 2 * * *` for 02:30 UTC. Cron picks up the change on its own. To stop backups, delete the file:

```bash
sudo rm /etc/cron.d/supabase-dbbackup
```

### Turn On Backups After Launch

If you launched with the default `yours3bucket`, point the script at your bucket and create the cron job file, replacing `<your-bucket>` with the bucket name:

```bash
sudo sed -i 's;yours3bucket;<your-bucket>;g' /opt/scripts/dbbackup.sh
printf 'CRON_TZ=UTC\n0 12 * * * root /opt/scripts/dbbackup.sh >> /var/log/scripts/dbbackup.log 2>&1\n' | sudo tee /etc/cron.d/supabase-dbbackup
```

The instance role also needs permission to upload, and the stack granted it on `yours3bucket` only. In the IAM console, open the role named `supabase-<DeploymentName>`, edit its inline policy, and change the resource of the **S3ForBackup** statement to `arn:aws:s3:::<your-bucket>/*`. Make this change in IAM rather than through a stack update, which restarts the instance without re-running the first-boot setup. Then run `sudo /opt/scripts/dbbackup.sh` once and check that the dump appears in the bucket.

### Restore a Backup

The instance role can only upload, so download the dump with your own AWS credentials and copy it to the server:

```bash
# On your machine
aws s3 cp s3://<your-bucket>/supabase-dbbackup/<dump-file>.sql.gz .
scp -i <your key name> <dump-file>.sql.gz ubuntu@<Public IP address>:/tmp/
```

Then, on the server, load it into Postgres and restart the stack so PostgREST reloads its schema cache:

```bash
gunzip -c /tmp/<dump-file>.sql.gz | sudo docker exec -i supabase-db psql -U supabase_admin -d postgres > /tmp/restore.log 2>&1
cd /opt/supabase/docker && sudo docker compose restart
rm /tmp/<dump-file>.sql.gz
```

The restore fills `restore.log` with "already exists" and "duplicate key" errors for Supabase's built-in schemas and roles. They are expected. Postgres loads each table's rows in one step, which decides what comes back:

-   A table that is missing or empty comes back in full.
-   A table that still holds any row with the same primary key as a row in the dump is left as it is, because one duplicate key cancels the load for that whole table. Rows deleted from it do not come back.
-   A table without a primary key that still holds rows gets every dumped row added again, as duplicates.

So a restore onto the same server brings back dropped or emptied tables, not individual deleted rows. To get the whole database back as it was, restore onto a new stack.

#### Restore onto a Different Stack

The dump also carries the database role passwords of the server it was taken on. Loaded onto a different stack, such as a replacement server or a newer version, it sets those passwords back to the old server's, and the Supabase services on the new server can no longer log in to Postgres. After the restore, reset the passwords with Supabase's own script, then recreate the containers:

```bash
cd /opt/supabase/docker
sudo sh utils/db-passwd.sh
sudo docker compose up -d --force-recreate
```

The script shows a new random password and asks for confirmation, so type **y**. It updates every database role and the POSTGRES\_PASSWORD in `.env`. If your project currently lives on supabase.com, our guide to [migrating from Supabase Cloud to self-hosted](https://meetrix.io/blogs/migrate-supabase-cloud-to-self-hosted/) covers bringing the database, Storage and Auth settings across.

## Generate SSL Manually

SSL is issued automatically through a Route 53 DNS challenge when the domain's hosted zone is in the same AWS account. If your DNS is hosted elsewhere, or the stack finished without a certificate, follow these steps. Until then, use the DashboardUrlIp, which serves Studio over plain HTTP on the Elastic IP. The certificate script is set up for the DomainName you entered when creating the stack, so if you launched without a domain, the simplest route is a new stack with your domain set.

### Step 1: Copy IP Address

1.  Follow the **Update DNS** steps above, if not already done, so the domain's A record points at the server.
2.  Copy the Public IP indicated as **"PublicIp"** in the **"Outputs"** tab.

### Step 2: Log in to the server

1.  Open the terminal and go to the directory where your private key is located.
2.  Run the following command, replacing the key name and IP address.
3.  Type "yes" and press Enter to confirm.

```bash
ssh -i <your key name> ubuntu@<Public IP address>
```

![Terminal connecting to the Supabase server over SSH and confirming the host key fingerprint](https://meetrix.io/blog-images/paas-dev-guides/supabase/supabase-08.png)

### Step 3: Generate SSL

Run the following command and follow the prompts:

```bash
sudo bash /root/certificate_generate_standalone.sh
```

## Check Server Logs

### Step 1: Log in to the server

```bash
ssh -i <your key name> ubuntu@<Public IP address>
```

![Terminal opening an SSH session to the Supabase server with a private key](https://meetrix.io/blog-images/paas-dev-guides/supabase/supabase-09.png)

### Step 2: Check the logs

Supabase runs as a set of Docker Compose services in `/opt/supabase/docker`. Check their status, follow the logs, or restart the whole stack:

```bash
cd /opt/supabase/docker
sudo docker compose ps          # status
sudo docker compose logs -f     # logs
sudo docker compose restart     # restart
```

To look at a single service, name it, for example `sudo docker compose logs -f auth` for Auth or `sudo docker logs supabase-db` for Postgres.

## Shutting Down Supabase

1.  In CloudFormation, click the link labeled **"Instance"** in the **"Resources"** tab to open the EC2 instance.
2.  Stop the Supabase instance from the **Instance state** dropdown. You can restart it later as needed.

![CloudFormation Resources tab with the EC2 Instance physical ID link](https://meetrix.io/blog-images/paas-dev-guides/supabase/supabase-10.png) ![EC2 Instance state dropdown with the Stop instance option](https://meetrix.io/blog-images/paas-dev-guides/supabase/supabase-11.png)

Note

While the instance is stopped, every API call from your app fails and the 12:00 UTC backup does not run. The Elastic IP stays attached, so your domain works again as soon as you start the instance.

## Remove Supabase

Take a final backup first with `sudo /opt/scripts/dbbackup.sh`. Then delete the CloudFormation stack from the AWS Management Console under "CloudFormation Stacks" by clicking "Delete". Deleting the stack removes the instance, its EBS volume with the database and Storage files, and the Elastic IP. The S3 bucket was not created by the stack, so the bucket and the backups in it are kept.

## Upgrades

Meetrix publishes a new AMI for each Supabase release, and the AWS Marketplace listing shows the current version. To move to it:

1.  Run a backup on the old instance with `sudo /opt/scripts/dbbackup.sh`.
2.  Launch a new stack from the new version, with a different **DeploymentName**.
3.  Restore the dump on the new instance as shown in **Restore a Backup**, including the password reset in **Restore onto a Different Stack**, and copy `/opt/supabase/docker/volumes/storage` across.
4.  Point your DNS record at the new PublicIp and check your app.
5.  Delete the old stack.

The new stack generates its own JWT secret and API keys, so update the keys your apps use. Signed-in users may need to sign in again.

## Increase the Volume Size

When the database or Storage outgrows the volume, grow it in place. The data stays where it is and the instance keeps running.

1.  In CloudFormation, click the **"Instance"** link in the **"Resources"** tab, open the **Storage** tab, and click the volume ID.
2.  Choose **Actions**, then **Modify volume**, enter the new size in GiB, and click **Modify**. AWS's guide to [modifying an EBS volume](https://docs.aws.amazon.com/ebs/latest/userguide/requesting-ebs-volume-modifications.html) covers the options.
3.  When the volume state shows **optimizing** or **completed**, log in to the server and extend the partition and file system.

```bash
lsblk
sudo growpart /dev/nvme0n1 1
sudo resize2fs /dev/nvme0n1p1
df -h /
```

Check the disk name in the `lsblk` output first. Current instance types such as t3a show `nvme0n1`, while older Xen types such as t2 show `xvda`, with the partition as `xvda1`. Rebooting the instance also works: Ubuntu grows the root partition and file system to fill the volume at boot.

Do not change VolumeSize with a stack update

Changing VolumeSize through **Update stack** replaces the EC2 instance: CloudFormation launches a new one with an empty database and new keys, then terminates the old one along with its volume. Resize the existing volume as above instead. AWS allows up to four modifications per volume in a rolling 24 hours, and each must complete before the next can start, so add generous headroom each time.

## Troubleshoot

If you face vCPU quota limits, request an increase: [How to increase AWS quota](https://meetrix.io/blogs/increase-aws-vcpu-quota/).

![CloudFormation event showing CREATE\_FAILED with a VcpuLimitExceeded error](https://meetrix.io/blog-images/paas-dev-guides/supabase/supabase-12.png)

If you face _insufficient capacity_ errors while creating the stack, try another region or time.

![CloudFormation event showing CREATE\_FAILED with an InsufficientInstanceCapacity error](https://meetrix.io/blog-images/paas-dev-guides/supabase/supabase-13.png)

If the stack fails on the **Instance** resource, first boot either reported an error or did not finish within 20 minutes, and CloudFormation rolled the stack back. Check the reason in the **Events** tab and create the stack again. If it fails a second time, send the event message to support.

If Supabase shows a 502 Bad Gateway error after a reboot or a `docker compose restart`, wait a few minutes and retry. Nginx answers before the Supabase services behind it are back up.

![502 Bad Gateway error page served by nginx](https://meetrix.io/blog-images/paas-dev-guides/supabase/supabase-14.png)

If sign-up, magic link or password reset emails never arrive, SMTP is not configured yet. See **Configure Email (SMTP)** above.

Check whether the instance storage is full. Log into the server and run:

```bash
df -h
```

![df -h output showing usage of the root filesystem](https://meetrix.io/blog-images/paas-dev-guides/supabase/supabase-15.png)

If the root volume is between 90-100%, [increase the volume size](#increase-volume-size).

## Conclusion

The Meetrix Supabase Deployment Guide gets a self-hosted Supabase backend running in your own AWS account, with secrets generated per deployment, a volume sized for your data, and a daily database backup to S3. See the [Supabase store page](https://meetrix.io/store/supabase/) for what the Meetrix image includes on AWS and Google Cloud. If you are deploying on Google Cloud instead, follow the [Supabase on GCP developer guide](https://meetrix.io/blogs/supabase-gcp-developer-guide/), and if you only need a plain database without the rest of Supabase, the [PostgreSQL developer guide](https://meetrix.io/blogs/postgresql-developer-guide/) sets one up on AWS. The source code and release notes are on [GitHub](https://github.com/supabase/supabase).

[

### Self-Host Supabase with Meetrix on AWS - The Open-Source Firebase Alternative, Ready in Minutes

Self-host Supabase on AWS in minutes with Meetrix's pre-configured, production-ready deployment - the open-source Firebase alternative with full data control and 24/7 expert support.

By Shalomi Umeshika • Meetrix.io

](https://meetrix.io/blogs/self-host-supabase-aws-meetrix/)

## Technical Support

Reach out to Meetrix Support ([aws@meetrix.io](mailto:aws@meetrix.io)) for assistance with Supabase issues.

## Frequently Asked Questions

What does the Meetrix Supabase AMI include?

A self-hosted Supabase stack on Ubuntu 26.04 LTS, running in Docker Compose: Postgres 17, Studio, Auth, PostgREST, Realtime, Storage, Edge Functions and the Supavisor connection pooler, behind an Nginx reverse proxy with a Let's Encrypt SSL certificate. The JWT secret, API keys and Postgres password are generated on first boot, so no two deployments share secrets.

Which instance type is recommended?

t3a.medium (2 vCPU, 4 GiB RAM), the default. Supabase needs at least 4 GiB of RAM, so do not pick anything smaller. Move to t3a.large or larger once real traffic, many Realtime connections or heavy queries arrive.

How big should the volume be, and can I change it later?

Set it with the VolumeSize parameter, anywhere from 20 to 16,384 GiB (30 GiB by default). The volume holds the Postgres database, files uploaded to Storage and the Docker images, so leave room to grow. You can enlarge it later from the EC2 console while the instance runs, but you cannot shrink it. Do not change VolumeSize through a stack update, because that replaces the instance.

How do I turn on daily database backups?

Enter the name of an existing S3 bucket in the S3Bucket parameter when you create the stack. The instance then dumps the database every day at 12:00 UTC and uploads the gzipped dump to the supabase-dbbackup/ folder of that bucket. With the default yours3bucket no backup is scheduled, but you can switch it on later from the server.

Does the backup include files uploaded to Supabase Storage?

No. The daily job dumps the database only: tables, roles and Auth users. Storage files live on the EBS volume under /opt/supabase/docker/volumes/storage, so take EBS snapshots to protect them.

How do I upgrade Supabase?

Meetrix publishes a new AMI for each Supabase release. Run a backup, launch a new stack from the latest version in AWS Marketplace, restore the dump on the new server and reset its database passwords, copy your Storage files across, then delete the old stack. The new stack generates its own API keys, so update them in your apps.

How do I get technical support?

Reach out to Meetrix Support at [aws@meetrix.io](mailto:aws@meetrix.io) for assistance with Supabase issues.

## Ready to Deploy Your Own Supabase?

Get started in minutes with our pre-configured AMI and run Postgres, Auth, Storage and Realtime on infrastructure you own.

[Deploy Supabase from AWS Marketplace](https://aws.amazon.com/marketplace/pp/prodview-qg3lale77sic4)

Meetrix Store

Supabase

Postgres, Auth, Storage and Realtime, self-hosted

[Deploy it](https://meetrix.io/store/supabase/)

Meetrix Store New

Deploy what this guide covers, pre-configured.

-    [Supabase Postgres, Auth, Storage and Realtime, self-hosted](https://meetrix.io/store/supabase/)
-    [PostgreSQL A Postgres server with backups to Amazon S3](https://meetrix.io/store/postgresql/)
-    [Directus REST and GraphQL APIs on your SQL database](https://meetrix.io/store/directus/)
-    [Jitsi Meet Self-hosted video calls for 50 to 500 users](https://meetrix.io/store/jitsi-meet/)
-    [RustDesk Remote desktop AMI, a TeamViewer alternative](https://meetrix.io/store/rustdesk/)
-    [Coturn TURN/STUN for WebRTC, no per-minute relay fees](https://meetrix.io/store/coturn/)

[Browse all products](https://meetrix.io/store/)
