Любому пет-проекту рано или поздно нужен бэкенд: база, аутентификация, файловое хранилище и REST API, чтобы всё это связать.
Supabase Cloud даёт это из коробки, но на Free-плане потолок — два проекта, и любой из них ставится на паузу после недели простоя. А демо, приёмник вебхуков, API, от которого зависит скрипт должны оставаться доступными.
В этом гайде реальная установка self-hosted Supabase на VPS is*hosting тарифа Medium: от голого CentOS 9 x64 до одиннадцати контейнеров в статусе healthy меньше чем за семь минут.
Как работает Supabase
Supabase собирает Postgres вместе с сервисами, которые обычно навешивают на базу вручную.
- Postgres — сама база.
- Kong стоит впереди как API-шлюз.
- PostgREST автоматически превращает схему Postgres в REST API.
- GoTrue отвечает за аутентификацию и сессионные токены.
- Realtime — Elixir-сервер, который транслирует изменения в базе подписанным клиентам.
- Storage управляет загрузкой файлов, права раздаёт сам Postgres.
- imgproxy делает трансформации картинок на лету.
- Supavisor пулит подключения к Postgres, чтобы serverless-фронтенд не исчерпал лимит соединений базы.
- Дополняют стек postgres-meta и Deno-based Edge Runtime.
- Дашборд Studio связывает всё вместе.
Итого одиннадцать контейнеров в дефолтной установке.
Пара вещей по умолчанию выключена.
Logs и Analytics (Logflare плюс коллектор логов Vector) не запускаются, пока их не включить через sh run.sh config add logs — а включение заметно поднимает потребление памяти.
AI Assistant внутри Studio требует OPENAI_API_KEY в .env; из коробки ничего не подключено.
HTTPS тоже не настроен по умолчанию — нужен reverse proxy перед Kong.
Email-флоу для Auth (magic links, сброс пароля, подтверждение регистрации) не отправят ничего, пока в .env не прописан реальный SMTP-релей.
is*hosting по умолчанию блокирует исходящий SMTP на тарифах Lite и Start, но на Medium и выше он открыт. И ещё: self-hosted Supabase поддерживается сообществом — дежурной поддержки, которая примет вызов в 3 часа ночи, здесь нет.
Что понадобится до старта
- Root-доступ по SSH к VPS (есть на всех тарифах is*hosting)
- CentOS 9 x64, выбранный при оформлении — официальный установщик Supabase нативно поддерживает RHEL/CentOS
- Около 10 минут на саму установку
- Публичный IP VPS или домен, направленный на него, если HTTPS понадобится позже
- SMTP-релей, если нужны email-флоу для Auth (на Medium и выше исходящий SMTP открыт по умолчанию)
|
Сценарий |
RAM |
CPU |
is*hosting тариф |
|
Разработка / тестирование (заявленный минимум самого Supabase) |
4 GB |
3 CPU |
Medium — от $21.24/месяц |
|
Продакшн или с включёнными Logs & Analytics |
8 GB |
4 CPU |
Premium — от $31.99/месяц |
Оба тарифа по умолчанию включают выделенный IPv4-адрес и еженедельные бэкапы VPS. Полные спеки на странице VPS-тарифов. Этот гайд использует тариф Medium.
Как установить Supabase на VPS

