SSD Nodes Learn 8GB RAM — سالی $66
راهنماها Matt Connorتوسط Matt Connor · به‌روزرسانی شده 2026-08-01

نصب Supabase روی VPS با Docker؛ راهنمای self-hosting

استک رسمی Docker مربوط به Supabase را روی VPS خود اجرا کنید؛ secretهای پیش‌فرض، نقش 14 سرویس، نیاز واقعی RAM، پشتیبان‌گیری و به‌روزرسانی بدون حذف پایگاه‌داده را ببینید.

آنچه می‌سازید

Self-hosting Supabase یعنی اجرای رسمی Docker Compose stack روی سرور خودتان: Postgres، یک REST API در برابر آن، یک سرویس احراز هویت، فضای ذخیره‌سازی فایل، realtime websockets و داشبورد Studio. یک repository را clone می‌کنید، یک فایل .env را ویرایش می‌کنید و حدود چهارده container را راه‌اندازی می‌کنید که در مجموع مانند یک پروژه Supabase تحت کنترل شما عمل می‌کنند.

نصب کوتاه است. بخش مشکل‌ساز، فایل .env است. این فایل با secretهای آزمایشی ارائه می‌شود که در repository منتشر شده‌اند و stackای که با این مقادیر پیش‌فرض راه‌اندازی شود، برای هر فردی که آن را پیدا کند باز است. این راهنما secretهایی را که باید جایگزین کنید، کاربرد هر سرویس، میزان واقعی حافظه موردنیاز stack و روش به‌روزرسانی آن بدون حذف پایگاه داده را توضیح می‌دهد.

اگر Compose برای شما جدید است، ابتدا مبانی Docker Compose روی VPS را بخوانید. تمام مطالب زیر فرض می‌کنند که docker compose version از قبل یک version نمایش می‌دهد.

محتوای واقعی stack

Supabase یک برنامه واحد نیست. فایل Compose مجموعه‌ای از سرویس‌های جداگانه را در یک شبکه راه‌اندازی می‌کند. اگر بدانید هر سرویس چه کاری انجام می‌دهد، عیب‌یابی فهرست طولانی نام‌های container ساده‌تر می‌شود.

  • db همان PostgreSQL است که افزونه‌های Supabase روی آن بارگذاری شده‌اند. همه سرویس‌های دیگر با آن ارتباط دارند. اگر این container ناسالم باشد، همه سرویس‌های دیگر نیز از کار می‌افتند.
  • kong دروازه API است. این سرویس روی port 8000 به درخواست‌ها گوش می‌دهد و /rest/v1/، /auth/v1/ و /storage/v1/ را به backend مناسب مسیریابی می‌کند. فقط همین container را باید در معرض دسترسی قرار دهید.
  • rest همان PostgREST است. این سرویس schema مربوط به Postgres را می‌خواند و آن را به‌صورت REST API ارائه می‌کند. بنابراین، جدول جدید بدون نوشتن کد به endpoint جدید تبدیل می‌شود.
  • auth همان GoTrue است. این سرویس JSON web token (JWT)هایی را صادر می‌کند که کاربران شما را شناسایی می‌کنند.
  • storage و imgproxy آپلود فایل و تغییر اندازه تصویر را انجام می‌دهند.
  • realtime تغییرات پایگاه داده را از طریق websocketها ارسال می‌کند.
  • studio و meta به‌ترتیب dashboard و admin API مربوط به آن هستند.
  • analytics (Logflare) و vector لاگ‌ها را جمع‌آوری می‌کنند و supavisor pooler اتصال‌های Postgres است.

به همین دلیل اعداد مربوط به منابع در بخش‌های بعدی چنین هستند. شما فقط یک database را اجرا نمی‌کنید. یک database به‌همراه دوازده سرویس پشتیبان را اجرا می‌کنید.

اندازه‌گذاری: برای 8 GB حافظه RAM برنامه‌ریزی کنید

