אירוח עצמי של Supabase על שרת VPS באמצעות Docker
למדו כיצד להריץ את ה-stack הרשמי של Supabase על שרת פרטי. המדריך מפרט אילו secrets חובה להחליף בקובץ .env, דרישות זיכרון RAM, ניהול 14 השירותים וביצוע עדכונים ללא אובדן נתונים.
מה אתם בונים
אירוח עצמי של Supabase משמעו הרצת ה-stack הרשמי של Docker Compose על השרת שלכם: Postgres, ממשק REST API לפניו, שירות אימות (auth), אחסון קבצים, WebSocket בזמן אמת, ולוח הבקרה Studio. אתם משכפלים מאגר אחד, עורכים קובץ .env אחד, ומפעילים כ-14 מכולות שמתנהגות יחד כפרויקט Supabase בשליטתכם.
ההתקנה קצרה. החלק שמשתבש הוא קובץ ה-.env. הוא מגיע עם secrets לדוגמה שפורסמו במאגר, ו-stack שמופעל עם ברירות המחדל הללו חשוף לכל מי שימצא אותו. מדריך זה מכסה את ה-secrets שעליכם להחליף, את מטרת כל שירות, את כמות הזיכרון שה-stack באמת דורש, וכיצד לעדכן אותו מבלי למחוק את מסד הנתונים שלכם.
אם Docker Compose חדש לכם, קראו תחילה את יסודות Docker Compose ב-VPS. כל מה שמופיע להלן מניח ש-docker compose version כבר מציג גרסה תקינה.
מה באמת מכיל ה-stack
Supabase אינו תוכנה אחת. קובץ ה-Compose מפעיל קבוצה של שירותים נפרדים על רשת אחת, והבנה של תפקיד כל שירות הופכת רשימה ארוכה של שמות מכולות למשהו שניתן לבצע עבורו ניפוי שגיאות (debug).
dbהוא PostgreSQL עם התוספים של Supabase טעונים. כל שירות אחר מתקשר מולו. אם מכולה זו אינה תקינה, כל השאר יכשלו גם הם.kongהוא ה-API gateway. הוא מאזין בפורט 8000 ומנתב את/rest/v1/,/auth/v1/ו-/storage/v1/ל-backend המתאים. זו המכולה היחידה שצריך לחשוף החוצה.restהוא PostgREST. הוא קורא את ה-schema של Postgres ומגיש אותו כ-REST API, כך שכל טבלה חדשה הופכת ל-endpoint חדש ללא צורך בכתיבת קוד.authהוא GoTrue. הוא מנפיק את ה-JSON web tokens (JWT) שמזהים את המשתמשים שלכם.storageו-imgproxyמטפלים בהעלאות קבצים ובשינוי גודל של תמונות.realtimeמזרים שינויים במסד הנתונים דרך websockets.studioו-metaהם ה-dashboard וה-admin API שמאחוריו.analytics(Logflare) ו-vectorאוספים לוגים, ו-supavisorהוא ה-connection pooler של Postgres.
רשימה זו היא הסיבה לכך שמספרי המשאבים המפורטים להלן הם כפי שהם. אתם לא מריצים רק מסד נתונים. אתם מריצים מסד נתונים בתוספת תריסר שירותי תמיכה.
תכנון משאבים: הקצו 8 GB של RAM
נכון ליולי 2026, ה-stack צורך במצב המתנה (idle) כ-2.5 עד 3 GB של זיכרון פיזי בהתקנה נקייה, עוד לפני הוספת נתונים או תעבורה. שירות ה-analytics ותהליך ה-Node.js של ה-Studio הם הצרכנים הגדולים ביותר. שרת עם 2 GB יצליח להעלות את המכולות, אך לאחר מכן אחת מהן תופסק על ידי מנגנון ה-out of memory killer של ה-kernel, בדרך כלל analytics או db; התסמין לכך הוא מכולה שתקועה במצב הפעלה מחדש עם exit code 137.
עבור כל שירות שאתם מסתמכים עליו, הקצו 8 GB של RAM ו-4 vCPU. נפח של 4 GB יספיק לסביבת פיתוח אישית, בתנאי שתקבלו בהבנה שביצוע שאילתה כבדה במקביל לעבודה ב-Studio יגרור איטיות. גם לנפח הדיסק יש חשיבות, שכן Postgres, נפח האחסון ונתוני ה-log נמצאים כולם תחת תיקיית הפרויקט. התחילו עם 40 GB ועקבו אחר הצריכה. מומלץ להרגיל את עצמכם למנות את השירותים לפני בחירת תוכנית אירוח לכל שירות שאתם מארחים בעצמכם, שכן PhotoPrism ו-Immich דורשים רף RAM מינימלי גבוה משמעותית ממה שמשתמע מדפי ה-quick start שלהם.
התקנה: שכפול המאגר הרשמי
הנתיב הנתמך מעתיק את הספרייה 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 בשלב זה משמעותה שתג התמונה המקובע הוסר במקור, והפתרון הוא למשוך עותק חדש יותר של המאגר במקום לערוך תגים באופן ידני.
הסודות שיש לשנות לפני ההפעלה הראשונה
בצעו זאת לפני הפעלת ה-stack, ולא לאחר מכן. חלק מהערכים הללו נכתבים לתוך הנתונים בעת ה-boot הראשון, לכן שינוי שלהם בשלב מאוחר יותר מחייב איפוס של מסד הנתונים.
ה-repository כולל מחולל שמייצר כל ערך בצורה תקינה, כולל שני מפתחות ה-API שחייבים להיות חתומים עם ה-JWT secret החדש שלכם.
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 ואת ה-tokens של Logflare לתוך .env. הוא זקוק ל-openssl, שקיים בכל image סטנדרטי של Ubuntu.
ישנם שני ערכים שהסקריפט אינו מגדיר, ועליכם לערוך ידנית בתוך .env:
POSTGRES_PASSWORD. השתמשו באותיות ובספרות בלבד. סימני פיסוק כאן משבשים את מחרוזות החיבור ששירותים שונים בונים על ידי שרשור מחרוזות; הכשל נראה כשגיאת אימות (authentication error) ולא כשגיאת ניתוח (parsing error), מה שגורם למשתמשים לחפש את הבעיה במקום הלא נכון.DASHBOARD_USERNAMEו-DASHBOARD_PASSWORD. אלו הם פרטי האימות הבסיסיים עבור Studio. סיסמת ברירת המחדל שמגיעה עם המערכת היא פשוטthis_password_is_insecure_and_should_be_updated.
הבינו מדוע לא ניתן להמציא את ANON_KEY ו-SERVICE_ROLE_KEY. שניהם JWTs חתומים עם JWT_SECRET. ה-gateway מאמת את החתימה הזו בכל בקשה, לכן מפתח שאינו תואם ל-secret שלכם נדחה עם {"message":"Invalid authentication credentials"}. זהו כשל ה-self-hosting הנפוץ ביותר: המפעיל שינה את JWT_SECRET אך השאיר את מפתחות ה-demo. צרו את שלושתם יחד, תמיד.
התייחסו ל-SERVICE_ROLE_KEY כמו אל סיסמת root. הוא עוקף לחלוטין את ה-row level security. מקומו בקוד צד-שרת בלבד, ולא בשום מקום אחר.
הגדירו את SITE_URL ו-API_EXTERNAL_URL לכתובת שאליה המשתמשים שלכם יגיעו בפועל, לדוגמה https://supabase.example.com. שירות ה-Auth בונה את קישורי אימות האימייל וקישורי ה-callback של ה-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 מבוססים על אימות בסיסי (Basic Authentication), שהוא קידוד base64 ולא הצפנה.
הציבו reverse proxy לפני השירות, בצעו בו TLS termination, והגדירו את Kong להאזין לכתובת ה-loopback בלבד כדי למנוע גישה חיצונית. ב-docker-compose.yml מיפוי הפורטים kong הופך ל-127.0.0.1:8000:8000, וה-proxy מעביר את הבקשות לשם. המדריך Traefik לפני כמה יישומי Compose מסביר את הצד של ניהול התעודות.
סגרו את שאר הפורטים ב-firewall, כיוון ש-Docker מפרסם פורטים על ידי כתיבת חוקי iptables משלו, שקונפיגורציית ufw בסיסית אינה מזהה. מלכודת זו מוסברת ב-מדוע מכולות Docker מתעלמות מחוקי ה-ufw שלכם.
גבו את מסד הנתונים, לא את הספרייה
הנתונים של Postgres נמצאים ב-bind mount בנתיב ./volumes/db/data. העתקת הספרייה בזמן שהמכולה רצה יוצרת עותק פגום (torn copy), כיוון ש-Postgres מבצעת buffering לכתיבות והקבצים בדיסק עקביים רק בנקודת checkpoint. שחזור מגיבוי כזה בדרך כלל יעבוד, אך לעיתים יאבד בשקט את הטרנזקציות האחרונות – תרחיש הכשל הגרוע ביותר עבור גיבוי.
בצעו Dump במקום זאת. הפקודה pg_dumpall רצה בתוך המכולה ומייצרת snapshot עקבי:
docker exec -t supabase-db pg_dumpall -U postgres > supabase-$(date +%F).sqlודאו שהקובץ אינו ריק לפני שאתם מסתמכים עליו. לאחר מכן, העבירו את ה-dumps הללו מחוץ לשרת לפי לוח זמנים, וזהו בדיוק הייעוד של גיבויים מוצפנים מחוץ לאתר באמצעות restic. גבו את .env במקביל. אובדן של JWT_SECRET משמעו שכל אסימון (token) שהונפק הופך ללא תקף וכל סוד מוצפן שנשמר הופך לבלתי קריא.
קבצים שהועלו נמצאים ב-./volumes/storage, ומכיוון שמדובר בקבצים רגילים, העתקה פשוטה שלהם היא תקינה.
עדכון ללא אובדן נתונים
Supabase מקבע גרסאות של images בתוך docker-compose.yml, ולכן שום דבר אינו משתנה עד שמעדכנים אותו במפורש. כדאי להעתיק את דפוס הקיבוע לכל stack שמרכיבים ידנית. לכן relay עצמאי של RustDesk מקבע את שתי תמונות השרת שלו, במקום לעקוב אחר תגית משתנה: שדרוג צריך להתבצע רק במועד שבחרתם ושיש לכם זמן לטפל בו. לפני כל פעולה, בצעו dump.ાજપ
docker compose pull
sh run.sh recreateהפקודה recreate עוצרת את ה-stack ומפעילה אותו מחדש על ה-images החדשים. הנתונים שלכם נשמרים מכיוון שהם נמצאים ב-bind mounts על ה-host, ולא בתוך המכולות. קראו את CHANGELOG.md במאגר לפני שדרוג גרסה מרכזית, כיוון ששדרוגי גרסה מרכזית של Postgres אינם אוטומטיים ומחייבים ביצוע dump ו-restore.
כדי להחיל שינויים בקובץ ה-Compose עצמו, בצעו clone למאגר ה-upstream שוב והעתיקו את ספריית ה-docker שלו על פני הפרויקט שלכם, תוך הקפדה לא לדרוס את .env.
איפוס מלא, שמוחק את כל המידע כולל מסד הנתונים, מתבצע באמצעות סקריפט נפרד המבקש אישור לפני הרצה:
sh reset.shFAQ
מדוע קריאות ה-API שלי מחזירות "Invalid authentication credentials"?
ה-ANON_KEY או ה-SERVICE_ROLE_KEY שלך לא נחתמו עם ה-JWT_SECRET שנמצא כעת ב-.env. ה-gateway מאמת את החתימה בכל בקשה ודוחה חוסר התאמה. צור מחדש את שלושתם יחד באמצעות sh utils/generate-keys.sh --update-env, ולאחר מכן הרץ את sh run.sh recreate כדי שהשירותים יקראו את הערכים החדשים.
האם ניתן להריץ Supabase בניהול עצמי על שרת VPS עם 2 GB RAM?
לא בצורה אמינה. ה-stack צורך כ-3 GB במצב המתנה נכון ליולי 2026, כיוון שהוא מריץ כארבעה-עשר שירותים. שרת עם 2 GB יאבד מכולות בגלל ה-out of memory killer, ואתה תראה קוד יציאה 137 ב-docker compose ps. השתמש ב-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.
מדוע קישורי אימות הדוא"ל של שירות ה-auth מפנים ל-localhost?
הערכים SITE_URL ו-API_EXTERNAL_URL ב-.env נותרו בערכי ברירת המחדל שלהם. שירות ה-auth בונה כל קישור לאימות ולאיפוס סיסמה על בסיס שני הערכים הללו, ולכן הוא שולח את הכתובת שהוגדרה לו. הגדר את שניהם לכתובת ה-URL הציבורית האמיתית שלך וצור מחדש את ה-stack.