Self-Hosting

Self-Hosting with Docker

Learn how to configure and deploy Supabase with Docker.


Docker is the easiest way to get started with self-hosted Supabase. It should take you less than 30 minutes to get up and running.

Contents

  1. Before you begin
  2. System requirements
  3. Installing Supabase
  4. Configuring and securing Supabase
  5. Starting and stopping
  6. Accessing Supabase services
  7. Updating
  8. Uninstalling
  9. Advanced topics

Before you begin

This guide assumes you're comfortable with:

  • Linux server administration basics
  • Docker and Docker Compose
  • Networking fundamentals (ports, DNS, firewalls)

If you're new to these topics, consider starting with managed Supabase for free, or try local development with the CLI.

You need the following installed on your system:

System requirements

Baseline server requirements for running all Supabase components. These are suitable for development and small to medium production workloads:

ResourceMinimumRecommended
RAM4 GB8 GB+
CPU2 cores4 cores+
Disk50 GB SSD80 GB+ SSD

If you don't need specific services, such as Analytics (Logflare), Realtime, Storage, Auth, or PostgREST, you can exclude them from docker-compose.yml to reduce resource requirements.

Installing Supabase

Follow these steps to start Supabase on your machine:

1
# Get the code
2
git clone --depth 1 https://github.com/supabase/supabase
3
4
# Make your new supabase project directory
5
mkdir supabase-project
6
7
# Tree should look like this
8
# .
9
# ├── supabase
10
# └── supabase-project
11
12
# Copy the compose files over to your project
13
cp -rf supabase/docker/* supabase-project
14
15
# Copy the fake env vars
16
cp supabase/docker/.env.example supabase-project/.env
17
18
# Switch to your project directory
19
cd supabase-project
20
21
# Pull the latest images
22
docker compose pull

Configuring and securing Supabase

While we provided example placeholder passwords and keys in the .env.example file, you should NEVER start your self-hosted Supabase using these defaults.

Configure database password

Change the placeholder password in the .env file before starting your Supabase for the first time.

  • POSTGRES_PASSWORD: the password for the postgres and supabase_admin database roles

Follow the password guidelines for choosing a secure password. For easier configuration, use only letters and numbers to avoid URL encoding issues in connection strings.

Generate and configure API keys

Use the key generator below to obtain and configure the following secure keys in .env:

  • JWT_SECRET: Used by PostgREST and GoTrue to sign and verify JWTs.
  • ANON_KEY: Client-side API key with limited permissions (anon role). Use this in your frontend applications.
  • SERVICE_ROLE_KEY: Server-side API key with full database access (service_role role). Never expose this in client code.
  1. Copy the generated value and update JWT_SECRET in the .env file. Do not share this secret publicly or commit it to version control.
  2. Copy the generated value and update ANON_KEY in the .env file.
  3. Copy the generated value and update SERVICE_ROLE_KEY in the .env file.

The generated keys expire in 5 years. You can verify them at jwt.io using the JWT secret.

Configure other keys, and important URLs

Edit the following settings in the .env file:

  • SECRET_KEY_BASE: encryption key for securing Realtime and Supavisor communications. (Must be at least 64 characters; generate with openssl rand -base64 48)
  • VAULT_ENC_KEY: encryption key used by Supavisor for storing encrypted configuration. (Must be exactly 32 characters; generate with openssl rand -hex 16)
  • PG_META_CRYPTO_KEY: encryption key for securing connection strings used by Studio against postgres-meta. (Must be at least 32 characters; generate with openssl rand -base64 24)
  • LOGFLARE_PUBLIC_ACCESS_TOKEN: API token for log ingestion and querying. Used by Vector and Studio to send and query logs. (Must be at least 32 characters; generate with openssl rand -base64 24)
  • LOGFLARE_PRIVATE_ACCESS_TOKEN: API token for Logflare management operations. Used by Studio for administrative tasks. Never expose client-side. (Must be at least 32 characters; generate with openssl rand -base64 24)

Review and change URL environment variables:

  • SUPABASE_PUBLIC_URL: the base URL for accessing your Supabase via the Internet, e.g, http://example.com:8000
  • API_EXTERNAL_URL: the base URL for API requests, e.g., http://example.com:8000
  • SITE_URL: the base URL of your site, e.g., http://example.com:3000

Studio authentication

Access to Studio dashboard and internal API is protected with HTTP basic authentication.

Change the password in the .env file:

  • DASHBOARD_PASSWORD: password for Studio / dashboard

The password must include at least one letter (do not use numbers only).

Optionally change the user:

  • DASHBOARD_USERNAME: username for Studio / dashboard

Starting and stopping

You can start all services by using the following command in the same directory as your docker-compose.yml file:

1
# Start the services (in detached mode)
2
docker compose up -d

After all the services have started you can see them running in the background:

1
docker compose ps

After a minute or less, all services should have a status Up [...] (healthy). If you see a status such as created but not Up, try inspecting the Docker logs for a specific container, e.g.,

1
docker compose logs analytics

To stop Supabase, use:

1
docker compose down

Accessing Supabase services

After the Supabase services are configured and running, you can access the dashboard, connect to the database, and use edge functions.

Accessing Supabase Studio

You can access Supabase Studio through the API gateway on port 8000.

For example: http://example.com:8000, or http://<your-ip>:8000 (or localhost:8000 if you are running Docker Compose locally).

You will be prompted for a username and password. Use the credentials that you set up earlier in Studio authentication.

Accessing Postgres

By default, the Supabase stack provides the Supavisor connection pooler for accessing Postgres and managing database connections.

You can connect to the Postgres database via Supavisor using the methods described below. Use your domain name, your server IP, or localhost depending on whether you are running self-hosted Supabase on a VPS, or locally.

The default POOLER_TENANT_ID is your-tenant-id (can be changed in .env), and the password is the one you set previously in Configure database password.

For session-based connections (equivalent to a direct Postgres connection):

1
psql 'postgres://postgres.[POOLER_TENANT_ID]:[POSTGRES_PASSWORD]@[your-domain]:5432/postgres'

For pooled transactional connections:

1
psql 'postgres://postgres.[POOLER_TENANT_ID]:[POSTGRES_PASSWORD]@[your-domain]:6543/postgres'

When using psql with command-line parameters instead of a connection string to connect to Supavisor, the -U parameter should also be postgres.[POOLER_TENANT_ID], and not just postgres.

If for some reason you need to configure Postgres to be directly accessible from the Internet, read Exposing your Postgres database below.

Accessing Edge Functions

Edge Functions are stored in volumes/functions. The default setup has a hello function that you can invoke on http://<your-domain>:8000/functions/v1/hello.

You can add new Functions as volumes/functions/<FUNCTION_NAME>/index.ts. Restart the functions service to pick up the changes: docker compose restart functions --no-deps

Accessing the APIs

Each of the APIs is available through the same API gateway:

  • REST: http://<your-domain>:8000/rest/v1/
  • Auth: http://<your-domain>:8000/auth/v1/
  • Storage: http://<your-domain>:8000/storage/v1/
  • Realtime: http://<your-domain>:8000/realtime/v1/

Updating

We publish stable releases of the Docker Compose setup approximately once a month. To update, pull the latest changes from the repository and restart the services. If you want to run different versions of individual services, you can change the image tags in the Docker Compose file, but compatibility is not guaranteed. All Supabase images are available on Docker Hub.

To follow the changes and updates, refer to the self-hosted Supabase changelog.

You need to restart services to pick up the changes, which may result in downtime for your applications and users.

Example: You'd like to update or rollback the Studio image. Follow the steps below:

  1. Check the supabase/studio images on Supabase Docker Hub
  2. Find the latest version (tag) number. It looks something like 2025.11.26-sha-8f096b5
  3. Update the image field in the docker-compose.yml file. It should look like this: image: supabase/studio:2025.11.26-sha-8f096b5
  4. Run docker compose pull, followed by docker compose down && docker compose up -d to restart Supabase.

Uninstalling

To uninstall, stop Supabase (while in the same directory as your docker-compose.yml file):

1
# Stop docker and remove volumes:
2
docker compose down -v

Remove all Postgres data:

1
rm -rf volumes/db/data/

Advanced topics

Everything beyond this point in the guide helps you understand how the system works and how you can modify it to suit your needs.

Architecture

Supabase is a combination of open source tools specifically developed for enterprise-readiness.

If the tools and communities already exist, with an MIT, Apache 2, or equivalent open source license, we will use and support that tool. If the tool doesn't exist, we build and open source it ourselves.

  • Studio - A dashboard for managing your self-hosted Supabase project
  • Kong - Kong API gateway
  • GoTrue - JWT-based authentication API for user sign-ups, logins, and session management
  • PostgREST - Web server that turns your Postgres database directly into a RESTful API
  • Realtime - Elixir server that listens to Postgres database changes and broadcasts them to subscribed clients
  • Storage - RESTful API for managing files in S3, with Postgres handling permissions
  • ImgProxy - Fast and secure image processing server
  • postgres-meta - RESTful API for managing Postgres (fetch tables, add roles, run queries)
  • PostgreSQL - Object-relational database with over 30 years of active development
  • Edge Runtime - Web server based on Deno runtime for running JavaScript, TypeScript, and WASM services
  • Logflare - Log management and event analytics platform
  • Vector - High-performance observability data pipeline for logs
  • Supavisor - Supabase's Postgres connection pooler

For the system to work cohesively, some services require additional configuration within the Postgres database. For example, the APIs and Auth system require several default roles.

You can find all the default extensions inside the schema migration scripts repo. These scripts are mounted at /docker-entrypoint-initdb.d to run automatically when starting the database container.

Configuring services

Each service has a number of configuration options you can find in the related documentation.

Configuration options are generally added to the .env file and referenced in docker-compose.yml service definitions, e.g.,

1
services:
2
rest:
3
image: postgrest/postgrest
4
environment:
5
PGRST_JWT_SECRET: ${JWT_SECRET}

Common configuration tasks

You can configure each Supabase service separately through environment variables and configuration files. Below are the most common configuration options.

Configuring an email server

You will need to use a production-ready SMTP server for sending emails. You can configure the SMTP server by updating the following environment variables:

1
SMTP_ADMIN_EMAIL=
2
SMTP_HOST=
3
SMTP_PORT=
4
SMTP_USER=
5
SMTP_PASS=
6
SMTP_SENDER_NAME=

We recommend using AWS SES. It's extremely cheap and reliable. Restart all services to pick up the new configuration.

Configuring S3 Storage

By default all files are stored locally on the server. You can configure the Storage service to use S3 by updating the following environment variables:

1
storage:
2
environment: STORAGE_BACKEND=s3
3
GLOBAL_S3_BUCKET=name-of-your-s3-bucket
4
REGION=region-of-your-s3-bucket

You can find all the available options in the storage repository. Restart the storage service to pick up the changes: docker compose restart storage --no-deps

Configuring Supabase AI Assistant

Configuring the Supabase AI Assistant is optional. By adding your own OPENAI_API_KEY, you can enable AI services, which help with writing SQL queries, statements, and policies.

1
services:
2
studio:
3
image: supabase/studio
4
environment:
5
OPENAI_API_KEY: ${OPENAI_API_KEY:-}

Setting database's log_min_messages

By default, docker compose sets the database's log_min_messages configuration to fatal to prevent redundant logs generated by Realtime. You can configure log_min_messages using any of the Postgres Severity Levels.

Accessing Postgres through Supavisor

By default, Postgres connections go through the Supavisor connection pooler for efficient connection management. Two ports are available:

  • POSTGRES_PORT (default: 5432) – Session mode, behaves like a direct Postgres connection
  • POOLER_PROXY_PORT_TRANSACTION (default: 6543) – Transaction mode, uses connection pooling

For more information on configuring and using Supavisor, see the Supavisor documentation.

Exposing your Postgres database

By default, Postgres is only accessible through Supavisor. If you need direct access to the database (bypassing the connection pooler), you need to disable Supavisor and expose the Postgres port.

Update docker-compose.yml:

  1. Disable Supavisor - Comment out or remove the entire supavisor service section
  2. Expose Postgres port - Add the port mapping to the db service:
1
db:
2
ports:
3
- ${POSTGRES_PORT}:${POSTGRES_PORT}

You can then connect to the database directly using a standard Postgres connection string:

1
postgres://postgres:[POSTGRES_PASSWORD]@[your-server-ip]:5432/[POSTGRES_DB]

File storage backend on macOS

By default, Storage backend is set to file, which is to use local files as the storage backend. For macOS compatibility, you need to choose VirtioFS as the Docker container file sharing implementation (in Docker Desktop -> Preferences -> General).

Setting up logging with the Analytics server

Additional configuration is required for self-hosting the Analytics server. For the full setup instructions, see Self Hosting Analytics.

Upgrading Analytics

Due to the changes in the Analytics server, you will need to run the following commands to upgrade your Analytics server:

1
### Destroy analytics to transition to postgres self hosted solution without other data loss
2
3
# Enter the container and use your .env POSTGRES_PASSWORD value to login
4
docker exec -it $(docker ps | grep supabase-db | awk '{print $1}') psql -U supabase_admin --password
5
# Drop all the data in the _analytics schema
6
DROP PUBLICATION logflare_pub; DROP SCHEMA _analytics CASCADE; CREATE SCHEMA _analytics;\q
7
# Drop the analytics container
8
docker rm supabase-analytics

Managing your secrets

Many components inside Supabase use secure secrets and passwords. These are listed in the self-hosting env file, but we strongly recommend using a secrets manager when deploying to production.

Some suggested systems include:


Demo

  1. The VPS instance is a DigitalOcean droplet. (For server requirements refer to System requirements)
  2. To access Studio, use the IPv4 IP address of your Droplet.
  3. If you're unable to use Studio, run docker compose ps to see if all services are up and healthy.