Supabase
Overview
Supabase is the open-source Firebase alternative. It pairs a full PostgreSQL database with auto-generated REST and GraphQL APIs, an authentication service, realtime subscriptions, S3-compatible file storage and the Studio dashboard. Together they make a complete application backend.
The SecureAnyCloud image installs the official Supabase docker-compose stack (postgres, kong API gateway, gotrue auth, postgrest, realtime, storage, imgproxy, postgres-meta, studio and supavisor) and runs it under Docker behind an nginx reverse proxy on port 80. The database and storage persist on a dedicated Azure data disk, and a fresh set of per-VM secrets is generated on the first boot of every VM.
What you get:
- The official Supabase self-hosted stack running under Docker (PostgreSQL 17, kong, gotrue, postgrest, realtime, storage, imgproxy, postgres-meta, Studio, supavisor)
- nginx on
:80as a reverse proxy to the kong API gateway, serving both the Studio dashboard and the auto-generated APIs - Per-VM secrets generated on first boot: a unique
POSTGRES_PASSWORD, a randomJWT_SECRET, the matchinganonandservice_roleAPI keys signed with it, and a Studio dashboard password. They are recorded in a root-only file. - A dedicated Azure data disk at
/var/lib/supabasefor the PostgreSQL data and object storage docker.serviceandnginx.serviceas systemd units, enabled and active. The Supabase containers run with restart policies.- 24/7 SecureAnyCloud support
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet and subnet in the target region.
Standard_B4ms (4 vCPU / 16 GiB RAM) is the recommended starting size, because the full container stack needs the memory. For NSG inbound rules, allow 22/tcp from your management network and 80/tcp.
Supabase serves plain HTTP on port 80. For production, terminate TLS in front of it with your own domain.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal. Choose Create a resource, search the Marketplace for Supabase by SecureAnyCloud, and select Create.
On Basics, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22) and HTTP (80).
Review the dedicated data disk on the Disks tab, then select Review + create and Create.
Step 2 - Deploy from the Azure CLI
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:supabase-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name supabase \
--image sac1647283583153:supabase-ubuntu-24-04:default:latest \
--size Standard_B4ms \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name supabase --port 80 --priority 1010Step 3 - Connect to your VM
ssh azureuser@<vm-public-ip>Step 4 - Confirm the stack is running
The Supabase containers run under Docker, fronted by nginx. On first boot the stack generates per-VM secrets and starts; give it a couple of minutes after the VM is created.
systemctl is-active docker.service nginx.serviceBoth report active. You can list the running containers with:
sudo docker compose -f /opt/supabase/docker/docker-compose.yml psStep 5 - Retrieve your per-VM secrets
The dashboard password and the API keys are generated uniquely on the first boot of your VM and written to a root-only file:
sudo cat /root/supabase-credentials.txtThis file contains supabase.dashboard.pass (the Studio dashboard password), SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY, SUPABASE_POSTGRES_PASSWORD and SUPABASE_JWT_SECRET. The anon and service_role keys are JWTs signed with this VM's unique JWT_SECRET. Store these somewhere safe.
Step 6 - Confirm the health endpoint
nginx exposes an unauthenticated static health endpoint for load balancers and probes. The Studio dashboard is protected by basic authentication through the kong gateway:
curl -s http://localhost/healthIt returns ok. The Studio dashboard returns 401 without credentials and 200 with them:
DASH_PASS=$(sudo grep '^supabase.dashboard.pass=' /root/supabase-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'no creds -> HTTP %{http_code}\n' http://localhost/
curl -s -L -o /dev/null -w 'with creds -> HTTP %{http_code}\n' -u "supabase:$DASH_PASS" http://localhost/Step 7 - Open the Studio dashboard
Browse to http://<vm-public-ip>/ and sign in with username supabase and the password from Step 5 (<SUPABASE_DASHBOARD_PASSWORD>). The Studio dashboard is where you manage your database, tables, SQL, auth, storage and API settings.
The Table Editor lets you create and browse PostgreSQL tables and rows with a spreadsheet-like interface.
The SQL Editor runs arbitrary SQL against the database - schema changes, queries, functions and policies.
The API settings page shows your auto-generated REST endpoint and the per-VM anon and service_role API keys that your client apps use.
Step 8 - Call the REST API with your anon key
The auto-generated REST API (PostgREST, exposed through kong at /rest/v1/) requires your per-VM anon key. A request with a valid key is accepted, and a request with no key is rejected:
ANON=$(sudo grep '^SUPABASE_ANON_KEY=' /root/supabase-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'with anon key -> HTTP %{http_code}\n' -H "apikey: $ANON" -H "Authorization: Bearer $ANON" http://localhost/rest/v1/
curl -s -o /dev/null -w 'no key -> HTTP %{http_code}\n' http://localhost/rest/v1/The valid-key request returns a 2xx or 404 response, which means the API is reachable and authenticated. The no-key request returns 401. This proves the anon JWT verifies against this VM's unique JWT_SECRET.
Step 9 - Confirm data lives on the dedicated disk
The PostgreSQL database and object storage are kept on the dedicated Azure data disk so they survive OS changes and can be resized independently. Check the mount:
findmnt /var/lib/supabaseThe mount is backed by a separate Azure data disk captured into the image and re-provisioned on every VM. The PostgreSQL data directory and the storage objects live under it.
Building your app
Supabase is designed to be your app's entire backend. Point the official supabase-js client (or any HTTP client) at http://<your-domain>/ with your anon key and use the database for data, the auth API for user sign-up and login, realtime subscriptions for live updates, and the storage API for files. Use the SQL Editor or the official CLI for migrations. See the Supabase documentation for client libraries, row-level-security policies and the self-hosting guide.
Maintenance
- Dashboard / API keys: all per-VM secrets are in
/root/supabase-credentials.txt; theanonandservice_rolekeys are also on the Studio API settings page. - Database: PostgreSQL data and storage objects live on the
/var/lib/supabasedata disk - snapshot or resize that disk for backups. - Containers: manage the stack with
sudo docker compose -f /opt/supabase/docker/docker-compose.yml <ps|logs|restart>. - TLS: Supabase serves plain HTTP on port 80; front it with TLS (e.g. certbot) and your own domain before running it in production.
- Security patches: unattended-upgrades remains enabled so the OS continues to receive security updates automatically.
Support
SecureAnyCloud provides 24/7 expert support for this image. Contact sales@secureanycloud.com.
Deploy on Azure
Launch Supabase on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
This image runs Supabase as a single-node deployment. Supabase is the open-source Firebase alternative: a full PostgreSQL database with instant auto-generated REST and Realtime APIs, an authentication and user management service, object storage and a Studio web dashboard, all from a single open-source stack.
The image delivers the official Supabase self-host Docker Compose stack fully installed and configured, so a complete backend as a service is running within minutes of launch.
What you get:
- A Docker Compose stack with a PostgreSQL database, GoTrue for authentication, PostgREST for the auto-generated REST API, the Realtime server for live subscriptions, the Storage and imgproxy services for object storage, postgres-meta and the Studio dashboard for database management, the Kong API gateway, the Supavisor connection pooler and the supporting services.
- A single
supabase.servicesystemd unit that brings the whole stack up and down at boot. Docker Engine and the Docker Compose plugin are installed from the official Docker package repository. - Kong as the single entry point to the stack. It listens on the loopback address only, and
nginxon port 80 reverse-proxies to it. Kong enforces HTTP basic authentication on the Studio dashboard routes using theDASHBOARD_USERNAME(supabase) and the per-instanceDASHBOARD_PASSWORD. The Studio user interface and the management routes are therefore reachable on port 80 only with the generated dashboard credentials. - Secrets generated on the first boot of each deployed instance. Two instances launched from the same Amazon Machine Image never share a database password, a JWT secret, a dashboard password or the derived API keys. The credentials are written to
/root/supabase-credentials.txtwith mode 0600, so only the root user can read them. - A separate, independently resizable EBS volume mounted at
/var/lib/supabase. The PostgreSQL data directory and the Storage object data live on this dedicated disk rather than the operating system disk.
Prerequisites
Before you deploy this image you need:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group allowing inbound port 22 from your management network and inbound port 80 from the network you will reach the Studio dashboard from
- The AWS CLI (version 2) installed locally if you plan to deploy from the command line
Launch the Instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images, choose AWS Marketplace AMIs and search for Supabase. Select the SecureAnyCloud listing and choose Select, then Continue on the subscription summary.
Pick an instance type of t3.large or larger. Supabase runs about a dozen containers in its Compose stack, including a PostgreSQL database, the Realtime server and the Kong gateway. It benefits from at least two vCPUs and 8 GiB of memory.
Choose your EC2 key pair under Key pair (login). Under Network settings, select your VPC and subnet. Create or select a security group that allows inbound port 22 from your management network and inbound port 80 from the network you will reach the dashboard from.
Leave the root volume at the default size or larger. The image also attaches a separate 30 GiB gp3 data volume mounted at /var/lib/supabase for the database and object storage.
Select Launch instance. First-boot initialisation takes approximately three to five minutes after the instance state becomes Running and the status checks pass. During that time Supabase rotates every secret and brings its full Compose stack up.
Launch the Instance from the AWS CLI
The following command launches an instance from the SecureAnyCloud Supabase Marketplace AMI into an existing subnet and security group.
Replace <ami-id> with the AMI ID shown on the Marketplace listing. Replace <key-name> with your EC2 key pair name and <subnet-id> with your subnet ID. Replace <security-group-id> with a security group that opens ports 22 and 80 as described above.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type t3.large \
--key-name <key-name> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":20,"VolumeType":"gp3"}}]' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=supabase-01}]'The command prints a JSON document on success. Note the instance ID. Once the instance is running, retrieve its public address with aws ec2 describe-instances --instance-ids <instance-id> --query "Reservations[].Instances[].PublicIpAddress" --output text.
Connect and Retrieve Initial Credentials
Connect over SSH with the key pair you selected and the public IP address from Step 2. The SSH login user depends on the operating system of the AMI variant you launched:
AMI variant SSH login user
Supabase self-host on Ubuntu 24.04 ubuntu
The first-boot service rotates every secret and writes the credentials file before it completes, so the file is always in place when you log in for the first time. Read it:
sudo cat /root/supabase-credentials.txtThe plain-text file contains the Supabase URL, the Studio dashboard username (supabase) and password, the auto-generated anon and service_role API keys, and the PostgreSQL superuser password. Copy these values somewhere secure, such as a password manager or encrypted vault. Do not commit them to source control.
From the same SSH session, confirm the deployment is healthy. The nginx liveness endpoint returns ok. An authenticated request to the auto-generated REST API through the Kong gateway returns 200 once the database, the gateway and PostgREST are all up:
curl -fsS http://127.0.0.1/healthANON=$(sudo grep '^supabase.anon.key=' /root/supabase-credentials.txt | cut -d= -f2-)
curl -fsS -o /dev/null -w '%{http_code}\n' -H "apikey: ${ANON}" http://127.0.0.1/rest/v1/The first command returns ok and the second returns 200. Together they confirm that nginx, the Kong gateway and the database-backed REST API are all up. The Kong gateway requires the apikey header on the API routes, so an unauthenticated request to those routes returns 401 by design.
You can also inspect the Compose stack directly:
sudo docker compose -f /opt/supabase/docker/docker-compose.yml psEvery container is reported as Up (most with a (healthy) marker) once the stack has warmed up.
First Login to the Studio Dashboard
Open a web browser and go to http://<public-ip>/. The Kong gateway presents an HTTP basic authentication challenge for the Studio dashboard.
Enter the dashboard username supabase and the dashboard password from /root/supabase-credentials.txt. The Studio dashboard opens on the default project.
The navigation rail down the left of every page links to the table editor, the SQL editor, the authentication panel, the storage browser, the database tools, the auto-generated API documentation and the project settings.
The Table Editor
Select Table Editor in the navigation rail. The table editor is a spreadsheet-style view of your PostgreSQL tables. On a freshly launched instance the default public schema is empty.
Select New table to create your first table. Give it a name, define its columns and types, choose whether to enable Row Level Security, and save. Supabase creates the table in PostgreSQL and immediately exposes it over the auto-generated REST and Realtime APIs.
The SQL Editor
Select SQL Editor in the navigation rail. The SQL editor runs arbitrary SQL against the PostgreSQL database with the full power of Postgres. You can create tables, define functions and triggers, write Row Level Security policies, install extensions and query your data.
The following statement creates a simple table and inserts a row. Paste it into the editor and select Run:
create table if not exists notes ( id bigint generated always as identity primary key, title text not null, created_at timestamptz default now() ); insert into notes (title) values ('Hello from sac'); select * from notes;The results grid shows the inserted row. The new notes table now appears in the table editor and is immediately queryable over the REST API.
The Auto Generated REST API
Supabase exposes every table in the exposed schemas over a RESTful API created by PostgREST. It is served on the same port 80 through the Kong gateway under the /rest/v1/ prefix. Authenticate with the anon API key from the credentials file.
The following command queries the REST API root. PostgREST answers with an OpenAPI description of every endpoint available on your database:
ANON=$(sudo grep '^supabase.anon.key=' /root/supabase-credentials.txt | cut -d= -f2-)
curl -fsS -o /dev/null -w 'rest api http %{http_code}\n' \
-H "apikey: ${ANON}" \
-H "Authorization: Bearer ${ANON}" \
http://127.0.0.1/rest/v1/A 200 response confirms the REST API is live. Once you create a table such as the notes table from Step 6, it is immediately reachable at http://<public-ip>/rest/v1/notes?select=* from any client that can reach the instance on port 80 and presents the anon key.
The API Docs page in the Studio dashboard documents every auto-generated endpoint for your tables, with ready-to-paste snippets for the JavaScript, Python and other Supabase client libraries.
Connecting a Client Library
The Supabase client libraries connect to the instance with the project URL and the anon key. In JavaScript, for example:
import { createClient } from '@supabase/supabase-js' const supabase = createClient('http://<public-ip>', '<anon-key>') const { data, error } = await supabase.from('notes').select('*')Use the anon key in browser and mobile clients. It is safe to expose and is governed by your Row Level Security policies.
Use the service_role key only on a trusted server. It bypasses Row Level Security and must never be shipped to a client.
The Authentication Service
Select Authentication in the navigation rail. Supabase ships GoTrue, a complete authentication and user management service. From the dashboard you can invite users, configure email and password sign-in, enable social login providers, set up magic links and manage the JSON Web Token settings.
Every authenticated request carries a JWT signed with the per-instance JWT secret, and your Row Level Security policies can reference the authenticated user with the auth.uid() helper.
The Storage Service
Select Storage in the navigation rail. Supabase Storage is an S3-compatible object store for files such as images, videos and documents, with the same Row Level Security model as the database. Create a bucket, upload files through the dashboard or the client libraries, and serve them through the storage API.
The imgproxy service provides on-the-fly image transformations. The object data is stored on the dedicated data volume at /var/lib/supabase/storage.
Server Components
The deployed image contains the following components:
Component Purpose
Supabase self-host stack The open-source Firebase alternative: database, auth, APIs, storage, Studio
Docker Engine Container runtime that hosts the Supabase Compose stack
Docker Compose plugin Brings the Supabase stack up and down as a single Compose project
nginx Reverse proxy on port 80, forwards to the Kong gateway on loopback
supabase.service systemd unit Wraps docker compose up -d / down at the install directory
supabase-firstboot.service systemd unit One shot service that rotates every secret on first boot
Inside the Compose stack the following containers run:
Container Purpose
supabase-db The PostgreSQL database
supabase-kong The Kong API gateway, the single entry point to the stack
supabase-auth GoTrue authentication and user management
supabase-rest PostgREST auto-generated REST API
supabase-realtime Realtime subscriptions over WebSockets
supabase-storage Object and file storage service
supabase-imgproxy On the fly image transformations for storage
supabase-meta postgres-meta, the database management API
supabase-studio The Studio web dashboard
supabase-pooler Supavisor PostgreSQL connection pooler
Filesystem Layout
Path Purpose
/opt/supabase/docker/ Supabase Compose stack: docker-compose.yml, .env, volumes/
/opt/supabase/docker/.env Stack configuration and the per-instance secrets
/opt/supabase/docker/docker-compose.yml The Compose definition for the whole stack
/var/lib/supabase/ Stateful data root on a dedicated EBS volume
/var/lib/supabase/db-data/ PostgreSQL data directory
/var/lib/supabase/storage/ Storage object data
/root/supabase-credentials.txt Per instance dashboard + API credentials, generated on first boot, root only
The data volume is mounted by UUID in /etc/fstab with the nofail option, so the instance always boots even if the volume is detached.
Managing the Services
The Supabase Compose stack is started by systemd at boot through the supabase.service unit. Manage it as follows:
sudo systemctl status supabase.serviceTo restart the whole stack:
sudo systemctl restart supabase.serviceTo inspect or follow individual containers, use docker compose from the install directory:
cd /opt/supabase/docker && sudo docker compose ps --format 'table {{.Name}}\t{{.Status}}'sudo docker compose -f /opt/supabase/docker/docker-compose.yml logs --tail 100 supabase-kong
sudo docker compose -f /opt/supabase/docker/docker-compose.yml logs -f supabase-dbTo follow the systemd unit log:
sudo journalctl -u supabase.service -n 50 --no-pagerConnecting to PostgreSQL Directly
The PostgreSQL database is reachable inside the instance. Connect with the psql client in the database container using the superuser password from the credentials file:
PGPASS=$(sudo grep '^supabase.postgres.password=' /root/supabase-credentials.txt | cut -d= -f2-) sudo docker exec -e PGPASSWORD="$PGPASS" -i supabase-db psql -U postgres -c '\dt'For external clients, the Supavisor connection pooler exposes a pooled connection. For production workloads, keep the database on the private network and connect through a bastion or a VPN rather than exposing the database port to the internet.
Enable HTTPS
The stack listens on plain HTTP on port 80. For any deployment beyond a trusted management network, enable HTTPS so credentials and data cannot be intercepted.
The simplest approach is to terminate TLS at nginx. Obtain a certificate for your domain. Then add a TLS server block to the nginx site at /etc/nginx/sites-available/supabase that listens on 443 with your certificate and proxies to the Kong gateway exactly as the port 80 block does. Reload nginx:
sudo nano /etc/nginx/sites-available/supabase
# add a 'listen 443 ssl;' server block with ssl_certificate / ssl_certificate_key
sudo nginx -t sudo systemctl reload nginxIf you need a free, automatically renewed certificate, install certbot, point it at your domain, and let it manage the nginx TLS configuration.
After enabling HTTPS, update SITE_URL, API_EXTERNAL_URL and SUPABASE_PUBLIC_URL in /opt/supabase/docker/.env to your https:// URL. Restart the stack with sudo systemctl restart supabase.service so the dashboard and the auth redirects use the correct external URL. Then restrict the instance security group so port 443 carries the live traffic.
Backups and Maintenance
Supabase has two data sources that must be backed up together. The first is the PostgreSQL database in /var/lib/supabase/db-data, which holds your schema, rows, users and policies. The second is the Storage object data in /var/lib/supabase/storage, which holds the uploaded files.
The cleanest database backup is a logical dump taken from the running database container:
PGPASS=$(sudo grep '^supabase.postgres.password=' /root/supabase-credentials.txt | cut -d= -f2-) sudo docker exec -e PGPASSWORD="$PGPASS" supabase-db pg_dumpall -U postgres | sudo tee /var/backups/supabase-$(date +%F).sql > /dev/nullShip the dump to an Amazon S3 bucket or another object store, and copy the contents of /var/lib/supabase/storage alongside it.
Because the data root is on its own EBS volume, you can also take EBS snapshots of that volume for point-in-time recovery. For a consistent snapshot, stop the stack first with sudo systemctl stop supabase.service.
For kernel and package updates, Ubuntu's unattended-upgrades is enabled by default, so security patches apply automatically. To upgrade Supabase itself, follow the Supabase self-hosting upgrade documentation at https://supabase.com/docs/guides/self-hosting/docker. Pull the new images with sudo docker compose -f /opt/supabase/docker/docker-compose.yml pull, then restart the stack.
Scaling Beyond a Single Instance
For larger deployments, decouple the stateful tiers from the single-instance pattern:
- Move the PostgreSQL database to Amazon RDS for PostgreSQL or Amazon Aurora by pointing the database connection settings in
.envat the external endpoint - Move the Storage object data to Amazon S3 with the storage service's S3 backend
- Front the Kong gateway with an Application Load Balancer for managed TLS termination and horizontal scaling of the stateless services
- Or run Supabase on Amazon EKS for a fully orchestrated deployment
Screenshots
The Supabase Studio table editor, served on port 80 through an authenticating gateway, showing a database table with its columns and rows.
The Supabase Studio SQL editor running a query against the preinstalled PostgreSQL database and returning rows in the results grid.
The Supabase Studio API documentation page, listing the auto-generated REST endpoints and client snippets for the database tables.
Support and Resources
- SecureAnyCloud support: 24/7 by email and chat for deployment, schema design, Row Level Security, authentication, storage and backups
- Supabase documentation:
https://supabase.com/docs - Supabase self-hosting guide:
https://supabase.com/docs/guides/self-hosting/docker - Supabase GitHub:
https://github.com/supabase/supabase
Deploy on AWS
Launch Supabase on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com