Supabase на своём сервере — это девять контейнеров, а не одна кнопка
Маркетинг Supabase продаёт self-hosted версию как «тот же облачный Supabase, только на вашем сервере — разверните одной командой docker compose up». Формально это правда: команда действительно одна. Но за ней поднимается девять (а в актуальных версиях иногда и больше) контейнеров, каждый со своим циклом обновлений, своими требованиями к памяти и своей точкой отказа. Если вы уходили от Firebase к Supabase именно ради независимости от чужой инфраструктуры — приготовьтесь к тому, что эту инфраструктуру теперь обслуживаете вы сами, и это не одна база данных, а маленький дистрибьютед-систем.
Содержание
- Из чего реально состоит self-hosted Supabase
- Ресурсы: что реально нужно каждому контейнеру
- Обновления: почему это не «git pull и рестарт»
- Сеть и безопасность: Kong — это не деталь, это критический узел
- Хранение секретов: здесь их не один, а десяток
- Что стоит вынести за пределы стандартного docker-compose
- Когда self-hosted Supabase оправдан, а когда — нет
Из чего реально состоит self-hosted Supabase
Официальный docker-compose.yml для self-hosted разворачивания — это не PostgreSQL с REST-обёрткой поверх. Это набор независимых сервисов, которые вместе эмулируют облачную платформу:
- PostgreSQL — сама база данных, ядро всего стека, с набором дополнительных расширений (pgjwt, pgsodium, pg_graphql и другие), которые Supabase подключает поверх ванильного Postgres.
- GoTrue (Auth) — сервис авторизации: регистрация, вход, OAuth-провайдеры, магические ссылки, JWT-токены. Отдельный Go-бинарник со своей схемой в базе (
auth). - PostgREST — генерирует REST API прямо из схемы вашей базы данных. Это то, что даёт Supabase знаменитый «автоматический API» — но это отдельный процесс, который нужно перезапускать при изменении схемы (или настраивать
NOTIFY pgrst, 'reload schema'). - Realtime — сервис на Elixir, который слушает изменения в базе через логическую репликацию (
wal2jsonили pgoutput) и рассылает их подписчикам по WebSocket. Один из самых прожорливых по памяти компонентов при активном использовании. - Storage API — файловое хранилище с S3-совместимым бэкендом (либо локальная файловая система, либо внешний S3/MinIO). Хранит метаданные в той же Postgres.
- Kong — API-шлюз, через который проходят все внешние запросы к перечисленным сервисам. Именно Kong решает, какой путь (
/rest/v1,/auth/v1,/realtime/v1,/storage/v1) на какой контейнер маршрутизировать. - postgres-meta — сервис для программного управления схемой базы (это то, чем пользуется веб-интерфейс Studio, когда вы создаёте таблицу мышкой).
- Studio — веб-панель администрирования. В облаке она недоступна снаружи вашего проекта, в self-hosted версии это ещё один контейнер, который нужно защищать отдельно.
- imgproxy (опционально) — трансформация изображений на лету для Storage API.
- Vector / Analytics (Logflare) — сбор логов со всех контейнеров в единую точку, если вы включаете этот компонент.
Итого при полном разворачивании — от 9 до 12+ контейнеров в зависимости от версии docker-compose и того, что вы включили. Каждый — это отдельный процесс с собственным потреблением CPU/RAM, отдельными логами, отдельной версией, которая должна быть совместима с версиями соседних сервисов.
Ресурсы: что реально нужно каждому контейнеру
Официальная документация обычно не даёт точных цифр по потреблению ресурсов — они сильно зависят от нагрузки. Но по опыту эксплуатации на небольших и средних проектах можно ориентироваться так (это именно ориентир, а не гарантированные числа — на вашей нагрузке будет иначе):
| Компонент | Базовое потребление RAM в простое | Что раздувает его под нагрузкой |
|---|---|---|
| PostgreSQL | зависит от shared_buffers и числа подключений | активные запросы, число открытых соединений, размер рабочих таблиц |
| Realtime | заметно даже без подписчиков (Erlang VM) | число одновременных WebSocket-подключений и частота изменений в реплицируемых таблицах |
| GoTrue | небольшое | пиковая нагрузка на логин/регистрацию |
| PostgREST | небольшое, но растёт с кэшем схемы | размер и сложность схемы базы |
| Kong | умеренное, Lua-плагины добавляют накладные расходы | число активных плагинов (rate limiting, CORS, JWT-валидация) |
| Storage API | небольшое само по себе | обработка больших файлов, если не проксируется напрямую в S3 |
| Studio | заметное для админ-панели | практически не масштабируется нагрузкой пользователей, но ест ресурсы постоянно |
Ключевой практический вывод: на VPS с 2 ГБ RAM полный self-hosted стек Supabase будет работать на грани, особенно если Realtime и Studio включены постоянно. Реалистичный минимум для стабильной работы без постоянных OOM-килов — 4 ГБ RAM, и это без учёта самой нагрузки приложения. Если проект растёт, Postgres и Realtime почти всегда упираются в память первыми.
Если вы уже разбирались с тем, сколько соединений держит PostgreSQL до деградации, это знание пригодится напрямую: GoTrue, PostgREST и Realtime — это три независимых пула соединений к одной базе, и по умолчанию они не координируются между собой. При росте нагрузки легко упереться в max_connections раньше, чем ожидаете, просто потому что три сервиса держат свои собственные пулы одновременно.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPSОбновления: почему это не «git pull и рестарт»
В облачном Supabase обновления происходят прозрачно — команда Supabase тестирует совместимость версий GoTrue, PostgREST, Realtime, Kong и Postgres между собой и выкатывает согласованный набор. В self-hosted версии эта работа частично ложится на вас.
Формально официальный репозиторий supabase/supabase даёт готовый docker-compose.yml с зафиксированными версиями образов — и если просто обновлять весь стек целиком через официальный пример, совместимость обычно сохраняется. Проблемы начинаются, когда:
- вы обновляете один контейнер отдельно (например, только Postgres — для патча безопасности), не трогая остальные;
- вы кастомизировали конфигурацию Kong или добавили свои плагины, а новая версия Kong меняет формат конфига;
- у вас есть собственные расширения PostgreSQL, установленные вручную, а новый образ Postgres от Supabase их не включает;
- миграция схемы
authилиstorageв новой версии GoTrue/Storage API требует ручного вмешательства, если база большая и не отвечает вовремя на автоматическую миграцию при старте контейнера.
Практическая рекомендация: обновляйте весь docker-compose.yml целиком, синхронизируясь с официальным репозиторием, а не отдельные образы по своему усмотрению. И обязательно делайте бэкап базы перед обновлением — миграции схемы auth/storage/realtime выполняются автоматически при старте новых версий контейнеров, откатить их вручную сложнее, чем откатить сам образ.
Сеть и безопасность: Kong — это не деталь, это критический узел
В отличие от типичного self-hosted сервиса, где Nginx или Traefik — это просто reverse-proxy перед одним приложением, здесь Kong выполняет содержательную работу: JWT-валидацию, маршрутизацию по путям API, CORS-политики, rate limiting. Если Kong настроен неправильно или упал — недоступны сразу все сервисы Supabase, даже если сама база данных жива.
Частые грабли:
ANON_KEYиSERVICE_ROLE_KEYпутают роли.anon keyпредназначен для публичного использования на клиенте (защищён Row Level Security на стороне Postgres),service_role keyобходит RLS полностью. Утечкаservice_roleв клиентский код — это полный доступ к базе в обход всех политик безопасности.- RLS выключен «на время разработки» и забыт. Supabase по умолчанию создаёт таблицы без Row Level Security, если вы не включили его явно. В self-hosted версии не забывайте, что если вы даёте кому-то
anon key, а RLS не настроен — это открытая база данных. - Studio доступна из интернета без дополнительной защиты. В облаке Studio живёт за аутентификацией Supabase. Self-hosted Studio по умолчанию — это просто веб-приложение на своём порту; если вы прокидываете его наружу через Kong без basic-auth или VPN, любой, кто найдёт адрес, получит доступ к админ-панели.
Если раньше вы разворачивали сервисы через простой docker-compose.yml с одним приложением и одной базой, стоит заранее прочитать про типичные ошибки docker-compose в продакшене — в стеке из десятка контейнеров эти ошибки не складываются, а перемножаются: одна неверная переменная окружения ломает цепочку из трёх сервисов сразу.
Хранение секретов: здесь их не один, а десяток
В обычном self-hosted проекте обычно один-два секрета — пароль от базы и, возможно, API-ключ. В Supabase-стеке секретов на порядок больше, и все они связаны между собой:
POSTGRES_PASSWORD— пароль суперпользователя Postgres;JWT_SECRET— общий секрет, которым GoTrue подписывает токены, а PostgREST и Realtime их проверяют. Смена этого секрета разлогинивает всех пользователей мгновенно;ANON_KEYиSERVICE_ROLE_KEY— производные отJWT_SECRETJWT-токены с фиксированными ролями;SECRET_KEY_BASE— используется Realtime;DASHBOARD_USERNAME/DASHBOARD_PASSWORD— базовая защита Studio через Kong;- ключи для внешних OAuth-провайдеров (Google, GitHub и так далее), если вы их подключаете через GoTrue;
- SMTP-креды, если GoTrue отправляет письма подтверждения сами.
Если JWT_SECRET меняется, а ANON_KEY/SERVICE_ROLE_KEY не пересчитаны заново (они генерируются на основе секрета через jwt.io или скрипт) — приложение получит валидные с виду, но нерабочие токены, и разобраться в причине не так просто, потому что ошибка выглядит как проблема авторизации, а не как рассинхрон конфигурации. Если у вас уже есть привычка держать пароли в environment: секции docker-compose «для удобства» — в проекте с десятком связанных секретов это прямая дорога к утечке: один случайно закоммиченный .env — это не один скомпрометированный пароль, а весь стек авторизации целиком.
Что стоит вынести за пределы стандартного docker-compose
Не всё из коробки одинаково хорошо подходит для продакшена без доработки:
- Storage — на внешний S3-совместимый бэкенд. По умолчанию Storage API может писать файлы на локальный диск контейнера. Это работает для теста, но плохо переживает пересоздание контейнера и не масштабируется на несколько нод. Разумнее сразу подключить внешний S3 или поднять рядом собственный MinIO в docker-compose и указать его как бэкенд в переменных Storage API.
- PostgreSQL — вынести на выделенный volume с мониторингом места. Логическая репликация для Realtime означает рост WAL при активных подписках; если вы уже сталкивались с ситуацией, когда растёт размер WAL без явной причины, в Supabase-стеке это частый сценарий — Realtime не успевает вычитывать слот репликации, и WAL копится, пока не кончится место на диске.
- Kong — зафиксировать конфигурацию отдельно от контейнера. Официальный образ подтягивает
kong.ymlпри старте; если вы правите маршруты вручную внутри контейнера, изменения теряются при пересоздании. Держите конфиг в git рядом сdocker-compose.yml. - Логи — агрегировать сразу. Десяток контейнеров пишут логи независимо; без централизованного сбора (тот самый Vector/Logflare, либо любой альтернативный стек) разбор инцидента превращается в чтение логов из десяти разных
docker logsподряд.
Когда self-hosted Supabase оправдан, а когда — нет
Self-hosted имеет смысл, если у вас уже есть опыт эксплуатации многоконтейнерных стеков и одна из следующих причин:
- требования по хранению данных не позволяют использовать облако (юрисдикция, комплаенс);
- нагрузка достаточно большая, чтобы платный тариф в облаке обходился дороже, чем аренда сервера и время на администрирование;
- нужна кастомизация, недоступная в облачной версии — свои расширения Postgres, нестандартная сетевая топология, интеграция с внутренней инфраструктурой.
Если же цель — просто «не зависеть от Firebase, но не хочется администрировать инфраструктуру» — честнее признать, что self-hosted Supabase меняет одну зависимость (от Google) на другую (от вашей способности поддерживать девять взаимосвязанных сервисов). Managed Supabase Cloud в этом смысле — компромисс, который многие недооценивают до первого инцидента с рассинхроном версий контейнеров.
Для тех, кто всё же выбирает self-hosted: закладывайте отдельный сервер или как минимум отдельный VPS с запасом по памяти именно под этот стек, не подселяйте его к другим продакшен-сервисам «для экономии» — при девяти контейнерах с разным профилем нагрузки соседство с чужими процессами усложняет диагностику проблем с ресурсами.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать VPSНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли запустить self-hosted Supabase без Realtime и Studio, чтобы сэкономить ресурсы?
Да, docker-compose.yml можно редактировать и убирать ненужные сервисы (например, Realtime, если вы не используете подписки на изменения в реальном времени, или Studio, если администрируете базу напрямую через psql). Учтите, что часть клиентских SDK Supabase ожидает наличия эндпоинтов Realtime даже если вы их не используете активно — тестируйте после отключения.
Обязательно ли использовать Kong, или можно поставить свой reverse-proxy?
Технически можно заменить Kong на Nginx или Traefik с собственной настройкой маршрутизации, но тогда вы теряете встроенную JWT-валидацию и плагины, и их придётся реализовывать самостоятельно на уровне прокси или в самих сервисах. Большинство self-hosted инсталляций оставляют Kong как есть.
Что будет, если PostgreSQL упадёт, а остальные контейнеры останутся работать?
GoTrue, PostgREST, Realtime и Storage API держат соединения с базой и при её недоступности начинают возвращать ошибки 500/503 по своим эндпоинтам. Контейнеры не падают сами, но фактически всё API становится неработоспособным, пока Postgres не поднимется — это ожидаемое поведение, а не баг конфигурации.
Нужен ли отдельный сервер под Supabase, или можно на том же VPS, где крутится основное приложение?
Формально можно, но с оговоркой: девять контейнеров сами по себе создают заметную базовую нагрузку на CPU и RAM ещё до трафика пользователей. На небольшом VPS (1-2 ГБ RAM) совмещение с другими сервисами почти гарантированно приведёт к OOM-килам в момент пиковой нагрузки на любой из компонентов.
Правда ли, что self-hosted Supabase дешевле облачного в пересчёте на ресурсы?
Это зависит от масштаба и от того, считаете ли вы своё время администрирования. Сама аренда сервера обычно дешевле подписки на сопоставимый облачный тариф, но экономия исчезает, если на сопровождение стека уходят часы каждый месяц — обновления, мониторинг, разбор инцидентов с рассинхроном версий.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →