Как развернуть Supabase на VPS с Docker
Запустите официальный стек Supabase Docker на своем сервере: замените демосекреты, разберитесь в 14 сервисах, оцените RAM, настройте резервные копии и обновления без удаления БД.
Что вы развернете
Самостоятельный хостинг Supabase означает запуск официального стека Docker Compose на собственном сервере: Postgres, REST API перед ним, сервис аутентификации, файловое хранилище, веб-сокеты realtime и панель Studio. Вы клонируете один репозиторий, изменяете один файл .env и запускаете около четырнадцати контейнеров, которые вместе работают как управляемый вами проект Supabase.
Установка занимает немного времени. Проблемы обычно возникают из-за файла .env. В нем по умолчанию указаны демонстрационные секреты, опубликованные в репозитории, поэтому стек, запущенный с этими значениями, доступен всем, кто его обнаружит. В этом руководстве описаны секреты, которые необходимо заменить, назначение каждого сервиса, фактические требования стека к памяти и безопасное обновление без удаления базы данных.
Если вы еще не работали с Compose, сначала прочитайте Основы Docker Compose на VPS. Все дальнейшие инструкции предполагают, что команда docker compose version уже выводит версию.
Что фактически входит в стек
Supabase — это не одна программа. Файл Compose запускает набор отдельных сервисов в одной сети. Если понимать назначение каждого сервиса, вместо списка имен контейнеров вы получаете структуру, которую можно диагностировать.
db— это PostgreSQL с загруженными расширениями Supabase. Все остальные сервисы обращаются к нему. Если этот контейнер работает неправильно, остальные сервисы тоже выходят из строя.kong— это шлюз API. Он принимает соединения на порту 8000 и направляет/rest/v1/,/auth/v1/и/storage/v1/в соответствующие внутренние службы. Это единственный контейнер, который следует делать доступным извне.rest— это PostgREST. Он читает схему Postgres и предоставляет ее через REST API. Поэтому новая таблица автоматически становится новой конечной точкой без написания кода.auth— это GoTrue. Он выдает JSON Web Token (JWT), которые идентифицируют пользователей.storageиimgproxyобрабатывают загрузку файлов и изменение размера изображений.realtimeпередает изменения базы данных через websockets.studioиmeta— это панель управления и расположенный за ней административный API.analytics(Logflare) иvectorсобирают журналы, аsupavisor— это пул соединений PostgreSQL.
Именно поэтому ниже указаны такие значения потребления ресурсов. Вы запускаете не только базу данных. Вы запускаете базу данных и около десятка вспомогательных сервисов.
Размер: запланируйте 8 GB RAM
После чистой установки стек потребляет примерно от 2.5 до 3 GB резидентной памяти по состоянию на July 2026, без ваших данных и сетевого трафика. Сервис аналитики и процесс Studio Node.js — два крупнейших отдельных потребителя ресурсов. Сервер с 2 GB запустит контейнеры, а затем ядро завершит один из них из-за нехватки памяти, обычно analytics или db. Признак проблемы — контейнер зацикленно перезапускается с кодом выхода 137.
Для рабочих задач выделите 8 GB RAM и 4 vCPU. 4 GB достаточно для отдельного экземпляра разработки, если вы готовы к тому, что тяжелый запрос и сеанс Studio одновременно будут выполняться медленно. Важен и объем диска: Postgres, том хранилища и данные журналов находятся в каталоге проекта. Начните с 40 GB и контролируйте использование.
Установка: клонирование официального репозитория
Поддерживаемый способ копирует каталог docker из основного репозитория в отдельный каталог проекта. Это разделение важно, поскольку последующая операция git pull не сможет перезаписать .env.
git clone --depth 1 https://github.com/supabase/supabase
mkdir supabase-project
cp -rf supabase/docker/* supabase-project
cp supabase/docker/.env.example supabase-project/.env
cd supabase-project
docker compose pulldocker compose pull загружает несколько гигабайт образов. По завершении у каждой службы должен быть статус Pulled. Ошибка manifest unknown означает, что указанный тег образа был удалён из исходного репозитория. Чтобы исправить проблему, загрузите более новую копию репозитория, а не изменяйте теги вручную.
Секреты, которые необходимо изменить до первого запуска
Сделайте это до запуска стека, а не после. Некоторые из этих значений записываются в данные при первом запуске, поэтому их последующее изменение потребует сброса базы данных.
В репозитории есть генератор, который правильно создает все значения, включая два API-ключа, которые необходимо подписать новым секретом JWT.
sh utils/generate-keys.sh --update-envЭтот скрипт записывает новые значения для JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY, SECRET_KEY_BASE, REALTIME_DB_ENC_KEY, VAULT_ENC_KEY, PG_META_CRYPTO_KEY и токены Logflare в .env. Для его работы требуется openssl, который присутствует в любом стандартном образе Ubuntu.
Два значения он не устанавливает. Их необходимо изменить вручную в .env:
POSTGRES_PASSWORD. Используйте только буквы и цифры. Знаки пунктуации здесь нарушают строки подключения, которые несколько сервисов создают путем объединения строк. При этом ошибка выглядит как ошибка аутентификации, а не как ошибка разбора. Поэтому поиск причины часто ведется не в том месте.DASHBOARD_USERNAMEиDASHBOARD_PASSWORD. Это учетные данные базовой аутентификации для Studio. Пароль по умолчанию в поставляемой конфигурации буквально равенthis_password_is_insecure_and_should_be_updated.
Важно понимать, почему ANON_KEY и SERVICE_ROLE_KEY нельзя придумывать самостоятельно. Оба значения являются JWT, подписанными с помощью JWT_SECRET. Шлюз проверяет эту подпись при каждом запросе, поэтому ключ, не соответствующий вашему секрету, отклоняется с ошибкой {"message":"Invalid authentication credentials"}. Это самая распространенная ошибка при самостоятельном развертывании: оператор изменяет JWT_SECRET, но сохраняет демонстрационные ключи. Всегда создавайте все три значения одновременно.
С SERVICE_ROLE_KEY следует обращаться как с паролем root. Он полностью обходит защиту на уровне строк. Этот ключ должен использоваться только в серверном коде и нигде больше.
Установите SITE_URL и API_EXTERNAL_URL в адрес, по которому пользователи действительно будут обращаться к сервису, например https://supabase.example.com. Auth формирует ссылки подтверждения адреса электронной почты и обратного вызова OAuth на основе этих значений. Если оставить http://localhost:8000, все пользователи будут перенаправляться на собственные компьютеры.
Затем проверьте получившиеся значения:
sh run.sh secretsЗапустите его и убедитесь, что он работает исправно
sh run.sh start
docker compose psrun.sh start запускает docker compose up -d --wait и не возвращает управление, пока проверки работоспособности не завершатся успешно. Для каждого сервиса должно отображаться running (healthy) или running. Первый запуск занимает от двух до четырех минут, поскольку Postgres выполняет сценарии инициализации, прежде чем к нему сможет подключиться любой другой компонент.
Если контейнер перезапускается, просмотрите его журналы, указав имя сервиса:
docker compose logs db
docker compose logs authStudio будет доступен на порту 8000 и запросит заданные вами имя пользователя и пароль для панели управления.
Не размещайте порт 8000 в общедоступном интернете
Kong на порту 8000 использует обычный HTTP. Все API-ключи и пароли пользователей передаются по сети в открытом виде. Учетные данные Studio используют базовую аутентификацию, которая является кодированием base64, а не шифрованием.
Разместите перед ним обратный прокси и завершайте TLS (безопасность транспортного уровня) на этом прокси. Привяжите Kong к адресу loopback, чтобы никакие другие узлы не могли получить к нему доступ. В docker-compose.yml сопоставление порта kong становится 127.0.0.1:8000:8000, а прокси перенаправляет запросы на этот порт. В разделе Traefik перед несколькими приложениями Compose описана настройка сертификатов.
Также закройте остальные порты в брандмауэре, поскольку Docker публикует порты, добавляя собственные правила iptables, которые стандартная конфигурация ufw не учитывает. Эта проблема объясняется в разделе почему контейнеры Docker игнорируют правила ufw.
Резервируйте базу данных, а не каталог
Данные Postgres находятся в bind mount по пути ./volumes/db/data. Копирование этого каталога во время работы контейнера создаёт неполную копию, поскольку Postgres буферизует записи, а файлы на диске согласованы только в момент контрольной точки. Восстановление обычно сработает, но иногда последние транзакции будут незаметно потеряны. Для резервной копии это худший возможный сценарий отказа.
Вместо этого создайте дамп. pg_dumpall выполняется внутри контейнера и создаёт согласованный снимок:
docker exec -t supabase-db pg_dumpall -U postgres > supabase-$(date +%F).sqlПеред использованием убедитесь, что файл не пуст. Затем регулярно отправляйте эти дампы за пределы сервера. Для этого предназначено шифрованное резервное копирование на удалённый сервер с помощью restic. Одновременно создавайте резервную копию .env. При потере JWT_SECRET все выданные токены станут недействительными, а все сохранённые зашифрованные секреты будет невозможно расшифровать.
Загруженные файлы находятся в ./volumes/storage. Это обычные файлы, поэтому достаточно простого копирования.
Обновление без потери данных
Supabase фиксирует версии образов в docker-compose.yml, поэтому ничего не изменится, пока вы сами не выполните обновление. Перед каждым обновлением создавайте дамп.
docker compose pull
sh run.sh recreaterecreate останавливает стек и запускает его снова с новыми образами. Данные сохраняются, потому что находятся в bind mount на хосте, а не внутри контейнеров. Перед переходом на новую основную версию прочитайте CHANGELOG.md в репозитории: основные обновления Postgres не выполняются автоматически и требуют создания дампа и восстановления.
Чтобы применить изменения самого Compose-файла, снова клонируйте исходный репозиторий и скопируйте его каталог docker в свой проект. Не перезаписывайте .env.
Полный сброс, который удаляет все данные, включая базу данных, выполняется отдельным скриптом. Скрипт запрашивает подтверждение:
sh reset.shFAQ
Почему мои API-вызовы возвращают сообщение «Invalid authentication credentials»?
Ваши ANON_KEY или SERVICE_ROLE_KEY не были подписаны с помощью JWT_SECRET, который сейчас находится в .env. Шлюз проверяет подпись каждого запроса и отклоняет запрос при несовпадении. Повторно создайте все три значения с помощью sh utils/generate-keys.sh --update-env, затем выполните sh run.sh recreate, чтобы сервисы прочитали новые значения.
Можно ли запустить Supabase на собственном сервере с 2 GB RAM?
Надежно — нет. По состоянию на July 2026 стек потребляет около 3 GB в режиме простоя, поскольку запускает около fourteen сервисов. Поэтому на сервере с 2 GB RAM контейнеры завершаются из-за нехватки памяти, а в docker compose ps появляется код завершения 137. Для production используйте 8 GB RAM. Для индивидуальной разработки минимально допустимый объем составляет 4 GB RAM.
Включает ли Supabase на собственном сервере edge functions?
Да. Compose-файл включает runtime для функций на основе Deno. Он обслуживает все, что размещено в ./volumes/functions. В него не входит глобальная сеть развертывания hosted-платформы. Поэтому функции работают на одном вашем сервере и в одном расположении.
Как напрямую подключиться к базе данных Postgres?
Для интерактивной оболочки непосредственно на сервере используйте docker exec -it supabase-db psql -U postgres. Для внешнего клиента подключитесь через Supavisor на порту 5432, используя пользователя postgres.<POOLER_TENANT_ID> и ваш POSTGRES_PASSWORD. Не открывайте этот порт в интернете. Подключайтесь к нему через VPN или SSH-туннель.
Почему ссылки в моих письмах для подтверждения auth указывают на localhost?
В .env остались значения по умолчанию для SITE_URL и API_EXTERNAL_URL. Сервис auth создает все ссылки для подтверждения и сброса пароля на основе этих двух значений. Поэтому он отправляет адрес, который ему задан. Укажите для обоих параметров ваш реальный публичный URL и пересоздайте стек.