Шаг 1: проверяем стартовое состояние
CentOS Stream 9 идёт с установленным firewalld, но не обязательно запущенным. Проверяем, прежде чем что-то трогать:
cat /etc/os-release
systemctl status firewalld
На Medium VPS, который использовался для этого гайда, ОС подтвердилась как ожидалось, а firewalld оказался неактивен:
PRETTY_NAME="CentOS Stream 9"
...
○ firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; preset: enabled)
Active: inactive (dead)
Это важно для раздела про файрвол дальше: на этой машине правила firewalld трогать не нужно, и Docker ничего не отключал — оно и так было выключено.
Шаг 2: запускаем quick-start установщик
Supabase поставляет один скрипт, который ставит Docker, тянет конфиг Docker Compose и генерирует все секреты, нужные стеку. Запускаем от root:
curl -fsSL https://supabase.link/setup.sh | sh
Сначала он определяет ОС:
===> Detected OS: centos (rhel)
Затем ставит git, openssl, jq и ca-certificates, добавляет официальный CentOS-репозиторий Docker и ставит оттуда docker-ce, docker-ce-cli, containerd.io, docker-buildx-plugin и docker-compose-plugin.
Добавление репозитория Docker первым шагом на CentOS 9 важно: dnf install docker-ce из дефолтных репозиториев падает с ошибкой «No match for argument», потому что пакета там нет, пока не подключён репозиторий Docker. Скрипт делает этот шаг сам.
Шаг 3: задаём URL'ы
Скрипт спрашивает четыре значения в управляющем терминале. Для VPS без домена подставляем публичный IP сервера в первый запрос и принимаем дефолты для остальных:
SUPABASE_PUBLIC_URL (Studio + APIs) [http://localhost:8000]: http://<your-vps-ip>:8000
API_EXTERNAL_URL (Auth callbacks) [http://<your-vps-ip>:8000]: [Enter]
SITE_URL (default Auth redirect) [http://localhost:3000]: [Enter]
PROXY_DOMAIN (for nginx/caddy HTTPS proxy) [your-domain.example.com]: [Enter]
Скрипт попытается вывести email для Certbot из того, что введено как публичный URL. Если дать ему голый IP вместо домена, он выдаст что-то вроде [email protected], собранное из двух последних октетов.
На работу это не влияет — Certbot вообще не запускается, пока не включён override для HTTPS reverse-proxy, — но при первом появлении в консоли выглядит как ошибка.
Шаг 4: генерация секретов и pull образов
Скрипт автоматически прогоняет utils/generate-keys.sh и utils/add-new-auth-keys.sh, записывая свежие POSTGRES_PASSWORD, JWT_SECRET, DASHBOARD_PASSWORD и остальную пару API-ключей прямо в .env. Ни одно из этих значений не должно попасть в сохранённый лог или тикет в поддержку — скрипт печатает каждое в stdout по мере записи, так что если пишете свою сессию, редиректьте или вычищайте этот шаг.
Дальше он тянет все нужные образы:
===> Pulling Docker images
Image postgrest/postgrest:v14.12 Pulling
Image supabase/realtime:v2.102.3 Pulling
Image kong/kong:3.9.1 Pulling
...
Одиннадцать сервисных образов плюс временный node:22-alpine, нужный только для генерации ключей. Это самая долгая часть установки.
Шаг 5: поднимаем стек
cd supabase-project
sh run.sh start
Это запускает docker compose up -d --wait, стартуя каждый контейнер и блокируясь, пока все не перейдут в статус healthy.
Postgres и Studio поднимаются первыми, потому что от одного или обоих зависит большинство остальных сервисов; Kong конкретно ждёт Studio, а storage и edge-functions заканчивают последними.
На этом Medium VPS весь прогон — от первой строки ===> Setup starting до последнего контейнера в статусе healthy — занял 6 минут 53 секунды:
Setup complete. Project ready at: /root/supabase-project
Next steps:
cd /root/supabase-project
sh run.sh config
sh run.sh secrets
sh run.sh start
Проверяем, что всё поднялось:
docker compose ps
NAME IMAGE STATUS
supabase-db supabase/postgres:17.6.1.136 Up (healthy)
supabase-kong kong/kong:3.9.1 Up (healthy)
supabase-studio supabase/studio:2026.07.07-sha-a6a04f2 Up (healthy)
supabase-auth supabase/gotrue:v2.189.0 Up (healthy)
supabase-rest postgrest/postgrest:v14.12 Up (healthy)
supabase-storage supabase/storage-api:v1.60.4 Up (healthy)
supabase-meta supabase/postgres-meta:v0.96.6 Up (healthy)
supabase-pooler supabase/supavisor:2.9.5 Up (healthy)
supabase-imgproxy darthsim/imgproxy:v3.30.1 Up (healthy)
supabase-edge-functions supabase/edge-runtime:v1.74.0 Up (healthy)
realtime-dev.supabase-realtime supabase/realtime:v2.102.3 Up (healthy)
Все одиннадцать в статусе healthy — ровно те одиннадцать образов, что тянулись на шаге 4.
Файрвол
Все порты, которые открывает этот стек, приходят от Docker, а не от хостового сервиса. Kong публикует 8000 (HTTP) и 8443 (HTTPS, не используется, пока не настроен сертификат) прямо в интернет. Supavisor так же публикует 5432 (Postgres в session-режиме) и 6543 (пулинг в transaction-режиме). Проверили на этой машине через ss -tlnp:
LISTEN 0.0.0.0:5432 docker-proxy
LISTEN 0.0.0.0:8000 docker-proxy
LISTEN 0.0.0.0:8443 docker-proxy
LISTEN 0.0.0.0:6543 docker-proxy
LISTEN 0.0.0.0:22 sshd
iptables-правила Docker делают эти четыре порта доступными независимо от состояния firewalld, поэтому шага с firewall-cmd тут нет — firewalld остался неактивным и до, и после установки, хосту он не нужен.
Одно решение стоит принять самостоятельно: 5432 и 6543 по умолчанию открыты всему интернету, защищены только POSTGRES_PASSWORD. Если прямой внешний доступ к Postgres не нужен, эти два порта лучше ограничить или вовсе убрать маппинг портов у сервиса supavisor в docker-compose.yml.
Как пользоваться Supabase: Studio, Table Editor и API-ключи
Studio доступен за Kong по адресу http://<your-vps-ip>:8000, защищён HTTP Basic Auth через DASHBOARD_USERNAME и DASHBOARD_PASSWORD из .env.
После логина сразу открывается обзор проекта — многошагового онбординг-визарда прокликивать не нужно.

Панель Advisor на этом первом экране запускается автоматически и подсвечивает проблемы безопасности и производительности — неиспользуемые индексы, таблицы без row-level security и подобное, — без всякой настройки.
Table Editor и SQL Editor, оба в левом сайдбаре, закрывают две самые частые задачи первого дня: собрать схему визуально в Table Editor или выполнить сырой SQL в SQL Editor для всего, что не покрывает point-and-click.

API Keys, под панелью Get Connected — там лежат anon-ключ (безопасен для клиентского кода) и service_role-ключ (только серверная сторона, полный доступ к базе). Каждый запрос через Kong к /rest/v1/, /auth/v1/ или /storage/v1/ требует один из этих двух ключей.
Как обновлять Supabase
Supabase выпускает новый стабильный релиз конфига Docker Compose примерно раз в месяц. Чтобы обновить один сервис, паттерн, который документирует сам проект: проверить теги образов на Docker Hub, поправить строку с версией в docker-compose.yml, затем спуллить и пересоздать только этот сервис:
sh run.sh pull
sh run.sh recreate studio
Обновление конфигурации всего стека менее автоматично, потому что quick-start скрипт делает sparse-clone директории docker/ один раз и не держит её под git локально. Повторный запуск setup.sh внутри существующей директории проекта ничего не делает — он находит существующие .env и docker-compose.yml и сразу выходит.
Чтобы подхватить новый релиз, нужно пере-клонировать директорию docker/ из репозитория Supabase в свежую временную папку и сравнить её с текущим docker-compose.yml, не трогая существующий .env.
is*hosting включает бесплатные еженедельные бэкапы VPS на всех тарифах, но полное восстановление VPS — слишком грубый способ откатить один сбойный контейнер. Точечный дамп Postgres восстанавливается быстрее и не трогает ничего больше на машине:
docker exec supabase-db pg_dumpall -U postgres > supabase-backup-$(date +%F).sql
Что в итоге работает
От начала до конца установка заняла 6 минут 53 секунды на VPS Medium (3 CPU, 4 GB RAM, 40 GB SSD, $21.24/мес) — от первой строки вывода setup.sh до всех одиннадцати контейнеров в статусе healthy.
Стек занял примерно на 10 GB диска и 1.9 GB RAM из 3.8 GB доступных по free -h, оставляя около 2 GB запаса до момента, когда есть смысл переходить на Premium.
На этой одной машине работает: полноценная база Postgres 17, автогенерируемый REST API, JWT-аутентификация, файловое хранилище с трансформацией картинок, realtime-подписки и Deno-based edge-функции — всё за единым шлюзом Kong на порту 8000.
Для первого логина и начального харденинга VPS основы, которые этот гайд подразумевает, разобраны в гайде по настройке Linux VPS, а вся линейка тарифов — на странице VPS-тарифов.
VPS
Разверните весь стек Supabase — Postgres, Auth, Storage и edge-функции — на VPS с выделенным IPv4 и бесплатными еженедельными бэкапами.
Supabase vs. Supabase Cloud: когда селф-хостинг оправдан
Free-план Supabase Cloud покрывает два проекта по 500 МБ хранилища базы на каждый, но ставит на паузу любой проект после недели простоя. Именно пауза, а не цена — реальный потолок Free-плана для всего, что должно работать постоянно.
Pro стоит $25 в месяц за организацию, с compute-кредитом $10, который покрывает один Micro-инстанс; каждый следующий проект в той же организации требует своего compute-аддона от ~$10 в месяц. Три always-on пет-проекта на Pro выходят примерно в $45 в месяц.
VPS is*hosting тарифа Medium держит столько self-hosted проектов, сколько влезет на машину, за $21.24 в месяц по фиксированной цене — без паузы и без per-project счётчика compute.
Компромисс в том, что патчить Postgres и следить за диском теперь ваша забота. Еженедельные бэкапы is*hosting покрывают весь VPS, а не point-in-time recovery для одной базы.
Для чувствительных к задержке приложений 40+ локаций is*hosting дают ещё один плюс — базу можно физически поставить рядом с пользователями, чего фиксированный AWS-регион в Supabase Cloud на уровне проекта не предложит.