این پشته در یک نصب تازه، تا ژوئیه 2026 و پیش از اضافه‌شدن داده‌ها یا ترافیک شما، تقریباً 2.5 تا 3 GB حافظه مقیم مصرف می‌کند. سرویس analytics و فرایند Studio Node.js دو مصرف‌کننده منفرد بزرگ‌تر هستند. یک سرور 2 GB کانتینرها را راه‌اندازی می‌کند، اما سپس هسته یکی از آن‌ها را به‌دلیل فعال‌شدن out of memory killer متوقف می‌کند؛ این وضعیت معمولاً با analytics یا db رخ می‌دهد. نشانه آن، کانتینری است که پیوسته راه‌اندازی مجدد می‌شود و با exit code 137 خارج می‌شود.

برای هر محیطی که به آن اتکا دارید، 8 GB حافظه RAM و 4 vCPU اختصاص دهید. 4 GB برای یک نمونه توسعه انفرادی قابل استفاده است، اگر بپذیرید که اجرای هم‌زمان یک پرس‌وجوی سنگین و یک نشست Studio کند خواهد بود. فضای دیسک نیز اهمیت دارد، زیرا Postgres، volume ذخیره‌سازی و داده‌های log همگی در مسیر پروژه قرار دارند. با 40 GB شروع کنید و آن را monitor کنید.

نصب: کلون‌کردن مخزن رسمی

روش پشتیبانی‌شده، پوشه 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 چندین گیگابایت image دانلود می‌کند. در پایان، وضعیت همه سرویس‌ها باید Pulled باشد. خطای manifest unknown در این مرحله یعنی tag مربوط به image مشخص‌شده در upstream حذف شده است. راه‌حل، دریافت نسخه جدیدتری از مخزن است، نه ویرایش دستی tagها.

رازهایی که باید قبل از اولین راه‌اندازی تغییر دهید

این کار را پیش از راه‌اندازی stack انجام دهید، نه پس از آن. چند مورد از این مقادیر در اولین boot داخل داده‌ها نوشته می‌شوند؛ بنابراین تغییر آن‌ها در ادامه مستلزم بازنشانی database است.

repository یک generator دارد که همه مقادیر را به‌درستی تولید می‌کند؛ از جمله 2 API key که باید با JWT secret جدید شما امضا شوند.

sh utils/generate-keys.sh --update-env

این script مقادیر جدید را برای JWT_SECRET، ANON_KEY، SERVICE_ROLE_KEY، SECRET_KEY_BASE، REALTIME_DB_ENC_KEY، VAULT_ENC_KEY، PG_META_CRYPTO_KEY و tokenهای Logflare در .env می‌نویسد. این script به openssl نیاز دارد که در هر Ubuntu image معمولی موجود است.

2 مقدار را تنظیم نمی‌کند و باید آن‌ها را به‌صورت دستی در .env ویرایش کنید:

  • POSTGRES_PASSWORD. فقط از حروف و ارقام استفاده کنید. وجود علائم نگارشی در این مقدار، connection stringهایی را که چند service با الحاق رشته‌ها می‌سازند مختل می‌کند. در این حالت، خطا به‌جای خطای parsing شبیه خطای authentication دیده می‌شود و افراد را به بررسی بخش نادرست هدایت می‌کند.
  • DASHBOARD_USERNAME و DASHBOARD_PASSWORD. این‌ها credentialهای basic authentication برای Studio هستند. password پیش‌فرض ارائه‌شده دقیقاً this_password_is_insecure_and_should_be_updated است.

باید بدانید چرا نمی‌توان ANON_KEY و SERVICE_ROLE_KEY را به‌صورت دلخواه ایجاد کرد. هر دو JWT هستند که با JWT_SECRET امضا شده‌اند. gateway این امضا را در هر request بررسی می‌کند؛ بنابراین keyای که با secret شما مطابقت نداشته باشد با {"message":"Invalid authentication credentials"} رد می‌شود. این رایج‌ترین خطا در self-hosting است: operator مقدار JWT_SECRET را تغییر می‌دهد، اما keyهای نمایشی را نگه می‌دارد. هر 3 مقدار را همیشه با هم تولید کنید.

