Docker দিয়ে VPS-এ Supabase self-host করার গাইড
নিজের VPS-এ অফিসিয়াল Supabase Docker stack চালান: %%C9%%-এর demo secret বদলানো, প্রায় fourteenটি service, RAM প্রয়োজন, backup ও update পদ্ধতি জানুন।
আপনি যা তৈরি করছেন
Supabase self-hosting বলতে নিজের সার্ভারে অফিসিয়াল Docker Compose stack চালানো বোঝায়। এতে Postgres, এর সামনে থাকা একটি REST API, একটি auth service, file storage, realtime websockets এবং Studio dashboard থাকে। আপনি একটি repository clone করবেন, একটি .env file সম্পাদনা করবেন এবং প্রায় fourteenটি container চালু করবেন। এগুলো একসঙ্গে আপনার নিয়ন্ত্রণাধীন একটি Supabase project-এর মতো কাজ করবে।
ইনস্টলেশন সংক্ষিপ্ত। সমস্যার মূল কারণ সাধারণত .env file। এতে repository-তে প্রকাশিত demo secret থাকে। এই default দিয়ে চালু করা stack যে কেউ খুঁজে পেলে ব্যবহার করতে পারে। এই guide-এ কোন secret প্রতিস্থাপন করতে হবে, প্রতিটি service-এর কাজ কী, stack-এর প্রকৃত memory requirement কত এবং database মুছে না দিয়ে কীভাবে update করতে হবে—তা ব্যাখ্যা করা হয়েছে।
Compose আপনার জন্য নতুন হলে আগে VPS-এ Docker Compose-এর মৌলিক বিষয়গুলি পড়ুন। নিচের সব নির্দেশনা ধরে নিচ্ছে যে docker compose version ইতিমধ্যে একটি version দেখায়।
স্ট্যাকে আসলে কী থাকে
Supabase একটি মাত্র প্রোগ্রাম নয়। Compose ফাইল একই নেটওয়ার্কে একাধিক পৃথক সার্ভিস চালু করে। কোন সার্ভিসের কাজ কী তা জানলে অনেকগুলো container name-এর তালিকা বুঝে ডিবাগ করা সহজ হয়।
dbহলো Supabase extension লোড করা PostgreSQL। অন্য সব সার্ভিস এটির সঙ্গে যোগাযোগ করে। এই container অস্বাস্থ্যকর হলে অন্য সবকিছুও ব্যর্থ হবে।kongহলো API gateway। এটি port 8000-এ listening করে এবং/rest/v1/,/auth/v1/ও/storage/v1/-কে সঠিক backend-এ route করে। একমাত্র এই container-টিই আপনার কখনো বাইরে expose করা উচিত।restহলো PostgREST। এটি আপনার Postgres schema পড়ে সেটিকে REST API হিসেবে পরিবেশন করে। তাই কোনো code ছাড়াই নতুন table একটি নতুন endpoint হয়ে যায়।authহলো GoTrue। এটি আপনার user-দের পরিচয় শনাক্তকারী JSON web token (JWT) তৈরি করে।storageএবংimgproxyfile upload ও image resizing পরিচালনা করে।realtimewebsockets-এর মাধ্যমে database-এর পরিবর্তন stream করে।studioএবংmetadashboard এবং এর পেছনের admin API।analytics(Logflare) এবংvectorlog সংগ্রহ করে, আরsupavisorহলো Postgres connection pooler।
এই তালিকাই ব্যাখ্যা করে কেন নিচের resource-এর সংখ্যাগুলো এমন। আপনি শুধু একটি database চালাচ্ছেন না। আপনি একটি database-এর সঙ্গে এক ডজন support service চালাচ্ছেন।
মাপ নির্ধারণ: 8 GB RAM-এর পরিকল্পনা করুন
নিজস্ব ডেটা বা নেটওয়ার্ক ট্রাফিক যোগ করার আগে, July 2026 অনুযায়ী নতুন ইনস্টলে এই stack প্রায় 2.5 থেকে 3 GB resident memory ব্যবহার করে। Analytics service এবং Studio Node.js process হলো এককভাবে সবচেয়ে বেশি memory ব্যবহারকারী দুটি উপাদান। 2 GB-এর server container চালু করবে, কিন্তু পরে kernel-এর out of memory killer একটি container বন্ধ করে দেবে, সাধারণত analytics অথবা db। এর লক্ষণ হলো কোনো container exit code 137 দিয়ে বারবার restart হতে থাকা।
যে কাজের ওপর আপনি নির্ভর করেন, তার জন্য 8 GB RAM এবং 4 vCPU দিন। 4 GB RAM একক developer-এর development instance-এর জন্য যথেষ্ট, যদি একই সময়ে heavy query এবং Studio session ধীরগতির হওয়া মেনে নেন। Disk-এর ক্ষমতাও গুরুত্বপূর্ণ, কারণ Postgres, storage volume এবং log data—সবই project directory-এর অধীনে থাকে। 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 pulldocker compose pull কয়েক গিগাবাইটের ইমেজ ডাউনলোড করে। এটি প্রতিটি সার্ভিসকে Pulled হিসেবে চিহ্নিত করে শেষ হওয়া উচিত। এখানে manifest unknown ত্রুটি হলে বুঝতে হবে upstream থেকে নির্দিষ্ট image tag সরিয়ে ফেলা হয়েছে। সমাধান হলো tag হাতে সম্পাদনা না করে রিপোজিটরির নতুন কপি pull করা।
প্রথমবার চালু করার আগে যে গোপন মানগুলো পরিবর্তন করতে হবে
স্ট্যাক চালু করার আগে এটি করুন, পরে নয়। প্রথমবার চালুর সময় এই মানগুলোর কয়েকটি ডেটাতে লেখা হয়। তাই পরে এগুলো পরিবর্তন করতে হলে ডেটাবেস রিসেট করতে হবে।
রিপোজিটরিতে থাকা জেনারেটরটি প্রতিটি মান সঠিকভাবে তৈরি করে। এর মধ্যে আপনার নতুন JWT secret দিয়ে সাইন করা আবশ্যক দুটি API key-ও রয়েছে।
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 token-গুলোর নতুন মান .env-এ লেখে। এটির openssl প্রয়োজন, যা যেকোনো সাধারণ Ubuntu image-এ থাকে।
দুটি মান এটি সেট করে না। এগুলো আপনাকে .env-এ হাতে সম্পাদনা করতে হবে:
POSTGRES_PASSWORD। শুধু অক্ষর ও সংখ্যা ব্যবহার করুন। এখানে বিরামচিহ্ন ব্যবহার করলে একাধিক service string জোড়া দিয়ে যে connection string তৈরি করে, তা নষ্ট হয়। তখন parsing error-এর বদলে authentication error দেখা যায়। ফলে সমস্যা ভুল জায়গায় খোঁজা হয়।DASHBOARD_USERNAMEএবংDASHBOARD_PASSWORD। এগুলো Studio-এর basic authentication credential। সরবরাহ করা default password আক্ষরিকভাবেthis_password_is_insecure_and_should_be_updated।
কেন ANON_KEY এবং SERVICE_ROLE_KEY নিজের মতো করে তৈরি করা যায় না, তা বুঝুন। দুটিই JWT_SECRET দিয়ে সাইন করা JWT। Gateway প্রতিটি request-এ সেই signature যাচাই করে। তাই আপনার secret-এর সঙ্গে না মেলা key {"message":"Invalid authentication credentials"} দিয়ে প্রত্যাখ্যাত হয়। Self-hosting ব্যর্থ হওয়ার এটি সবচেয়ে সাধারণ কারণ: operator JWT_SECRET পরিবর্তন করেছেন, কিন্তু demo key রেখে দিয়েছেন। তিনটিই সবসময় একসঙ্গে তৈরি করুন।
SERVICE_ROLE_KEY-কে root password-এর মতো সুরক্ষিত রাখুন। এটি সম্পূর্ণভাবে row level security এড়িয়ে যায়। এটি শুধু server side code-এ থাকা উচিত, অন্য কোথাও নয়।
SITE_URL এবং API_EXTERNAL_URL-এ এমন address দিন যেখানে আপনার ব্যবহারকারীরা বাস্তবে পৌঁছাবেন, যেমন https://supabase.example.com। Auth এই মানগুলো থেকে email confirmation এবং OAuth callback link তৈরি করে। তাই এগুলো http://localhost:8000 রেখে দিলে আপনার প্রত্যেক ব্যবহারকারীকে তাদের নিজের machine-এ পাঠানো হবে।
এরপর আপনার সেটিংস পরীক্ষা করুন:
sh run.sh secretsএটি চালু করুন এবং সুস্থতা নিশ্চিত করুন
sh run.sh start
docker compose psrun.sh start, docker compose up -d --wait-কে মোড়ক হিসেবে ব্যবহার করে, তাই স্বাস্থ্য পরীক্ষা সফল না হওয়া পর্যন্ত এটি ফলাফল ফেরত দেয় না। প্রতিটি সার্ভিসে running (healthy) অথবা running দেখানো উচিত। প্রথমবার চালু হতে দুই থেকে চার মিনিট লাগে, কারণ অন্য কোনো কিছু সংযোগ করার আগে Postgres এর প্রাথমিকীকরণ স্ক্রিপ্ট চালায়।
কোনো container পুনরায় চালু হলে, সার্ভিসের নাম ব্যবহার করে এর লগ পড়ুন:
docker compose logs db
docker compose logs authএরপর Studio 8000 পোর্টে থাকবে এবং আপনি যে dashboard-এর username ও password সেট করেছেন, সেগুলো চাইবে।
port 8000 সর্বসাধারণের ইন্টারনেটে প্রকাশ করবেন না
port 8000-এ Kong সাধারণ HTTP ব্যবহার করে। প্রতিটি API key এবং প্রতিটি ব্যবহারকারীর password নেটওয়ার্কে সরল পাঠ্য হিসেবে যায়। Studio-এর credentials হলো basic authentication, যা encryption নয়, base64 encoding।
Kong-এর সামনে একটি reverse proxy রাখুন। সেখানে TLS (transport layer security) সমাপ্ত করুন। Kong-কে loopback address-এ bind করুন, যাতে অন্য কোনো কিছু এতে পৌঁছাতে না পারে। docker-compose.yml-এ kong port mapping হয়ে যায় 127.0.0.1:8000:8000, এবং proxy সেটিতে request forward করে। একাধিক Compose app-এর সামনে Traefik-এ certificate সম্পর্কিত বিষয়টি ব্যাখ্যা করা হয়েছে।
বাকি port-গুলোকেও firewall-এ বন্ধ করুন। Docker নিজস্ব iptables rules লিখে port প্রকাশ করে, যা সাধারণ ufw configuration দেখতে পায় না। এই সমস্যাটি Docker container কেন আপনার ufw rules উপেক্ষা করে-এ ব্যাখ্যা করা হয়েছে।
ডিরেক্টরি নয়, ডেটাবেসের ব্যাকআপ নিন
Postgres-এর ডেটা ./volumes/db/data-এ একটি bind mount-এ থাকে। Container চলার সময় ওই ডিরেক্টরি কপি করলে কপিটি অসামঞ্জস্যপূর্ণ হবে, কারণ Postgres write buffer করে এবং checkpoint-এর সময়ই ডিস্কের ফাইলগুলো সামঞ্জস্যপূর্ণ থাকে। এটি restore করলে সাধারণত কাজ করবে, তবে কখনও কখনও শেষের transaction-গুলো নিঃশব্দে হারিয়ে যাবে। ব্যাকআপের ক্ষেত্রে এটিই সবচেয়ে গুরুতর ব্যর্থতার ধরন।
পরিবর্তে 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 অবৈধ হয়ে যাবে এবং সংরক্ষিত প্রতিটি encrypted secret পড়া যাবে না।
আপলোড করা ফাইলগুলো ./volumes/storage-এ থাকে। এগুলো সাধারণ ফাইল, তাই সাধারণ কপি যথেষ্ট।
ডেটা না হারিয়ে আপডেট করুন
Supabase docker-compose.yml-এ image version নির্দিষ্ট করে রাখে, তাই আপনি আপডেট না করা পর্যন্ত কোনো পরিবর্তন হবে না। প্রতিবার আগে একটি dump নিন।
docker compose pull
sh run.sh recreaterecreate stack বন্ধ করে এবং নতুন image দিয়ে আবার চালু করে। আপনার ডেটা অক্ষত থাকে, কারণ এটি container-এর ভিতরে নয়, host-এর bind mount-এ থাকে। বড় version পরিবর্তনের আগে repository-র CHANGELOG.md পড়ুন, কারণ Postgres-এর major upgrade স্বয়ংক্রিয় নয় এবং dump ও restore প্রয়োজন।
Compose file-এ নিজস্ব পরিবর্তন গ্রহণ করতে upstream repository আবার clone করুন এবং এর docker directory আপনার project-এ কপি করুন। .env যেন overwrite না হয়, সেদিকে খেয়াল রাখুন।
সম্পূর্ণ reset করার জন্য আলাদা script আছে। এটি database-সহ সবকিছু মুছে দেয় এবং নিশ্চিতকরণ চায়:
sh reset.shFAQ
আমার API কলগুলোর ফলাফল "Invalid authentication credentials" কেন আসে?
আপনার ANON_KEY অথবা SERVICE_ROLE_KEY বর্তমানে .env-এ থাকা JWT_SECRET দিয়ে স্বাক্ষরিত হয়নি। Gateway প্রতিটি অনুরোধের স্বাক্ষর যাচাই করে এবং অমিল থাকলে অনুরোধ প্রত্যাখ্যান করে। sh utils/generate-keys.sh --update-env দিয়ে তিনটিই একসঙ্গে পুনরায় তৈরি করুন। এরপর sh run.sh recreate চালান, যাতে পরিষেবাগুলো নতুন মান পড়ে।
আমি কি 2 GB VPS-এ self-hosted Supabase চালাতে পারি?
নির্ভরযোগ্যভাবে নয়। July 2026 অনুযায়ী এই stack নিষ্ক্রিয় অবস্থাতেই প্রায় 3 GB মেমরি ব্যবহার করে, কারণ এতে প্রায় fourteenটি পরিষেবা চলে। তাই 2 GB সার্ভারে out of memory killer container বন্ধ করে দেয় এবং docker compose ps-এ exit code 137 দেখা যায়। Production-এর জন্য 8 GB ব্যবহার করুন। এককভাবে development-এর জন্য 4 GB-কে সর্বনিম্ন সীমা হিসেবে ধরুন।
self-hosted Supabase-এ কি edge functions অন্তর্ভুক্ত থাকে?
হ্যাঁ। Compose file-এ Deno ভিত্তিক functions runtime অন্তর্ভুক্ত থাকে। ./volumes/functions-এর অধীনে রাখা যেকোনো function এটি পরিবেশন করে। Hosted platform-এর global deployment network এতে অন্তর্ভুক্ত নয়। তাই আপনার functions একটি location-এ, আপনার একমাত্র server-এ চলে।
Postgres database-এ সরাসরি কীভাবে সংযোগ করব?
Server-এ নিজেই interactive shell চালাতে docker exec -it supabase-db psql -U postgres ব্যবহার করুন। External client-এর জন্য port 5432-এ Supavisor-এর মাধ্যমে postgres.<POOLER_TENANT_ID> user এবং আপনার POSTGRES_PASSWORD দিয়ে সংযোগ করুন। এই port-টি internet-এর জন্য উন্মুক্ত করবেন না। VPN অথবা SSH tunnel ব্যবহার করে এতে পৌঁছান।
আমার auth confirmation email-গুলোর link localhost-এ কেন গেছে?
.env-এ SITE_URL এবং API_EXTERNAL_URL ডিফল্ট মানে ছিল। Auth service প্রতিটি confirmation এবং password reset link এই দুটি মান থেকে তৈরি করে। তাই service-কে যে address দেওয়া হয়েছিল, সেটিই পাঠিয়েছে। দুটিই আপনার প্রকৃত public URL-এ সেট করুন এবং stack পুনরায় তৈরি করুন।