Supabase brings PostgreSQL, authentication, storage, Realtime, Edge Functions, and a web-based management dashboard into one backend platform. When you self-host it, you're responsible for server and database maintenance, backups, monitoring, and deciding which services should be reachable from the internet.
I'm going to use NetBird to keep administrative and database access on a private network, then limit which devices can connect.
In this guide, we're going to:
- Install NetBird and the official Supabase Docker stack.
- Bind the gateway and database pooler to the NetBird IP before starting Supabase.
- Create groups and access policies for administrators, developers, and application servers.
- Optionally add HTTPS hostnames for Studio and the application APIs with NetBird's reverse proxy.
We'll start with the private setup below, then cover the optional public API:
Simply knowing the public IP address of the server isn't enough to reach these services. The device also needs to be connected through NetBird and permitted by an access policy.
What Is Supabase?
Supabase is an open-source backend platform built around a standard PostgreSQL database. It adds PostgREST for a REST API, GoTrue for authentication, Realtime for WebSocket updates, Storage for files, and Edge Functions for server-side code. You keep SQL, foreign keys, and support for Postgres extensions.
Supabase Studio is the management dashboard, while Supavisor pools database connections. Self-hosting lets you run these services on your own infrastructure.
The officially recommended way to self-host Supabase is Docker Compose. Supabase currently lists 4 GB of RAM and 2 CPU cores as the minimum for the complete stack, while recommending at least 8 GB of RAM, 4 CPU cores, and 80 GB of SSD storage for a more comfortable deployment.
For this guide, I recommend an Ubuntu or Debian server with at least:
A small VPS, dedicated server, or home server will work.
Why Add NetBird?
Publishing a Docker container port can make it reachable through the host's network interfaces. Studio lets administrators inspect databases, execute SQL, manage users and storage, and make other significant changes. That access, along with direct database connections, should be limited to trusted devices.
NetBird adds network access control through groups and policies . We can allow specific source groups to reach the Supabase server on selected ports, while Supabase's own authentication and database permissions control what they can do once connected.
Step 1: Prepare the Server
Start by updating the system.
You'll also want SSH access to the server before making any network changes.
Check the current IP addresses with:
At this point, your server probably has a public IP, private LAN IP, or both.
We will eventually configure Supabase so its important ports bind specifically to the NetBird interface instead.
Step 2: Install NetBird
Install NetBird first so we have the private address for Supabase's port mappings. Use the Linux installation command :
Connect the server to your NetBird account interactively:
For a server, use a setup key so enrollment doesn't require a browser on the remote machine. Create a key in the NetBird dashboard, then run:
Check the connection:
The server should now appear under Peers in the NetBird dashboard. Make note of its NetBird IP address. NetBird uses by default; I'll use as a placeholder throughout this guide. Replace it everywhere with your server's actual address.
Step 3: Install Supabase
Use Supabase's official Linux setup script :
The installer supports common Debian/Ubuntu and RHEL-family Linux distributions. It can install prerequisites and Docker Engine, fetch the Supabase configuration, generate secrets, and create the project directory.
The default project directory is . When prompted for the gateway URLs, use your server's NetBird address:
is where Supabase's auth service redirects the browser after an auth action finishes (email confirmation, magic link, password reset, OAuth callback). Point it at your frontend, not at Supabase itself.
For a test frontend running on your own computer, can be .
At the prompt, accept the suggested NetBird IP. That field is used by Supabase's bundled Caddy or Nginx overlays, which we aren't enabling in this guide.
The URLs and generated credentials, including database and dashboard passwords, API keys, and signing keys, are saved in . You can edit the URLs later. Keep this file private and out of version control.
Step 4: Bind the Supabase Gateway to NetBird
Before starting Supabase, we'll restrict its published ports to the NetBird IP. Move into the project directory:
The default Docker stack publishes three ports:
| Port | Service | Purpose |
|---|---|---|
| 8000 | Envoy API gateway | Studio, REST, Auth, Storage, Realtime, and Edge Functions |
| 5432 | Supavisor session mode | Persistent PostgreSQL clients that need session features |
| 6543 | Supavisor transaction mode | Workloads with many short-lived connections |
The database container isn't directly exposed; Supavisor handles external database connections . We'll bind all three published ports to the host's NetBird IP.
Open:
Find the service.
You'll see a port mapping similar to:
Change this to your NetBird address:
This publishes the gateway on the host's NetBird IP.
Step 5: Bind the Database Pooler to NetBird
Next, locate the service.
The current configuration publishes:
Change those to:
Save the file.
Step 6: Start Supabase
With all three port mappings set to your NetBird IP, start the stack:
The helper starts the Docker Compose deployment and waits for the services to become healthy.
Check the containers:
You should eventually see the Supabase services reporting that they're running and healthy.
If something fails, Supabase also provides:
To inspect an individual service's logs, use its Compose service name. For example:
Step 7: Access Supabase Studio
Open to reach Studio through the gateway. You should see the Supabase login prompt.
Use (default: ) and the generated from the project's file.
You can display the password and other generated secrets with:
For now, the entire gateway is private, including the application APIs that share port with Studio.
Step 8: Verify the Network Bindings
Check which interfaces are listening:
Instead of seeing:
you should see your NetBird IP:
A service listening on:
is listening on every IPv4 interface.
A service listening on:
is specifically bound to that interface.
Step 9: Test Public vs. Private Access
From a machine that is not connected to NetBird, try:
It should fail.
Now connect your computer to NetBird.
Open:
Supabase Studio should load.
We've now removed the public network path to the service.
But we can go further.
At the moment, other NetBird peers may still have access depending on the policies configured in your account.
Next we'll restrict that.
Step 10: Create Groups and Policies
Go to Access Control → Groups and create:
Assign the Supabase server to , then put your own admin, developer, and application-server peers into the matching group.
Next, go to Access Control → Policies → Add Policy and create three policies. For each one, set source to the group below, destination to , protocol TCP, and direction Unidirectional:
| Policy | Source | Ports |
|---|---|---|
| Supabase Administrators | supabase-admins | 8000, 5432, 6543 |
| Supabase Developers | supabase-developers | 8000 |
| Supabase Application Servers | supabase-app-servers | 5432 |
Administrators can reach the gateway and both database pooler ports. Developers get gateway access, including Studio and the application APIs, without direct pooler access. Application servers get the session pooler on .
Studio credentials still allow database administration, including SQL execution. Blocking direct pooler connections doesn't restrict what developers can do through Studio. Adjust these grants to your team's needs; developers running migrations might also need .
Do note that the default policy and other broad allow rules can still grant wider access. Disable or narrow them once replacement policies cover SSH and any other access you need.
Step 11: Test the Policies
From an admin machine, both should succeed:
Supavisor requires the tenant ID in the username. Replace with the server's value from , then enter its when prompted.
From a developer machine, the gateway works but the database port doesn't:
From any other NetBird peer, both fail:
Being connected to NetBird doesn't automatically mean being trusted with every resource.
Exposing Studio and a Frontend with the NetBird Reverse Proxy
So far, we've reached Supabase through its NetBird IP. The built-in reverse proxy adds hostnames and automatic TLS, with access settings for each service. We'll use it for Studio and, optionally, a public API that a frontend can call.
NetBird's reverse proxy supports HTTP, TCP, UDP, and TLS services , but NetBird-Only authentication is available only for HTTP services. We'll use it for the API gateway on and keep the database ports and behind the groups and policies from Steps 10-11.
One prerequisite too: the private access mode below needs a proxy cluster with the Private capability. Self-hosted, that's in plus a one-line Traefik routing fix for the proxy's gRPC service. On NetBird Cloud, the shared clusters don't have that capability, so you'd need to run your own Bring Your Own Proxy cluster to use it.
Give Studio an HTTPS Hostname
In the dashboard, go to Reverse Proxy → Add Service. Pick a subdomain, like , and set the target to the Supabase peer's NetBird address on port , the same address from Step 4.
Under Authentication, choose NetBird-Only and set the access groups to and . The service resolves inside your NetBird network automatically, and the proxy authenticates requests through the NetBird connection. Studio still requires the dashboard credentials from Step 7.
For user-owned devices, also add the admin and developer users to their matching groups under Team → Users. NetBird-Only Access checks the owning user's group membership, so assigning a group only to the peer in Step 10 isn't enough. For peers without an owning user, it checks the peer's own groups instead.
You can now use an HTTPS hostname such as to reach Studio privately.
Connect a Frontend App
For a frontend, you can let the browser talk to Supabase directly with . First, create a separate public API service in NetBird:
- Go to Reverse Proxy → Services → Add Service. Choose HTTP, enter as the subdomain, and select the same base domain you used for Studio.
- Click Add Target, choose Peer, and select the Supabase server. Set the target protocol to HTTP, port to , and path to . Add another target pointing to the same peer and port with as its path. Add other API paths only as your app needs them, such as , , , or . Preserve the original API paths when forwarding requests; see path-based routing .
- Under Authentication, leave proxy-level authentication disabled for this public API service. Keep NetBird-Only enabled on the separate Studio service.
- Save the service and copy its full HTTPS URL into the Supabase URL settings below. With as the base domain, this will be .
Do not add a catch-all target to that public service. Studio uses the same gateway, so forwarding every path to port also makes Studio reachable through the public API hostname. Its dashboard password still applies, but the separate NetBird-Only hostname doesn't make that public route private.
Before updating , verify that the new HTTPS URL has a valid certificate, the required API requests work, and requests to , Studio routes such as , and the administrative path are rejected by the public proxy. They should never reach Studio or the database management API through that hostname.
Public API access relies on Supabase's authentication and authorization. Before exposing your data:
- Enable row-level security (RLS) on tables in exposed schemas, define policies for the intended users, and grant database roles only the operations they need.
- Use , or the legacy , in browser clients. Keep and on trusted backends; these privileged keys can bypass RLS. See the self-hosted API key guide .
- Review Storage access policies and ensure your Edge Functions enforce the required authentication and authorization. Table RLS doesn't replace access checks in custom endpoints.
If you'd rather keep the gateway private too, use a frontend with a server-side backend and expose the frontend itself as a reverse proxy service. Join the frontend server to NetBird and assign its peer to a dedicated group. Add a Unidirectional TCP policy from to on port , then point the backend's Supabase client at . The existing application-server policy only allows database connections on .
The browser sends application requests to your backend, which handles authentication and authorization before calling Supabase. Browser-side calls from public visitors can't reach the private gateway, so those calls need to move into your backend. If the app needs Realtime updates, your backend also needs to relay them to the browser.
Keep Studio's proxy service NetBird-Only, restricted to and , and ensure no public proxy service forwards requests to its routes.
Update Supabase's URLs
Once the NetBird service is configured and its HTTPS URL works, update the Supabase URL settings in the project's file. For a public API service created at , use:
Replace these hostnames with your own, and point your browser's Supabase client at the same API origin. If you're only adding the private Studio hostname, use for and add for . If your gateway keeps using its raw NetBird IP, keep the original gateway URL settings. In every case, should point to your frontend.
Review any additional frontend redirects in . If you use OAuth, update the provider's registered callback URL to your chosen gateway's address. Then apply the changes from the Supabase project directory:
Test Studio and your application's sign-in and redirect flows using the new hostnames.
Separating Development and Production
For multiple environments, use a separate destination group for each: , , and . Scope policies to match:
| Source | Destination | Ports |
|---|---|---|
| Developers | supabase-dev | 8000, 5432 |
| Developers | supabase-staging | 8000 |
| DevOps | supabase-production | 8000, 5432 |
| Production App Servers | supabase-production | 5432 |
This gives you network-level segmentation on top of whatever authentication exists inside the applications themselves.
Production Considerations
Putting Supabase behind NetBird doesn't remove the rest of your operational responsibilities.
Plan for the following before using the deployment in production:
Backups
Back up the PostgreSQL database, locally stored files, and the configuration and secrets needed to restore the deployment. Keep a protected copy off the server and test that you can restore it.
Updates
Supabase publishes stable snapshots of its Docker Compose stack and provides an update.sh workflow for self-hosted installations. Review the release notes and back up your data before updating. Avoid replacing individual services with arbitrary images.
Secrets
Restrict access to the file and any backups containing credentials. For production, consider a dedicated secrets manager. Give application database roles only the permissions they need.
HTTPS
NetBird traffic itself is encrypted, but production applications may still require HTTPS, particularly when browsers, OAuth providers, or public users are involved.
Monitoring
Monitor CPU, memory, disk capacity, PostgreSQL and container health, application errors, and backup jobs.
Self-hosting means that when the server goes down, you're the hosting provider.
Conclusion
We now have a Supabase stack with its published ports on the server's NetBird IP and access policies for each group of devices. If your app needs public access, expose its required API routes while keeping Studio private, and enforce application permissions with Supabase's authentication and database controls.
The same approach works for other internal dashboards, databases, and development tools. When you're ready to expand it, the NetBird access control guide covers how to manage groups and policies across your network.
