SSD Nodes Learn Hosting plans →
गाइड Matt Connorलेखक: Matt Connor · अपडेट किया गया: 2026-08-27

VPS पर Supabase को Docker के साथ self-host कैसे करें

अपने VPS पर Supabase Docker stack को सुरक्षित रूप से चलाने का तरीका जानें। इसमें .env फ़ाइल के जरूरी secrets, 14 services का विवरण, RAM की आवश्यकताएं और डेटा बैकअप शामिल हैं।

आप क्या बना रहे हैं

Supabase को self-host करने का अर्थ है अपने सर्वर पर आधिकारिक Docker Compose stack चलाना: Postgres, इसके सामने एक REST API, एक auth service, file storage, realtime websockets, और Studio dashboard। आप एक repository clone करते हैं, एक .env file को edit करते हैं, और लगभग चौदह containers start करते हैं जो मिलकर एक ऐसे Supabase project की तरह काम करते हैं जिसे आप नियंत्रित करते हैं।

install प्रक्रिया छोटी है। जो हिस्सा गलत हो सकता है वह .env file है। यह demo secrets के साथ आती है जो repository में public हैं, और उन defaults के साथ start किया गया stack किसी भी ऐसे व्यक्ति के लिए खुला है जो इसे ढूँढ लेता है। यह guide उन secrets को कवर करती है जिन्हें आपको बदलना होगा, प्रत्येक service किस लिए है, stack को वास्तव में कितनी memory की आवश्यकता है, और अपने database को delete किए बिना इसे update कैसे करें।

यदि Compose आपके लिए नया है, तो पहले Docker Compose basics on a VPS पढ़ें। नीचे दी गई हर चीज़ यह मानकर चलती है कि docker compose version पहले से ही एक version print करता है।

स्टैक में वास्तव में क्या शामिल है

Supabase कोई एक प्रोग्राम नहीं है। Compose फ़ाइल एक नेटवर्क पर अलग-अलग सेवाओं का एक सेट शुरू करती है, और यह जानना कि कौन सी सेवा क्या है, कंटेनर नामों की एक लंबी सूची को ऐसी चीज़ में बदल देता है जिसे आप डीबग कर सकते हैं।

  • db Supabase एक्सटेंशन के साथ लोड किया गया PostgreSQL है। अन्य सभी सेवाएँ इसी से बात करती हैं। यदि यह कंटेनर अस्वस्थ (unhealthy) है, तो बाकी सब कुछ भी विफल हो जाता है।
  • kong API गेटवे है। यह पोर्ट 8000 पर लिसन करता है और /rest/v1/, /auth/v1/ तथा /storage/v1/ को सही बैकएंड पर रूट करता है। यह एकमात्र कंटेनर है जिसे आपको कभी भी एक्सपोज़ करना चाहिए।
  • rest PostgREST है। यह आपके Postgres स्कीमा को पढ़ता है और इसे REST API के रूप में सर्व करता है, इसलिए एक नई टेबल बिना किसी कोड के एक नया एंडपॉइंट बन जाती है।
  • auth GoTrue है। यह JSON वेब टोकन (JWT) जारी करता है जो आपके उपयोगकर्ताओं की पहचान करते हैं।
  • storage और imgproxy फ़ाइल अपलोड और इमेज रिसाइज़िंग को संभालते हैं।
  • realtime वेबसॉकेट के माध्यम से डेटाबेस परिवर्तनों को स्ट्रीम करता है।
  • studio और meta डैशबोर्ड और उसके पीछे का एडमिन API हैं।
  • analytics (Logflare) और vector लॉग एकत्र करते हैं, और supavisor Postgres कनेक्शन पूलर है।

यह सूची ही कारण है कि नीचे दिए गए संसाधन नंबर इतने अधिक हैं। आप केवल एक डेटाबेस नहीं चला रहे हैं। आप एक डेटाबेस के साथ-साथ एक दर्जन सपोर्ट सेवाएँ चला रहे हैं।

Sizing: 8 GB RAM के लिए योजना बनाएं

जुलाई 2026 तक, आपके डेटा या ट्रैफिक से पहले, एक फ्रेश इंस्टॉलेशन पर यह स्टैक लगभग 2.5 से 3 GB रेजिडेंट मेमोरी का उपयोग करता है। एनालिटिक्स सर्विस और Studio Node.js प्रोसेस सबसे अधिक मेमोरी खपत करने वाले दो घटक हैं। 2 GB का सर्वर कंटेनर्स को शुरू तो कर देगा, लेकिन बाद में कर्नल का out of memory killer किसी एक कंटेनर को बंद कर देगा, जो आमतौर पर analytics या db होता है। इसका लक्षण यह है कि कंटेनर exit code 137 के साथ बार-बार रीस्टार्ट होता रहता है।

