Self-host Supabase
Last updated: June 22, 2026
A huge share of AI-built apps run on Supabase. It's the default Postgres-plus-auth-plus-storage backend that coding agents reach for, and the hosted cloud version is the fastest way to start. But as a project grows, three things start to matter: predictable cost at scale, your data living on a server you control, and no automatic project pausing on idle. Self-hosting gives you all three.
The catch has always been the Linux work — provisioning a server, running Supabase's Docker stack, generating secrets, putting a reverse proxy and TLS in front. This recipe hands that work to your AI assistant. With the American Cloud MCP server connected, your assistant sizes a server, shows you the cost, creates the VM with the right ports open, and then does the whole server setup over SSH.
Why Claude Code for this
Any MCP client can create the infrastructure. But self-hosting Supabase also means running commands on the server: SSH in, install Docker, pull Supabase's self-hosting compose files, generate secrets, bring the stack up. Claude Code combines the American Cloud tools with your terminal, so one session can provision the VM and configure it without you switching tools. That's the setup this recipe assumes. Cursor and the other clients work too — you'll just run the SSH steps yourself when the assistant tells you to.
Provisioning is a write operation. You'll need a read-write API key from
console.americancloud.com/api-keys
and the --allow-writes flag on the MCP server. See the
overview for setup and safety details. Start read-only,
get comfortable, then switch the key when you're ready to build.
Before you start
- A domain you control, with the ability to point its DNS at American Cloud.
- The MCP server connected to your assistant with a read-write key and
--allow-writes. - Decide where your app lives. Supabase is the backend; your app (the frontend or API that talks to it) can live anywhere — see deploy a Next.js app for putting it in front.
Prefer a point-and-click path? American Cloud has a dashboard-based Supabase install in the marketplace — see the Supabase marketplace guide. This page is the AI-driven, full-control alternative: a plain Ubuntu VM plus Supabase's own official self-hosting setup, all driven from your assistant.
Sizing the server
Supabase's self-hosted stack is a set of Docker containers — its own Postgres database, the API gateway, auth, storage, the Studio dashboard, and supporting services — all running together with docker compose. That means you want a VM with enough memory to hold the whole stack comfortably, not a bare minimum box.
Don't guess. Ask your assistant to read Supabase's own published self-hosting requirements and map them onto a VM size, with a cost estimate first:
I want to self-host Supabase on American Cloud. Look up Supabase's official
self-hosting requirements for running their full Docker compose stack, then:
1. List the available regions and Ubuntu LTS images, and the VM packages.
2. Recommend a VM size that meets Supabase's stated requirements for the
self-hosted stack, with some headroom for Docker and my data.
3. Show me the monthly cost estimate for that size before creating anything,
and wait for me to confirm.What your assistant will do
- Survey the options. It calls
list_regions,list_images(filtered to Ubuntu LTS), andlist_vm_packagesto find a region near your users and a compute tier whose CPU and memory limits cover Supabase's stated requirements for the self-hosted stack. - Price it first. It calls
get_cost_estimate_vmwith the exact region, package, size, and image, and shows you the hourly and monthly numbers before creating anything. Nothing is billed until you approve.
Size to Supabase's own published guidance, plus headroom — the stack runs more comfortably when it isn't memory-starved, and you can always resize it later as your data grows.
Create the server
On your go-ahead, the assistant provisions the VM. The important detail here is which ports it opens, and it opens only what Supabase needs to be reachable from the public internet.
Create a small Ubuntu VM for Supabase with the size we agreed on. Put it on an
isolated network, register my SSH key, and open inbound ports 22 (SSH) and 443
(HTTPS) only. Wait until it's fully running and report the public IP.What your assistant will do
- Sort out the SSH key. It calls
list_ssh_keysto see what's registered. If nothing fits,create_ssh_keygenerates a new pair — the private key is returned once and never stored, so the assistant saves it locally (for example to~/.ssh/) with correct permissions. It needs this key both to register on the VM and to SSH in afterward. - Create the VM with the right ports open.
create_vmprovisions the Ubuntu VM. The same call carriesnetworkAccess.inboundPortsto open 22 (SSH) and 443 (HTTPS), andkeypairsto install your SSH key.networkAccess.inboundPortsopens the firewall rule and the port forwarding to the network's public IP together, so those ports are genuinely reachable — not just allowed in one place. - Wait for it to be ready. The VM provisions asynchronously, so the assistant polls
get_vmuntil its status reachesSTARTEDand it has a public IP.
Why only 22 and 443? Supabase's self-hosted architecture puts a single proxy in front of the whole stack, and everything else — its database, the auth and storage services, the internal APIs — is designed to talk to each other inside the Docker network, not over the public internet. So you expose 443 for the proxy (HTTPS) and 22 for your own SSH access, and you keep the rest internal. That's Supabase's own design; you're just honoring it at the firewall.
If you later decide a port genuinely needs to be reachable, opening it takes two rules, not one: a firewall rule alone won't make traffic arrive. Ask your assistant to add it and it will create both create_firewall_rule and create_port_forwarding_rule (or use enable_static_nat to map a dedicated public IP to the VM). Keep that surface as small as Supabase's architecture allows.
Set up Supabase over SSH
With the VM running, the assistant moves to the terminal. This is the part Claude Code does in the same session.
SSH into the VM and set up Supabase using their official self-hosting Docker
instructions:
1. Install Docker Engine and the Docker Compose plugin.
2. Pull Supabase's official self-hosting compose files onto the server.
3. Generate all the required secrets ON THE SERVER — the Postgres password,
the JWT secret, and the anon and service keys derived from it. Do not print
the secret values into our chat; write them straight into the env file and
tell me only that they were generated.
4. Bring the stack up with docker compose and confirm all containers are
healthy.What your assistant will do
- Install Docker. Over SSH it installs Docker Engine and the Compose plugin on the Ubuntu VM.
- Fetch Supabase's self-hosting setup. It pulls Supabase's official self-hosting compose files (the ones Supabase publishes for running the stack with
docker compose) onto the server. This includes Supabase's own bundled Postgres — that database is a component of the Supabase stack, lives inside the compose project, and is what your app connects to. - Generate the secrets server-side. Supabase needs a database password, a JWT secret, and the
anonandserviceAPI keys derived from that secret. The assistant generates these on the server and writes them directly into Supabase's environment file — not into the chat transcript. Secrets that scroll through a chat window are a leak risk; keeping them on the box is the safe default. - Bring the stack up. It runs
docker compose up -dfrom Supabase's compose directory, then checks that the containers report healthy.
Ask the assistant to generate every secret on the server and never echo the values into the chat — "write them into the env file and just tell me they were set." You can read them back over SSH yourself when you need them (for example to configure your app). This keeps long-lived credentials out of any conversation history.
Proxy, DNS, and HTTPS
The last piece is making Supabase reachable on your domain over HTTPS. Supabase's stack already includes a proxy for routing to its internal services; you put a TLS-terminating reverse proxy in front so the only thing exposed on port 443 is encrypted traffic on your domain.
Now make Supabase reachable at {your-domain.com} over HTTPS:
1. Configure nginx on the VM as a reverse proxy in front of the Supabase stack,
listening on 443.
2. Add a DNS A record pointing {your-domain.com} at the VM's public IP.
3. Once DNS resolves, provision a Let's Encrypt certificate with certbot and
enable automatic renewal.
Then confirm the Studio dashboard and the API both respond over HTTPS.What your assistant will do
- Put a reverse proxy in front. It configures nginx (or Supabase's own proxy, per their docs) to terminate TLS on 443 and route to the Supabase services on the Docker network.
- Point the domain at it. It calls
list_dns_zonesto see if your domain is already hosted. If not,create_dns_zoneadds it (you'll then update your registrar's nameservers to American Cloud's, which the assistant can show you). Thencreate_dns_recordadds anArecord for the domain pointing at the VM's public IP. - Turn on HTTPS. Once DNS resolves to the VM, it runs certbot to obtain a Let's Encrypt certificate, switches the proxy to HTTPS, and enables automatic renewal.
- Verify. It checks that the Supabase Studio dashboard loads and the API responds over
https://{your-domain.com}.
When it's done, you have a full Supabase backend — database, auth, storage, and Studio — running on a server you own, behind your domain and HTTPS, with only the ports Supabase needs exposed.
DNS changes take time to propagate — anywhere from a few minutes to a couple of hours. certbot needs the domain to resolve to the VM before it can issue a certificate, so the HTTPS step may have to wait. Ask your assistant to "check what {your-domain.com} currently resolves to and tell me when it points at the VM's IP."
Moving an existing Supabase cloud project
If you already have a project on Supabase cloud, migrating to your self-hosted instance is two pieces: the database and the storage objects. This is the high-level shape — your assistant can drive it, but treat a large or live project carefully.
- Database. Take a logical dump of your cloud project's Postgres with
pg_dumpand restore it into your self-hosted stack's database withpg_restore(orpsql). Your assistant can run both ends over SSH and tell you exactly which connection strings it's using. - Storage objects. If your project uses Supabase Storage, the objects move with
rclonewhen the source is S3-compatible, or with Supabase's own storage tooling. Either way it's a copy from the old bucket into the new one. - App config. Point your app at the new backend by updating its
SUPABASE_URLand theanon/servicekeys to the values from your self-hosted instance (the ones generated server-side during setup).
For anything beyond a small project, test the migration on a copy first. Dump and restore into a throwaway self-hosted instance, point a staging copy of your app at it, and confirm auth, row-level security policies, and storage all behave before you cut production over. Schema extensions, custom roles, and large object stores are where surprises hide.
Day-2: running it
Once Supabase is live, treat the VM like any server you own.
- Snapshot before you upgrade. Before bumping Supabase versions or changing the stack, ask your assistant to take a snapshot with
create_snapshotso you can roll back. See backups with your AI assistant for the full backup-and-restore workflow. - Resize as it grows. When your data or traffic outgrows the box, your assistant can
scale_vmto a larger size (it may require a brief restart) — no rebuild, no migration. - Keep large files off the VM disk. If your app stores user uploads or big assets in Supabase Storage, consider backing them with object storage, which is S3-compatible and metered by usage rather than filling a fixed disk.
- When SSH isn't available. If you ever lock yourself out, the assistant can reset access with
reset_vm_passwordor open a browser-based session withcreate_vm_console.
Troubleshooting
A container won't start or the stack is unhealthy. Ask your assistant to "SSH in and show me the docker compose logs for the unhealthy Supabase containers." Most first-run issues are a missing or mistyped value in the env file — the assistant can read the logs and pinpoint it without printing the secrets back to you.
The domain doesn't load over HTTPS. Have the assistant confirm DNS resolves to the VM and that certbot issued a certificate. If DNS is still propagating, certbot can't validate yet — wait and retry. If DNS resolves but the page is unreachable, ask it to "list the firewall rules on the VM's public IP and confirm 443 is open" (list_firewall_rules), and to check the proxy container is running.
Studio loads but the API doesn't respond. This is usually proxy routing — the reverse proxy reaching the dashboard but not the API service. Ask the assistant to review the proxy config against Supabase's published routing and the running container ports.
Next steps
- Deploy a Next.js app — put the app that talks to Supabase in front of it, on its own server and domain.
- Deploy with Docker Compose — the general pattern for running any compose-based stack on a VM.
- Backups with your AI assistant — snapshots, off-site dumps, and restore drills so an upgrade can never cost you data.
- Write an AGENTS.md for your project — teach your assistant your stack and conventions so future steps are one prompt.