با SERVICE_ROLE_KEY مانند root password رفتار کنید. این مقدار به‌طور کامل row level security را دور می‌زند. این مقدار فقط باید در server-side code قرار داشته باشد و نباید در جای دیگری استفاده شود.

SITE_URL و API_EXTERNAL_URL را روی نشانی‌ای تنظیم کنید که کاربران واقعاً از طریق آن به service دسترسی خواهند داشت؛ برای مثال https://supabase.example.com. Auth لینک‌های email confirmation و OAuth callback را بر اساس این مقادیر ایجاد می‌کند. بنابراین اگر آن‌ها را روی http://localhost:8000 باقی بگذارید، همه کاربران به machine خودشان هدایت می‌شوند.

سپس مقادیر تنظیم‌شده را بررسی کنید:

sh run.sh secrets

آن را راه‌اندازی کنید و از سالم بودن آن مطمئن شوید

sh run.sh start
docker compose ps

run.sh start، docker compose up -d --wait را دربرمی‌گیرد؛ بنابراین تا زمان موفقیت بررسی‌های سلامت بازنمی‌گردد. هر سرویس باید وضعیت running (healthy) یا running را نشان دهد. راه‌اندازی نخست 2 تا 4 دقیقه طول می‌کشد، زیرا Postgres پیش از آنکه هر مورد دیگری بتواند متصل شود، اسکریپت‌های مقداردهی اولیه خود را اجرا می‌کند.

اگر یک container در حال راه‌اندازی مجدد است، گزارش‌های آن را بر اساس نام سرویس بخوانید:

docker compose logs db
docker compose logs auth

Studio اکنون روی port 8000 در دسترس است و نام کاربری و گذرواژه dashboard را که تنظیم کرده‌اید درخواست می‌کند.

پورت 8000 را در اینترنت عمومی قرار ندهید

Kong روی پورت 8000 با HTTP ساده ارتباط برقرار می‌کند. همه کلیدهای API و گذرواژه‌های کاربران به‌صورت متن واضح از شبکه عبور می‌کنند. اعتبارنامه‌های Studio نیز از احراز هویت پایه استفاده می‌کنند که به‌جای رمزنگاری، فقط encoding به‌صورت base64 است.

یک reverse proxy را در مقابل آن قرار دهید و TLS (امنیت لایه انتقال) را در همان‌جا خاتمه دهید. سپس Kong را به آدرس loopback متصل کنید تا هیچ سرویس دیگری نتواند به آن دسترسی داشته باشد. در docker-compose.yml، نگاشت پورت kong به 127.0.0.1:8000:8000 تبدیل می‌شود و proxy درخواست‌ها را به آن ارسال می‌کند. قرار دادن Traefik در مقابل چند برنامه Compose بخش مربوط به گواهی را پوشش می‌دهد.

باقی پورت‌ها را نیز در firewall مسدود کنید، زیرا Docker با نوشتن ruleهای اختصاصی خود در iptables پورت‌ها را منتشر می‌کند و یک پیکربندی ساده ufw این ruleها را نمی‌بیند. این دام در دلیل نادیده گرفتن ruleهای ufw توسط کانتینرهای Docker توضیح داده شده است.

از پایگاه داده نسخه پشتیبان بگیرید، نه از دایرکتوری