किसी भी ऐसे काम के लिए जिस पर आप निर्भर हैं, 8 GB RAM और 4 vCPU का उपयोग करें। यदि आप यह स्वीकार करते हैं कि एक भारी क्वेरी और Studio सेशन एक साथ चलने पर धीमे होंगे, तो सोलो डेवलपमेंट इंस्टेंस के लिए 4 GB पर्याप्त है। डिस्क भी महत्वपूर्ण है, क्योंकि Postgres, स्टोरेज वॉल्यूम और लॉग डेटा सभी प्रोजेक्ट डायरेक्टरी के अंतर्गत रहते हैं। 40 GB से शुरुआत करें और उस पर नज़र रखें। किसी भी self-hosted सर्विस के लिए प्लान चुनने से पहले सेवाओं की गणना करना एक अच्छी आदत है, क्योंकि PhotoPrism और Immich की वास्तविक RAM आवश्यकता उनके quick start पेजों में बताए गए आंकड़ों से काफी अधिक होती है।

Install: आधिकारिक रिपॉजिटरी को clone करें

समर्थित तरीका मुख्य रिपॉजिटरी से 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 एरर का मतलब है कि पिन किया गया इमेज टैग अपस्ट्रीम से हटा दिया गया है, और इसका समाधान टैग्स को मैन्युअल रूप से एडिट करने के बजाय रिपॉजिटरी की एक नई कॉपी पुल करना है।

वे secrets जिन्हें आपको पहली बार start करने से पहले बदलना होगा

यह काम stack को start करने से पहले करें, बाद में नहीं। इनमें से कई values पहली बार boot होने पर data में लिख दी जाती हैं, इसलिए उन्हें बाद में बदलने का मतलब है database को reset करना।

Repository में एक generator मौजूद है जो हर value को सही ढंग से तैयार करता है, जिसमें वे दो API keys भी शामिल हैं जिन्हें आपके नए JWT secret के साथ sign किया जाना चाहिए।

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 और Logflare tokens के लिए नई values को .env में लिखती है। इसके लिए openssl की आवश्यकता होती है, जो किसी भी सामान्य Ubuntu image पर उपलब्ध होता है।

दो values ऐसी हैं जिन्हें यह script set नहीं करती, और उन्हें आपको .env में स्वयं edit करना होगा:

  • POSTGRES_PASSWORD। केवल अक्षरों और अंकों का उपयोग करें। यहाँ punctuation का उपयोग करने से वे connection strings टूट जाती हैं जिन्हें कई services strings को जोड़कर बनाती हैं। इसकी विफलता एक authentication error जैसी दिखती है, न कि parsing error जैसी, जिससे लोग गलत जगह पर समस्या ढूँढने लगते हैं।
  • DASHBOARD_USERNAME और DASHBOARD_PASSWORD। ये Studio के लिए basic authentication credentials हैं। इसमें दिया गया default password वास्तव में this_password_is_insecure_and_should_be_updated है।

समझें कि ANON_KEY और SERVICE_ROLE_KEY को मनमाने ढंग से क्यों नहीं बनाया जा सकता। दोनों ही JWT_SECRET के साथ signed JWTs हैं। Gateway हर request पर उस signature की पुष्टि करता है, इसलिए जो key आपके secret से मेल नहीं खाती, उसे {"message":"Invalid authentication credentials"} के साथ reject कर दिया जाता है। self-hosting में यह सबसे आम विफलता है: operator ने JWT_SECRET तो बदल दिया लेकिन demo keys को ही रहने दिया। तीनों को हमेशा एक साथ ही generate करें।

SERVICE_ROLE_KEY के साथ root password जैसा व्यवहार करें। यह row level security को पूरी तरह से bypass कर देता है। इसे केवल server-side code में ही रखा जाना चाहिए, कहीं और नहीं।

SITE_URL और API_EXTERNAL_URL को उस address पर set करें जहाँ तक आपके users वास्तव में पहुँचेंगे, उदाहरण के लिए https://supabase.example.com। Auth अपनी email confirmation और OAuth callback links को इन्हीं values से बनाता है, इसलिए उन्हें http://localhost:8000 पर छोड़ देने से आपके सभी users अपने स्वयं के machine पर redirect हो जाएंगे।

इसके बाद जाँचें कि आपके पास क्या है:

sh run.sh secrets

इसे start करें और सुनिश्चित करें कि यह healthy है

sh run.sh start
docker compose ps

