Deploy Supabase Lite
Minimal self-hosted Supabase: 7 core services, ~1.5 GB RAM, ~$10-15/mo.
Just deployed
realtime
Just deployed
Just deployed
Just deployed
/var/lib/postgresql
Just deployed
Just deployed
Just deployed
/data
Deploy and Host
A minimal, cost-optimized self-hosted Supabase stack for Railway. Unlike the full 12-service Supabase template that needs 4–8 GB RAM, Supabase Lite runs the 7 core services in ~1.5 GB RAM for roughly $10–15/mo.
About Hosting
Supabase Lite runs 7 Docker-based services on Railway's managed infrastructure. All inter-service communication uses Railway private networking (*.railway.internal). Only the Kong gateway is exposed publicly via a Railway domain. Two persistent volumes are provisioned automatically: postgres-data (mounted at /var/lib/postgresql) and minio-data (mounted at /data).
Why Deploy
- Cost-efficient: ~1.5 GB RAM total vs 4–8 GB for the full Supabase template
- Production-ready auth, REST, realtime, and storage — the core Supabase API surface
- Private by default: only Kong is public; all other services are internal
- No vendor lock-in: standard Supabase images, portable schemas, standard Postgres
Common Use Cases
- Self-hosted backend for a web or mobile app needing auth + database + storage
- Cost-conscious Supabase alternative for hobby/staging projects
- API gateway pattern with Kong routing to auth/rest/realtime/storage
- S3-compatible file storage with MinIO backend
What's included
| Service | Upstream image | Port | Purpose |
|---|---|---|---|
| postgres | supabase/postgres:15.8.1.085 | 5432 | PostgreSQL with pgvector, pgjwt, pg_graphql |
| kong | kong:3.9.1 | 8080 | API gateway — only public-facing service |
| auth | supabase/gotrue:v2.186.0 | 8080 | Auth / user management (GoTrue) |
| rest | postgrest/postgrest:v14.8 | 8080 | Auto-generated REST API from Postgres |
| realtime | supabase/realtime:v2.76.5 | 8080 | WebSocket realtime subscriptions |
| storage | supabase/storage-api:v1.48.26 | 8080 | S3-compatible object storage API |
| minio | minio/minio:RELEASE.2025-09-07T16-13-09Z | 8080 | S3 backend for Storage |
Not included: Studio UI, imgproxy, postgres-meta, edge-runtime, logflare, supavisor, vector.
Dependencies for
Deployment Dependencies
- PostgreSQL volume (
postgres-data) for persistent database storage - MinIO volume (
minio-data) for persistent S3 object storage - Railway private networking for inter-service communication
- Postgres must be healthy before auth/storage/rest start (handled by startCommand wait loops)
Architecture
┌─────────┐ ┌─────┐ ┌─────────────────────────────────┐
│ Client │────▶│ Kong│────▶│ auth / rest / realtime / storage│
└─────────┘ └─────┘ └─────────────────────────────────┘
│
┌─────────────┴─────────────┐
▼ ▼
┌──────────┐ ┌──────────┐
│ postgres │ │ minio │
└──────────┘ └──────────┘
Post-deploy setup
Your public Supabase URL is the Kong service domain:
https://.up.railway.app
Service paths
| Feature | Kong path | Upstream |
|---|---|---|
| Auth | /auth/v1/ | auth:8080 |
| REST | /rest/v1/ | rest:8080 |
| Realtime | /realtime/v1/ | realtime:8080 |
| Storage | /storage/v1/ | storage:8080 |
| Health | /health | Kong request-termination plugin (200 OK) |
Verify the stack
curl -sS "https:///health" -w "\nHTTP %{http_code}\n"
# expected: HTTP 200
Connect with the JS client
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('https://.up.railway.app', '')
Key design decisions
- Postgres roles: Custom entrypoint elevates
postgresto SUPERUSER and createsanon,authenticated,service_roleroles for migrations. - Kong DB-less: Declarative config rendered at runtime from Railway private-domain env vars.
/healthroute returns 200 via request-termination plugin. - Startup ordering: auth and storage use startCommand wait loops (
nc -z) to block until postgres (and minio for storage) are accepting TCP connections. - MinIO binding: Forces
0.0.0.0:8080for Railway healthcheck compatibility. - No SMTP:
GOTRUE_MAILER_AUTOCONFIRM=trueauto-confirms emails. Set SMTP vars for real email.
Troubleshooting
- Services FAILED but logs fine: Set
PORTenv var to match the app's listening port. - "permission denied for schema auth": Check postgres logs —
ALTER ROLE postgres WITH SUPERUSERmust succeed. - Kong 404 on
/health: Don't change healthcheck path; entrypoint defines/healthreturning 200. - Realtime crashes: Set
APP_NAME=realtime.
License
MIT. All upstream images retain their respective licenses.
Template Content