Databases Azure

Supabase on Ubuntu 24.04 on Azure User Guide

| Product: Supabase on Ubuntu 24.04 LTS on Azure

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 a polished Studio dashboard - everything you need for a complete application backend. The cloudimg image installs the official Supabase docker-compose stack (postgres, kong API gateway, gotrue auth, postgrest, realtime, storage, imgproxy, postgres-meta, studio and supavisor), runs it under Docker behind an nginx reverse proxy on port 80, persists the database and storage on a dedicated Azure data disk, and generates a fresh set of per-VM secrets on the first boot of every VM. Backed by 24/7 cloudimg support.

What is included:

  • The official Supabase self-hosted stack running under Docker (PostgreSQL 17, kong, gotrue, postgrest, realtime, storage, imgproxy, postgres-meta, Studio, supavisor)
  • nginx on :80 as 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 random JWT_SECRET, the matching anon and service_role API keys signed with it, and a Studio dashboard password - recorded in a root-only file
  • A dedicated Azure data disk at /var/lib/supabase for the PostgreSQL data and object storage
  • docker.service + nginx.service as systemd units, enabled and active; the Supabase containers run with restart policies
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet + subnet in the target region. Standard_B4ms (4 vCPU / 16 GiB RAM) is the recommended starting size - the full container stack needs the memory. NSG inbound: 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 cloudimg, 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 Review + create -> Create.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name supabase \
  --image <marketplace-image-urn> \
  --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 1010

Step 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.service

Both report active. You can list the running containers with:

sudo docker compose -f /opt/supabase/docker/docker-compose.yml ps

Supabase container stack running under Docker behind nginx

Step 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.txt

This 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, and the Studio dashboard is protected by basic-auth via the kong gateway:

curl -s http://localhost/health

It 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/

Supabase static health endpoint and the kong basic-auth dashboard check

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.

Supabase Studio project home

The Table Editor lets you create and browse PostgreSQL tables and rows with a spreadsheet-like interface.

Supabase Studio Table Editor

The SQL Editor runs arbitrary SQL against the database - schema changes, queries, functions and policies.

Supabase Studio SQL Editor

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.

Supabase Studio API settings

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; 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/404 (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.

The per-VM anon key authenticating against the auto-generated REST API

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:

findmnt /var/lib/supabase

The 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; the anon and service_role keys are also on the Studio API settings page.
  • Database: PostgreSQL data and storage objects live on the /var/lib/supabase data 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 production use.
  • Security patches: unattended-upgrades remains enabled so the OS continues to receive security updates automatically.

Support

cloudimg provides 24/7 expert support for this image. Contact support@cloudimg.co.uk.