run.sh start, docker compose up -d --wait को wrap करता है, इसलिए यह तब तक return नहीं करता जब तक health checks पास न हो जाएं। प्रत्येक service को running (healthy) या running दिखाना चाहिए। पहली बार boot होने में 2 से 4 मिनट लगते हैं क्योंकि Postgres किसी भी अन्य चीज़ के connect होने से पहले अपनी initialisation scripts चलाता है।

यदि कोई container बार-बार restart हो रहा है, तो service के नाम के अनुसार उसके logs पढ़ें:

docker compose logs db
docker compose logs auth

Studio इसके बाद port 8000 पर उपलब्ध होगा, और यह आपसे वह dashboard username और password मांगेगा जिसे आपने set किया है।

पोर्ट 8000 को पब्लिक इंटरनेट पर न रखें

Kong पोर्ट 8000 पर plain HTTP का उपयोग करता है। प्रत्येक API key और उपयोगकर्ता का पासवर्ड नेटवर्क पर clear text में जाता है, और Studio credentials basic authentication का उपयोग करते हैं, जो encryption के बजाय base64 encoding है।

इसके सामने एक reverse proxy लगाएँ, वहाँ TLS (transport layer security) terminate करें, और Kong को loopback address पर bind करें ताकि कोई अन्य इसे एक्सेस न कर सके। docker-compose.yml में kong पोर्ट मैपिंग 127.0.0.1:8000:8000 हो जाती है, और proxy उस पर traffic forward करता है। कई Compose apps के सामने Traefik सर्टिफिकेट वाले हिस्से को कवर करता है। वही proxy अंततः सर्वर पर मौजूद बाकी सभी चीजों को भी संभालता है, इस stack से लेकर 90 के दशक के वीडियो स्टोर के रूप में फिर से बनाई गई Jellyfin लाइब्रेरी जैसी सामान्य चीजों तक, और उनमें से प्रत्येक को एक और open port के बजाय एक hostname की आवश्यकता होती है। यदि कोई dashboard केवल आपके उपयोग के लिए है, तो proxy को छोड़ दें और इसके बजाय SSH tunnel के माध्यम से loopback port तक पहुँचें, यही वह तरीका है जिसका उपयोग self-hosted open-kritt अपने स्कैनिंग इंटरफ़ेस को पूरी तरह से पब्लिक इंटरनेट से दूर रखने के लिए करता है।

बाकी पोर्ट्स को भी firewall पर बंद कर दें, क्योंकि Docker अपने स्वयं के iptables नियम लिखकर पोर्ट्स को publish करता है जिन्हें एक सामान्य ufw कॉन्फ़िगरेशन देख नहीं पाता है। यह समस्या Docker containers आपके ufw नियमों को क्यों अनदेखा करते हैं में समझाई गई है।

डेटाबेस का बैकअप लें, डायरेक्टरी का नहीं

Postgres डेटा ./volumes/db/data पर एक bind mount में रहता है। कंटेनर के चलते समय उस डायरेक्टरी को कॉपी करने से आपको एक अधूरा (torn) बैकअप मिलता है, क्योंकि Postgres writes को बफर करता है और डिस्क पर फाइलें केवल checkpoint पर ही consistent होती हैं। इसे रिस्टोर करना आमतौर पर काम कर जाता है, लेकिन कभी-कभी यह चुपचाप अंतिम ट्रांजेक्शन को खो देता है, जो बैकअप के लिए सबसे खराब स्थिति है।

इसके बजाय dump का उपयोग करें। pg_dumpall कंटेनर के अंदर चलता है और एक consistent स्नैपशॉट तैयार करता है:

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

भरोसा करने से पहले जांच लें कि फाइल खाली तो नहीं है। फिर इन dumps को एक शेड्यूल के अनुसार सर्वर से बाहर भेजें, जिसके लिए encrypted offsite backups with restic का उपयोग किया जाता है। एक शेड्यूल किया गया dump जो चुपचाप विफल हो जाता है, वह बिना बैकअप के होने जैसा ही है, इसलिए cron या systemd जॉब को push an alert to your phone के लिए कॉन्फ़िगर करें जब यह non-zero exit कोड दे। साथ ही अपने .env का भी बैकअप लें। JWT_SECRET खोने का मतलब है कि हर जारी किया गया टोकन अमान्य हो जाएगा और हर स्टोर किया गया एन्क्रिप्टेड सीक्रेट अपठनीय हो जाएगा।

अपलोड की गई फाइलें ./volumes/storage में रहती हैं, और वे सामान्य फाइलें हैं, इसलिए उनकी सीधी कॉपी लेना ठीक है।

डेटा खोए बिना अपडेट करना

