Как развернуть Supabase на своем VPS через Docker
Пошаговое руководство по установке Supabase на личный сервер. Вы узнаете, как настроить файл .env, заменить стандартные секреты, распределить 4 ГБ ОЗУ и обновлять стек.
Что вы создаете
Self-hosting Supabase означает запуск официального стека Docker Compose на вашем собственном сервере: Postgres, REST API поверх него, сервис аутентификации, хранилище файлов, realtime websockets и панель управления Studio. Вы клонируете один репозиторий, редактируете один файл .env и запускаете одиннадцать контейнеров, которые вместе работают как проект Supabase под вашим контролем.
Установка занимает немного времени. Часть, в которой часто возникают ошибки, — это файл .env. Он поставляется с демонстрационными секретами, которые опубликованы в репозитории, и стек, запущенный с такими настройками по умолчанию, открыт для любого, кто его обнаружит. В этом руководстве рассматриваются секреты, которые необходимо заменить, назначение каждого сервиса, реальные требования стека к оперативной памяти и способы обновления без удаления базы данных.
Если вы не знакомы с Compose, сначала прочитайте Основы Docker Compose на VPS. Все, что описано ниже, предполагает, что команда docker compose version уже выводит версию программы.
Из чего на самом деле состоит стек
Supabase — это не одна программа. Файл Compose запускает набор отдельных сервисов в одной сети. Понимание назначения каждого из них превращает список имен контейнеров в систему, которую можно отлаживать.
db— это PostgreSQL с загруженными расширениями Supabase. С ним взаимодействуют все остальные сервисы. Если этот контейнер неисправен, всё остальное также перестает работать.api-gw— это API gateway. Начиная с релиза августа 2026 года, он использует Envoy; до этого использовался сервис под названиемkong, а Kong по-прежнему доступен как опциональная замена. Он слушает порт 8000 и направляет запросы/rest/v1/,/auth/v1/и/storage/v1/к нужному бэкенду. Это единственный контейнер, который следует открывать во внешнюю сеть.rest— это PostgREST. Он считывает схему Postgres и предоставляет её в виде REST API, поэтому новая таблица автоматически становится новой точкой доступа без написания кода.auth— это GoTrue. Он выдает JSON web tokens (JWT), которые идентифицируют ваших пользователей.storageиimgproxyотвечают за загрузку файлов и изменение размера изображений.realtimeтранслирует изменения базы данных через websockets.studioиmeta— это панель управления и стоящий за ней admin API.functions— это edge runtime на базе Deno, аsupavisor— это пул соединений Postgres.
Логи и аналитика (Logflare плюс vector) были исключены из стандартного файла Compose в июне 2026 года. Теперь это опциональный файл конфигурации, который подключается через sh run.sh config add logs, используя тот же метод наслоения файлов Compose, что описан в запуск одного стека из нескольких файлов Compose.
Этот список объясняет, почему требования к ресурсам ниже именно такие. Вы запускаете не просто базу данных. Вы запускаете базу данных вместе с десятью вспомогательными сервисами.
Планирование ресурсов: выделите 8 ГБ ОЗУ
По состоянию на июль 2026 года, на чистой установке стек потреблял примерно от 2.5 до 3 ГБ резидентной памяти до начала обработки ваших данных или трафика. В этом замере крупнейшими потребителями ресурсов были сервис аналитики и процесс Studio Node.js. Аналитика больше не входит в стек по умолчанию, поэтому она расходует память только при включении переопределения логов. На сервере с 2 ГБ ОЗУ контейнеры запустятся, но один из них будет завершен механизмом kernel out of memory killer; симптомом этого станет контейнер, который постоянно перезапускается с кодом выхода 137. В официальной документации Supabase по self-hosting, проверенной в октябре 2026 года, указаны минимальные требования: 4 ГБ ОЗУ, 2 ядра CPU и 40 ГБ SSD, а рекомендуемые — 8 ГБ, 4 ядра и 80 ГБ.
Для любого критически важного проекта выделяйте 8 ГБ ОЗУ и 4 vCPU. 4 ГБ достаточно для одиночного экземпляра разработки, если вы готовы к тому, что выполнение тяжелого запроса одновременно с сессией Studio будет медленным. Дисковое пространство также важно, так как Postgres, том хранилища и данные логов (если они включены) размещаются в директории проекта. Начните с 40 ГБ и следите за использованием. Подсчет ресурсов для сервисов перед выбором тарифного плана — полезная привычка для любого self-hosted решения, так как PhotoPrism и Immich также имеют строгие требования к ОЗУ: страница быстрого старта Immich, проверенная в октябре 2026 года, требует минимум 6 ГБ ОЗУ и 2 ядра CPU. Если это избыточные мощности для вашего текущего проекта, сравните их с тем, что на самом деле включает бесплатный облачный план Supabase, так как небольшое приложение, которое занимает менее 500 МБ и не простаивает неделями, может работать там бесплатно.
Установка: клонирование официального репозитория
Поддерживаемый метод предполагает копирование директории 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 pullКоманда docker 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, ключей протокола S3 и MINIO_ROOT_PASSWORD в файл .env. По состоянию на октябрь 2026 года он также записывает случайные значения для POSTGRES_PASSWORD и DASHBOARD_PASSWORD. Для работы скрипта требуется openssl, который присутствует в любом стандартном образе Ubuntu. Поскольку теперь он также перезаписывает пароль базы данных, запускайте его с --update-env только до первого старта и никогда не применяйте к стеку, в котором уже есть данные.
Два значения всё же стоит проверить вручную в .env:
POSTGRES_PASSWORD. Скрипт заполняет его случайными шестнадцатеричными символами, что безопасно. Если вы заменяете его своим значением, используйте только буквы и цифры. Знаки препинания здесь нарушают строки подключения, которые некоторые сервисы формируют путем объединения строк. Ошибка выглядит как проблема аутентификации, а не как ошибка парсинга, что заставляет администраторов искать причину не в том месте.DASHBOARD_USERNAMEиDASHBOARD_PASSWORD. Это учетные данные для базовой аутентификации в Studio. Скрипт устанавливает случайный пароль, но оставляет имя пользователя по умолчаниюsupabase. Пароль по умолчанию буквально равенthis_password_is_insecure_and_should_be_updated, поэтому, если вы пропустили выполнение скрипта, измените его сейчас.
Поймите, почему ANON_KEY и SERVICE_ROLE_KEY нельзя придумать самостоятельно. Оба являются JWT-токенами, подписанными с помощью JWT_SECRET. Шлюз принимает только те ключи, которые указаны в .env, а сервисы за ним проверяют подпись по JWT_SECRET, поэтому ключ, который не совпадает, отклоняется с ошибкой HTTP 401. Стандартный шлюз Envoy отвечает 401 Unauthorized, так же как и текущий переопределенный Kong, который использует Kong 3.9 и возвращает {"message":"Unauthorized"}. В инсталляциях до марта 2026 года использовался Kong 2.8, который отвечает {"message":"Invalid authentication credentials"}. Это самая распространенная ошибка при самостоятельном хостинге: оператор изменил JWT_SECRET, но оставил демонстрационные ключи. Всегда генерируйте все три значения вместе.
Относитесь к SERVICE_ROLE_KEY как к паролю root. Он полностью обходит защиту на уровне строк (row level security). Он должен использоваться только в серверном коде и нигде больше.
Установите SITE_URL в адрес вашего приложения, а API_EXTERNAL_URL — в публичный адрес API с /auth/v1 в конце, например https://supabase.example.com/auth/v1. Установите SUPABASE_PUBLIC_URL в тот же публичный адрес без пути. Сервис Auth формирует ссылки для подтверждения email и OAuth-коллбэков на основе этих значений, поэтому, если оставить их со значениями по умолчанию localhost, каждый ваш пользователь будет перенаправлен на свой собственный компьютер.
Затем проверьте полученный результат:
sh run.sh secretsЗапуск и проверка работоспособности
sh run.sh start
docker compose psrun.sh start является оберткой для docker compose up -d --wait, поэтому команда не завершится, пока не будут пройдены проверки работоспособности. Каждый сервис должен находиться в состоянии running (healthy) или running. Первый запуск занимает от 2 до 4 минут, так как Postgres выполняет скрипты инициализации до того, как другие компоненты смогут подключиться.
Если контейнер постоянно перезапускается, изучите его логи, указав имя сервиса:
docker compose logs db
docker compose logs authПосле этого Studio будет доступна на порту 8000; система запросит имя пользователя и пароль для панели управления, которые вы задали ранее.
Не выставляйте порт 8000 в публичную сеть
Шлюз на порту 8000 использует обычный HTTP. Все API-ключи и пароли пользователей передаются по сети в открытом виде, а учетные данные Studio используют базовую аутентификацию (basic authentication), которая представляет собой кодирование base64, а не шифрование.
Установите перед ним reverse proxy, настройте там TLS (transport layer security) и привяжите шлюз к адресу loopback, чтобы никто другой не мог получить к нему доступ. В docker-compose.yml строка с портом в разделе сервиса api-gw меняется на 127.0.0.1:${API_GW_HTTP_PORT:-${KONG_HTTP_PORT:-8000}}:8000/tcp, и прокси перенаправляет трафик на этот адрес. При установке, выполненной до перехода на Envoy в августе 2026 года, та же строка порта находится в разделе сервиса kong. В Traefik перед несколькими Compose-приложениями описана настройка сертификатов. Этот же прокси в итоге обслуживает всё остальное на сервере: от данного стека до таких проектов, как библиотека Jellyfin, стилизованная под видеопрокат 90-х, и для каждого из них требуется имя хоста, а не еще один открытый порт. Если панель управления нужна только вам, откажитесь от прокси и подключайтесь к порту loopback через SSH-туннель — это тот же подход, который self-hosted open-kritt использует для полной изоляции интерфейса сканирования от публичного интернета.
Закройте остальные порты на межсетевом экране, так как Docker публикует порты, записывая собственные правила iptables, которые стандартная конфигурация ufw не видит. Эта ловушка описана в почему Docker-контейнеры игнорируют правила ufw.
Создавайте резервную копию базы данных, а не директории
Данные Postgres хранятся в bind mount по пути ./volumes/db/data. Копирование этой директории во время работы контейнера приводит к созданию несогласованной копии, так как Postgres буферизирует операции записи, а файлы на диске становятся консистентными только в момент контрольной точки (checkpoint). Восстановление из такой копии обычно проходит успешно, но иногда приводит к незаметной потере последних транзакций, что является худшим сценарием отказа для резервной копии.
Вместо этого используйте дамп. Команда pg_dumpall выполняется внутри контейнера и создает консистентный снимок:
docker exec -t supabase-db pg_dumpall -U postgres > supabase-$(date +%F).sqlПеред тем как доверять файлу, убедитесь, что он не пуст. Затем настройте регулярную отправку этих дампов с сервера, для чего предназначены зашифрованные удаленные резервные копии с помощью restic. Регулярный дамп, который завершается с ошибкой без уведомления, ничем не отличается от отсутствия резервной копии, поэтому настройте cron или systemd-задание так, чтобы оно отправляло уведомление на ваш телефон при ненулевом коде выхода. Одновременно с этим создавайте резервную копию .env. Потеря JWT_SECRET означает, что все выданные токены станут недействительными, а все сохраненные зашифрованные секреты — нечитаемыми.
Загруженные файлы находятся в ./volumes/storage; поскольку это обычные файлы, их можно копировать стандартными средствами.
Обновление без потери данных
Supabase фиксирует версии образов в docker-compose.yml, поэтому ничего не меняется, пока вы сами не инициируете обновление. Фиксацию версий стоит применять в любом стеке, который вы собираете вручную. Именно поэтому самостоятельно развернутый ретранслятор RustDesk фиксирует версии своих двух серверных образов, а не использует «плавающие» теги: обновление должно быть осознанным решением, принятым в удобное для вас время. Всегда делайте дамп данных перед началом.
docker compose pull
sh run.sh recreaterecreate останавливает стек и запускает его снова на новых образах. Ваши данные сохраняются, так как они находятся в bind mounts на хосте, а не внутри контейнеров. Перед переходом на мажорную версию прочитайте CHANGELOG.md в репозитории, так как мажорное обновление Postgres — это отдельный этап, который recreate не выполняет. Postgres 17 является версией по умолчанию с июня 2026 года. Существующая установка на базе Postgres 15 переносится на неё с помощью sudo bash utils/upgrade-pg17.sh, который использует pg_upgrade для миграции данных на месте и запрашивает подтверждение на каждом основном этапе. Для этого процесса необходимо, чтобы все контейнеры были запущены, а на диске было свободное место в объеме не менее двух размеров вашей базы данных плюс 5 GB. Supabase по-прежнему рекомендует сделать собственную независимую резервную копию перед началом работы.
Чтобы применить изменения в самом файле Compose, выполните sh update.sh из директории проекта или sh update.sh --dry-run, чтобы сначала увидеть, что именно изменится. Эта команда объединяет апстрим-файлы с вашими правками, никогда не перезаписывает существующие значения в .env (она только добавляет новые ключи) и архивирует вашу конфигурацию в backups/ перед записью, но не саму базу данных. Для установки без файла .supabase-version требуются --from и релиз, с которого она была начата. Это особенно важно для релиза августа 2026 года, в котором сервис kong был заменен на api-gw, что требует обновления docker-compose.yml. Ручной способ также работает: снова клонируйте апстрим-репозиторий и скопируйте его директорию docker поверх вашего проекта, стараясь не перезаписать .env.
Полный сброс, который уничтожает всё, включая базу данных, и возвращает .env к значениям по умолчанию (старый файл сохраняется как .env.old), выполняется отдельным скриптом и требует подтверждения:
sh reset.shFAQ
Почему мои API-запросы возвращают "Invalid authentication credentials"?
Это сообщение выдает Kong 2.8 — шлюз, который использовался в стеке при установке до марта 2026 года. Стандартный шлюз Envoy и текущая версия Kong 3.9 сообщают об этой же проблеме как об обычной ошибке 401 Unauthorized. В любом случае, переданный вами ключ не совпадает с ANON_KEY или SERVICE_ROLE_KEY в .env, либо эти ключи не были подписаны с помощью JWT_SECRET, находящегося в .env. Если в стеке еще нет данных, пересоздайте все три значения одновременно с помощью sh utils/generate-keys.sh --update-env. Если стек уже работает, запустите скрипт без флага и ответьте «нет» (no), чтобы он только вывел новые значения. Затем вручную скопируйте JWT_SECRET, ANON_KEY и SERVICE_ROLE_KEY в .env, а POSTGRES_PASSWORD оставьте без изменений. После этого выполните sh run.sh recreate, чтобы сервисы считали новые значения.
Можно ли запустить self-hosted Supabase на VPS с 2 ГБ ОЗУ?
Ненадежно. В официальной документации Supabase по self-hosting на октябрь 2026 года указано 4 ГБ ОЗУ как минимальное требование. По состоянию на июль 2026 года стек в режиме простоя потреблял около 3 ГБ (включая сервисы логирования, которые сейчас являются опциональными). На сервере с 2 ГБ контейнеры будут завершаться из-за нехватки памяти (OOM killer), и вы увидите код выхода 137 в docker compose ps. Для продакшена используйте 8 ГБ, а 4 ГБ считайте нижним пределом для индивидуальной разработки.
Включает ли self-hosted Supabase edge functions?
Да. Файл Compose включает среду выполнения функций на базе Deno, которая обслуживает всё, что вы разместите в ./volumes/functions. В него не входит глобальная сеть развертывания, доступная в облачной платформе, поэтому ваши функции будут выполняться только на вашем сервере в одной локации.
Как подключиться к базе данных Postgres напрямую?
Используйте docker exec -it supabase-db psql -U postgres для доступа к интерактивной оболочке на самом сервере. Для внешнего клиента подключайтесь через Supavisor по порту 5432 с пользователем postgres.<POOLER_TENANT_ID> и вашим POSTGRES_PASSWORD. Не открывайте этот порт в Интернет. Доступ к нему должен осуществляться через VPN или SSH-туннель.
Почему ссылки в письмах с подтверждением авторизации ведут на localhost?
SITE_URL и API_EXTERNAL_URL в .env остались со значениями по умолчанию. Сервис авторизации формирует каждую ссылку для подтверждения и сброса пароля на основе этих двух значений, поэтому он отправляет тот адрес, который был указан. Установите оба параметра на ваш реальный публичный URL и пересоздайте стек.