داده‌های Postgres در یک bind mount در مسیر ./volumes/db/data قرار دارند. اگر هنگام اجرای container این دایرکتوری را کپی کنید، یک کپی ناقص ایجاد می‌شود؛ زیرا Postgres نوشتن‌ها را buffer می‌کند و فایل‌های روی دیسک فقط در زمان checkpoint سازگار هستند. بازیابی این کپی معمولاً انجام می‌شود، اما گاهی آخرین تراکنش‌ها بدون هیچ هشدار آشکاری از بین می‌روند. این بدترین حالت ممکن برای یک نسخه پشتیبان است.

در عوض، dump بگیرید. pg_dumpall داخل container اجرا می‌شود و یک snapshot سازگار ایجاد می‌کند:

docker exec -t supabase-db pg_dumpall -U postgres > supabase-$(date +%F).sql

پیش از اعتماد به فایل، بررسی کنید که خالی نباشد. سپس این dumpها را طبق یک برنامه زمانی به خارج از server منتقل کنید؛ نسخه‌های پشتیبان رمزگذاری‌شده خارج از سایت با restic برای همین کار است. هم‌زمان از .env نیز نسخه پشتیبان بگیرید. از دست رفتن JWT_SECRET باعث می‌شود همه tokenهای صادرشده نامعتبر شوند و همه secretهای رمزگذاری‌شده ذخیره‌شده قابل خواندن نباشند.

فایل‌های بارگذاری‌شده در ./volumes/storage قرار دارند و فایل‌های معمولی هستند؛ بنابراین کپی ساده آن‌ها کافی است.

به‌روزرسانی بدون از دست دادن داده‌ها

Supabase نسخه‌های image را در docker-compose.yml ثابت می‌کند؛ بنابراین تا زمانی که خودتان آن را تغییر ندهید، چیزی جابه‌جا نمی‌شود. هر بار ابتدا یک dump بگیرید.

docker compose pull
sh run.sh recreate

recreate پشته را متوقف می‌کند و آن را با imageهای جدید دوباره راه‌اندازی می‌کند. داده‌های شما باقی می‌مانند، زیرا روی bind mountهای میزبان قرار دارند، نه داخل containerها. پیش از ارتقای major version، CHANGELOG.md را در repository بخوانید، زیرا ارتقای major در Postgres خودکار نیست و به dump و restore نیاز دارد.

برای اعمال تغییرات خود فایل Compose، repository بالادستی را دوباره clone کنید و directory مربوط به docker را روی پروژه خود کپی کنید. مراقب باشید .env را overwrite نکنید.

بازنشانی کامل، که همه‌چیز از جمله database را حذف می‌کند، اسکریپت جداگانه‌ای دارد و برای تأیید از شما درخواست می‌کند:

sh reset.sh

FAQ

چرا فراخوانی‌های API من پیام «اعتبارنامه‌های احراز هویت نامعتبر است» برمی‌گردانند؟

ANON_KEY یا SERVICE_ROLE_KEY شما با JWT_SECRETای که در حال حاضر در .env قرار دارد، امضا نشده است. دروازه امضای هر درخواست را بررسی می‌کند و در صورت مغایرت، درخواست را رد می‌کند. هر سه مقدار را با sh utils/generate-keys.sh --update-env دوباره تولید کنید، سپس sh run.sh recreate را اجرا کنید تا سرویس‌ها مقادیر جدید را بخوانند.

آیا می‌توانم Supabase خودمیزبان را روی یک VPS با 2 GB اجرا کنم؟

به‌طور قابل‌اعتماد نه. این پشته در July 2026 حدود 3 GB حافظه را در حالت بیکار مصرف می‌کند، زیرا حدود fourteen سرویس اجرا می‌کند. بنابراین یک ماشین 2 GB کانتینرها را به دلیل فعال‌شدن out of memory killer از دست می‌دهد و کد خروج 137 را در docker compose ps مشاهده می‌کنید. برای محیط production از 8 GB استفاده کنید و 4 GB را حداقل موردنیاز برای توسعه انفرادی در نظر بگیرید.

آیا 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 عمومی واقعی خود تنظیم کنید و پشته را دوباره ایجاد کنید.