API Gateway Configuration for Self-Hosted Supabase: Kong and Envoy Guide

Configure Kong and Envoy API gateways for self-hosted Supabase with routing, SSL termination, and security best practices.

Cover Image for API Gateway Configuration for Self-Hosted Supabase: Kong and Envoy Guide

When you deploy self-hosted Supabase, the API gateway sits between the outside world and your internal services. Every request—whether it's hitting the REST API, Auth, Storage, or Realtime—passes through this gateway. Getting it wrong means exposing your entire stack. Getting it right means proper routing, authentication enforcement, and a foundation for production security.

Self-hosted Supabase ships with Kong as the default gateway, but recent updates introduced Envoy as an alternative. This guide covers both options, explains when to use each, and walks through the security configurations that matter.

How the API Gateway Fits Into Supabase Architecture

Supabase isn't a single application—it's approximately 12 interconnected services. The API gateway acts as the single entry point, routing requests to:

  • PostgREST at /rest/v1/ for database queries
  • GoTrue at /auth/v1/ for authentication
  • Storage API at /storage/v1/ for file uploads
  • Realtime at /realtime/v1/ for WebSocket connections
  • GraphQL at /graphql/v1/ for GraphQL queries
  • Studio at / for the dashboard

Without proper gateway configuration, these services would need individual ports, separate SSL certificates, and duplicated authentication logic. The gateway consolidates all of this behind a single endpoint.

Kong: The Default Gateway

Self-hosted Supabase uses Kong in DB-less declarative mode. The configuration lives in a static YAML file (kong.yml) rather than a database, making it lightweight and suitable for containerized deployments.

By default, Kong listens on port 8000. The full URL becomes http://<your-domain>:8000 for API requests and dashboard access.

Understanding the Routing Configuration

Routes are matched in order—the first matching prefix wins. Here's what the default configuration exposes:

Protected routes (require apikey header):

  • /auth/v1/ — Authentication endpoints
  • /rest/v1/ — PostgREST Data API
  • /graphql/v1 — GraphQL API
  • /realtime/v1/ — Realtime subscriptions
  • /pg/ — Direct PostgreSQL access (service role only)

Open routes (no API key required):

  • / — Studio dashboard (HTTP Basic Auth instead)

The key detail many self-hosters miss: the /pg/ route only accepts service role keys. Attempting to use an anonymous key returns HTTP 403. This is intentional—direct database access should be restricted.

API Key Handling

Kong handles three authentication steps:

  1. Dashboard Basic Auth — The catch-all / route requires HTTP basic auth using DASHBOARD_USERNAME and DASHBOARD_PASSWORD from your environment variables.

  2. API Key Enforcement — Protected routes require a valid apikey header. Missing or invalid keys return HTTP 401.

  3. Key Translation — The gateway translates opaque API keys (sb_publishable_* and sb_secret_*) into internal JWTs before forwarding requests to services.

The older ANON_KEY and SERVICE_ROLE_KEY HS256 JWT keys still work until the end of 2026, but Supabase recommends migrating to the new key format. You can run both simultaneously during migration.

Envoy: The New Alternative

Supabase introduced an Envoy-based gateway as an optional alternative. Envoy provides more sophisticated routing capabilities and better observability, which matters for production deployments.

Enabling Envoy

The Envoy gateway is a Docker Compose override. If your stack is running:

docker compose down
docker compose -f docker-compose.yml -f docker-compose.envoy.yml up -d

The override disables Kong and starts Envoy on the same port (8000). Both services expose the same network aliases (api-gw and kong), so internal service communication continues working.

Envoy vs Kong: When to Choose Each

Stick with Kong if:

  • You have a working setup and no specific issues
  • Your configuration is simple with no custom routing needs
  • You prefer the Kong ecosystem for plugins and extensions

Consider Envoy if:

  • You need granular traffic control and rate limiting
  • You want better observability with Prometheus metrics out of the box
  • You're running Kubernetes and want consistency with your service mesh
  • You need more sophisticated load balancing algorithms

For most self-hosters, Kong works fine. Envoy becomes attractive when you're scaling beyond a single instance or integrating with existing Envoy-based infrastructure.

SSL Termination: The Right Way

Running production workloads over plain HTTP isn't acceptable. But configuring SSL directly in Kong for self-hosted setups creates unnecessary complexity. The recommended approach: place a reverse proxy in front of the gateway.

Using Caddy for Automatic SSL

