SSD Nodes Learn 8GB RAM — $66/рік
Посібники Matt ConnorВід Matt Connor · Оновлено 2026-08-01

Supabase на VPS із Docker: повне самостійне розгортання

Дізнайтеся, які секрети замінити в .env, що роблять 14 сервісів Supabase, скільки RAM потрібно, як налаштувати резервні копії та оновлення.

Що ви розгортаєте

Self-hosting Supabase означає запуск офіційного стека Docker Compose на власному сервері: Postgres, REST API перед ним, сервіс автентифікації, файлове сховище, вебсокети realtime і панель Studio. Ви клонуєте один репозиторій, редагуєте один файл .env і запускаєте близько чотирнадцяти контейнерів, які разом працюють як керований вами проєкт Supabase.

Установлення коротке. Проблеми виникають через файл .env. Він містить демонстраційні секрети, опубліковані в репозиторії, а стек, запущений із цими значеннями за замовчуванням, відкритий для кожного, хто їх знайде. У цьому посібнику описано, які секрети потрібно замінити, для чого призначений кожен сервіс, скільки пам’яті насправді потребує стек і як оновлювати його без видалення бази даних.

Якщо Docker 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 (JWT), які ідентифікують користувачів.
  • storage і imgproxy обробляють завантаження файлів і змінюють розмір зображень.
  • realtime передає зміни бази даних через websockets.
  • studio і meta — це панель керування та API адміністратора, який вона використовує.
  • analytics (Logflare) і vector збирають журнали, а supavisor — це пулер підключень до Postgres.

Саме тому наведені нижче значення використаних ресурсів такі. Ви запускаєте не лише базу даних. Ви запускаєте базу даних і ще близько дюжини допоміжних сервісів.

Розмір: заплануйте 8 GB RAM

Після чистого встановлення стек використовує приблизно від 2.5 до 3 GB resident memory станом на July 2026, без урахування власних даних і мережевого трафіку. Сервіс аналітики та процес Studio Node.js є двома найбільшими окремими споживачами ресурсів. Сервер із 2 GB запустить контейнери, а потім kernel out of memory killer завершить один із них, зазвичай 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 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 у .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 ps

run.sh start обгортає docker compose up -d --wait, тому команда не повертає керування, доки не буде пройдено перевірки працездатності. Для кожної служби має відображатися running (healthy) або running. Перше запускання триває від двох до чотирьох хвилин, оскільки Postgres спочатку виконує сценарії ініціалізації, і лише після цього до нього можуть підключатися інші компоненти.

Якщо контейнер перезапускається, перегляньте його журнали за назвою служби:

docker compose logs db
docker compose logs auth

Studio працює на порту 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 зберігаються у змонтованому каталозі ./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 recreate

recreate зупиняє стек і запускає його знову з новими образами. Дані зберігаються, оскільки вони розміщені у bind mounts на хості, а не всередині контейнерів. Перед переходом на нову основну версію прочитайте CHANGELOG.md у репозиторії, оскільки основні оновлення Postgres не виконуються автоматично й потребують створення дампа та відновлення.

Щоб застосувати зміни безпосередньо до файлу Compose, знову клонуйте upstream-репозиторій і скопіюйте його каталог docker у свій проєкт. Не перезаписуйте .env.

Повне скидання, яке знищує все, зокрема базу даних, виконує окремий скрипт. Він запитує підтвердження:

sh reset.sh

FAQ

Чому мої виклики 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 RAM, оскільки запускає близько fourteen служб. Тому на сервері з 2 GB RAM контейнери завершуються через OOM killer, а у docker compose ps з’являється код завершення 137. Для production використовуйте 8 GB RAM, а 4 GB RAM вважайте мінімальним обсягом для самостійної розробки.

Чи містить Supabase на власному сервері edge functions?

Так. Compose-файл містить середовище виконання функцій на основі Deno і обслуговує все, що розміщено в ./volumes/functions. До нього не входить глобальна мережа розгортання hosted-платформи. Тому ваші функції працюють на одному сервері та в одному розташуванні.

Як підключитися безпосередньо до бази даних 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-адресу та повторно створіть стек.