# Supabase self-host stack

Source: https://docs.quake.ai/resources/iac-templates/supabase-selfhost
Markdown: https://docs.quake.ai/resources/iac-templates/supabase-selfhost.md

---

# Supabase self-host stack

This pattern composes Compute, Network, and Block Storage into the full self-hosted Supabase backend you run on infrastructure you control.

## What this template does

Provisions a single instance running the open-source [Supabase](https://supabase.com/docs/guides/self-hosting) stack (the open-source Firebase alternative): a Postgres database with an auto-generated REST API, user authentication, file storage, Realtime subscriptions, and the Studio dashboard. Your application keeps its backend on infrastructure you own:

- Compute instance that runs the full Supabase stack in Docker (Postgres plus the Kong API gateway, Auth, REST, Realtime, Storage, Studio, and the analytics services), sized for 4 vCPU and 16 GiB RAM
- Private network, subnet, router, port, and security group; a floating IP for public access
- A block volume mounted at `/opt/supabase`, so the database, storage uploads, and analytics data live on a volume you can grow rather than on the boot disk
- cloud-init installs Docker Engine, clones the official Supabase compose stack, and brings it up

Every secret is generated on first boot and written to `/opt/supabase/.env`; no credential ships with this template.

## What gets generated on first boot

cloud-init mints all of the following on the instance and never anywhere else:

- The Postgres password and the `JWT_SECRET` that signs every API token
- The `anon` and `service_role` API keys, as HS256 JWTs signed with that secret
- The Studio dashboard username and password
- The Realtime and Vault encryption keys

Read them once over SSH (`sudo cat /opt/supabase/.env`) and store them in your secret manager.

## Parameters

| Parameter | Description | Default |
| --- | --- | --- |
| `key_name` | SSH keypair name (must already exist) | No default |
| `flavor_name` | Instance size (the full stack runs on 4 vCPU / 16 GiB) | `m2a.xlarge` |
| `image_name` | Operating system image | `Ubuntu-24.04` |
| `app_name` | Display name prefix for resources | `supabase` |
| `volume_size` | Block volume size in GiB, mounted at `/opt/supabase` | `40` |
| `external_network` | External network for floating IP allocation | `PublicStatic` |
| `private_cidr` | CIDR for the private subnet | `10.47.0.0/24` |
| `api_allowed_cidr` | CIDR allowed to reach the API gateway (8000) and Studio (3000) | `10.47.0.0/24` |

## Finish setup after apply

cloud-init brings the stack up with the generated keys and a localhost public URL. Complete the setup over SSH so the stack serves your domain:

1. Point a domain's DNS A record at the floating IP and put a reverse proxy (Caddy or Nginx) in front for HTTPS on 443.
2. Edit `/opt/supabase/.env`: set `API_EXTERNAL_URL`, `SITE_URL`, and `SUPABASE_PUBLIC_URL` to your public HTTPS address.
3. Restart the stack:

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

## Access and security

The Kong API gateway listens on port 8000 (REST, Auth, Storage, Realtime) and Studio on port 3000, both over plain HTTP. The security group restricts 8000 and 3000 to `api_allowed_cidr`, which defaults to the private network only. Because Auth callbacks need a public URL, the normal access path is a domain with HTTPS on 443 behind a reverse proxy. Ports 80 and 443 stay open for that proxy; they carry no traffic until you add one.

## When to use this pattern

Run a complete application backend (database, auth, storage, and realtime) on a host you operate, with the Supabase client libraries and Studio dashboard you already know. The single-VM stack suits development, prototyping, and small production workloads. To scale, move Postgres onto a [self-managed PostgreSQL](/resources/iac-templates/self-managed-postgres) instance and run the stateless services behind a load balancer.

## Estimated cost

<PricingCompanion
  components={[
    { kind: "template", slug: "supabase-selfhost", required: true },
  ]}
/>

## Template source

<TemplateSource slug="supabase-selfhost" />

<TemplateResourceMap template="supabase-selfhost" format="opentofu" />

## Customize this pattern

- [Customize a template's image and flavor](/docs/automation/how-to/customize-template-image-flavor)
- [Add a block volume to a template](/docs/automation/how-to/add-volume-to-template)
- [Parameterize a template with a tfvars file](/docs/automation/how-to/parameterize-template-tfvars)

## See also

- [Self-managed PostgreSQL](/resources/iac-templates/self-managed-postgres)
- [S3 object storage](/resources/iac-templates/s3-storage-acl)
- [Coolify host](/resources/iac-templates/coolify-host)