Caddy provisions and renews Let's Encrypt certificates with zero configuration. It handles HTTP-to-HTTPS redirects, WebSocket upgrades, and HTTP/2 automatically.

Add to your Docker Compose:

caddy:
  image: caddy:2
  restart: unless-stopped
  ports:
    - "80:80"
    - "443:443"
  volumes:
    - ./Caddyfile:/etc/caddy/Caddyfile
    - caddy_data:/data

Your Caddyfile:

supabase.yourdomain.com {
  reverse_proxy api-gw:8000
}

That's the entire configuration. Caddy requests certificates, renews them before expiration, and proxies all traffic to Kong or Envoy.

For detailed instructions on custom domains and SSL, see our complete custom domains guide.

Security Configuration You Shouldn't Skip

Lock Down Docker Networking

By default, Docker dynamically alters your Linux iptables to route network traffic—bypassing standard firewalls completely. If you map a port without specifying an IP address, it becomes globally accessible.

The fix: explicitly bind services to localhost in your docker-compose.yml:

db:
  ports:
    - "127.0.0.1:5432:5432"

This ensures the database is only accessible from the host machine, not the public internet. Apply the same pattern to any service that shouldn't be directly exposed.

MCP Endpoint Protection

The Model Context Protocol endpoint at /mcp is blocked by default in the gateway configuration. If you enable local access for AI coding tools like Claude Code or Cursor, ensure your allow list contains only trusted IPs.

Don't expose MCP publicly—it's designed for local development workflows.

Dashboard Security

The Studio dashboard at / is protected only by HTTP Basic Auth. This provides minimal security for production environments.

Consider:

  • Using a VPN or bastion host for dashboard access
  • Implementing IP allowlisting at the firewall level
  • Adding an additional authentication layer via your reverse proxy

For teams, some self-hosters run Studio on a separate internal network entirely, only exposing the API endpoints publicly.

Service Role Key Protection

Never expose your service role key (SERVICE_ROLE_KEY or sb_secret_*) in client-side code. This key bypasses Row Level Security and grants full database access.

The gateway enforces this at the /pg/ route level—only service role keys work. But PostgREST and other endpoints accept both key types. Your application code must use the anonymous key for client requests.

Monitoring Gateway Health

Both Kong and Envoy expose health endpoints you should monitor:

Kong:

  • /status returns basic health information
  • Enable the Prometheus plugin for detailed metrics

Envoy:

  • /ready indicates the gateway is ready to receive traffic
  • /stats provides detailed metrics
  • /stats/prometheus formats metrics for Prometheus scraping

Set up alerts for:

  • Gateway container restarts
  • HTTP 5xx error rate spikes
  • Upstream service failures (PostgREST, Auth, etc.)
  • Certificate expiration warnings

For comprehensive monitoring setup, see our monitoring guide.

Common Gateway Issues and Fixes

"Connection refused" on first request

The gateway starts before upstream services are fully ready. Add health checks to your Docker Compose configuration:

kong:
  depends_on:
    db:
      condition: service_healthy
    auth:
      condition: service_healthy

WebSocket connections failing

Ensure your reverse proxy passes WebSocket upgrade headers. For Nginx:

location /realtime/ {
  proxy_pass http://api-gw:8000;
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
}

Caddy handles this automatically.

API keys work locally but fail in production

Check that your reverse proxy isn't stripping the apikey header. Some proxies filter non-standard headers by default.

502 Bad Gateway after service restart

Increase the gateway's retry configuration or add container health checks. Kong and Envoy both support automatic upstream retries.

Production Checklist

Before going live with your gateway configuration:

  • [ ] SSL certificates provisioned and auto-renewing
  • [ ] Database port bound to localhost only
  • [ ] Service role key not exposed in any client code
  • [ ] Dashboard protected beyond basic auth (VPN or IP allowlist)
  • [ ] MCP endpoint blocked or restricted
  • [ ] Health monitoring configured
  • [ ] Backup API keys stored securely (see our backup guide)

What Supascale Handles For You

If configuring Kong, Envoy, SSL, and gateway security sounds like more operational overhead than you want, Supascale handles this automatically. Every project gets:

  • Automatic SSL certificate provisioning and renewal
  • Pre-configured API gateway with secure defaults
  • Custom domain binding with proper routing
  • OAuth provider configuration without touching docker-compose files

Check our pricing—it's a one-time purchase that eliminates the ongoing maintenance burden of gateway configuration and certificate management.

Further Reading