Supabase docker-compose.yml में image versions को pin करता है, इसलिए जब तक आप स्वयं version न बदलें, कुछ भी अपने-आप आगे नहीं बढ़ता। अपने हाथ से तैयार किए गए किसी भी stack में pinning अपनाना उपयोगी है। इसी कारण self-hosted RustDesk relay moving tag को follow करने के बजाय अपनी दोनों server images को pin करता है: upgrade ऐसा काम होना चाहिए जिसे आप उस सुबह चुनें, जब आपके पास उसके लिए समय हो। हर बार पहले dump लें।

docker compose pull
sh run.sh recreate

recreate स्टैक को रोकता है और नई इमेजेस पर इसे फिर से शुरू करता है। आपका डेटा सुरक्षित रहता है क्योंकि यह कंटेनरों के अंदर नहीं, बल्कि होस्ट पर मौजूद बाइंड माउंट्स (bind mounts) में रहता है। किसी भी मेजर वर्ज़न जंप से पहले रिपॉजिटरी में CHANGELOG.md को पढ़ें, क्योंकि Postgres के मेजर अपग्रेड अपने आप नहीं होते और इसके लिए डंप और रिस्टोर की आवश्यकता होती है।

Compose फाइल में किए गए बदलावों को लागू करने के लिए, अपस्ट्रीम रिपॉजिटरी को फिर से क्लोन करें और इसकी docker डायरेक्टरी को अपने प्रोजेक्ट पर कॉपी करें। ध्यान रखें कि .env ओवरराइट न हो।

फुल रिसेट, जो डेटाबेस सहित सब कुछ नष्ट कर देता है, एक अलग स्क्रिप्ट है और यह पुष्टि (confirmation) मांगती है:

sh reset.sh

FAQ

मेरे API calls "Invalid authentication credentials" क्यों दिखाते हैं?

आपका ANON_KEY या SERVICE_ROLE_KEY उस JWT_SECRET के साथ हस्ताक्षरित (signed) नहीं था जो वर्तमान में .env में है। गेटवे हर अनुरोध पर हस्ताक्षर की जांच करता है और बेमेल होने पर उसे अस्वीकार कर देता है। sh utils/generate-keys.sh --update-env के साथ तीनों को एक साथ फिर से जनरेट करें, और फिर sh run.sh recreate चलाएं ताकि सेवाएं नए मानों को पढ़ सकें।

क्या मैं 2 GB VPS पर self-hosted Supabase चला सकता हूँ?

विश्वसनीय रूप से नहीं। जुलाई 2026 तक यह स्टैक लगभग 3 GB RAM का उपयोग करता है क्योंकि यह लगभग चौदह सेवाएं चलाता है। इसलिए 2 GB का सर्वर out of memory killer के कारण कंटेनरों को बंद कर देता है और आपको docker compose ps में exit code 137 दिखाई देता है। प्रोडक्शन के लिए 8 GB का उपयोग करें और व्यक्तिगत विकास के लिए 4 GB को न्यूनतम सीमा मानें।

क्या self-hosted Supabase में edge functions शामिल हैं?

हाँ। Compose फ़ाइल में Deno आधारित फंक्शन्स रनटाइम शामिल है, और यह उन सभी को सर्व करता है जिन्हें आप ./volumes/functions के अंतर्गत रखते हैं। इसमें होस्टेड प्लेटफ़ॉर्म का ग्लोबल डिप्लॉयमेंट नेटवर्क शामिल नहीं है, इसलिए आपके फंक्शन्स आपके एक सर्वर पर, एक ही स्थान पर चलते हैं।

मैं Postgres डेटाबेस से सीधे कैसे कनेक्ट करूँ?

सर्वर पर ही इंटरैक्टिव शेल के लिए docker exec -it supabase-db psql -U postgres का उपयोग करें। बाहरी क्लाइंट के लिए, postgres.<POOLER_TENANT_ID> उपयोगकर्ता और अपने POSTGRES_PASSWORD के साथ पोर्ट 5432 पर Supavisor के माध्यम से कनेक्ट करें। उस पोर्ट को इंटरनेट के लिए न खोलें। इसे VPN या SSH टनल के माध्यम से एक्सेस करें।

मेरे ऑथेंटिकेशन कन्फर्मेशन ईमेल localhost पर लिंक क्यों कर रहे थे?

.env में SITE_URL और API_EXTERNAL_URL को उनके डिफ़ॉल्ट मानों पर छोड़ दिया गया था। ऑथेंटिकेशन सेवा उन दो मानों से प्रत्येक कन्फर्मेशन और पासवर्ड रीसेट लिंक बनाती है, इसलिए यह वही पता भेजती है जो इसे भेजने के लिए कहा गया था। दोनों को अपने वास्तविक सार्वजनिक URL पर सेट करें और स्टैक को फिर से बनाएं।