SSD Nodes Learn Hosting plans →
নির্দেশিকা Matt Connorদ্বারা Matt Connor · আপডেট করা হয়েছে 2026-08-27

Docker দিয়ে VPS-এ Supabase self-host করার নিয়ম

নিজের VPS-এ Supabase-এর official Docker Compose stack চালান। কোন demo secret বদলাবেন, 14টি 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-এ হয়। এই file-এ repository-তে প্রকাশিত demo secret থাকে। ওই default ব্যবহার করে চালু করা stack যে কেউ খুঁজে পেলে ব্যবহার করতে পারে। এই guide-এ কোন secret পরিবর্তন করতে হবে, প্রতিটি service-এর কাজ কী, stack-এর প্রকৃত memory requirement কত, এবং database মুছে না ফেলে কীভাবে update করতে হবে তা ব্যাখ্যা করা হয়েছে।

Compose আপনার কাছে নতুন হলে আগে VPS-এ Docker Compose-এর ভিত্তি পড়ুন। নিচের সব নির্দেশনায় ধরে নেওয়া হয়েছে যে docker compose version ইতিমধ্যে একটি version দেখায়।

স্ট্যাকে আসলে কী আছে

Supabase একটি মাত্র প্রোগ্রাম নয়। Compose file একটি network-এ একগুচ্ছ পৃথক service চালু করে। কোন service কী কাজ করে তা জানলে অনেক container name-এর তালিকাকে সহজে debug করা যায়।

  • db হলো Supabase extension লোড করা PostgreSQL। অন্য সব service এর সঙ্গে যোগাযোগ করে। এই container অস্বাস্থ্যকর হলে অন্য সবকিছু ব্যর্থ হবে।
  • kong হলো API gateway। এটি port 8000-এ listen করে এবং /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 এবং imgproxy file upload ও image resize পরিচালনা করে।
  • realtime websocket-এর মাধ্যমে database পরিবর্তন stream করে।
  • studio এবং meta হলো dashboard এবং এর পেছনে থাকা admin API।
  • analytics (Logflare) এবং vector log সংগ্রহ করে। supavisor হলো Postgres connection pooler।

নিচের resource সংখ্যাগুলো এমন হওয়ার কারণ এই তালিকাতেই রয়েছে। আপনি শুধু একটি database চালাচ্ছেন না। আপনি একটি database-এর সঙ্গে আরও এক ডজন support service চালাচ্ছেন।

আকার নির্ধারণ: 8 GB RAM-এর পরিকল্পনা করুন

2026 সালের July অনুযায়ী, fresh install-এর পরে এবং আপনার নিজস্ব data বা traffic যোগ হওয়ার আগে এই 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 নিন এবং disk usage monitor করুন। Plan বেছে নেওয়ার আগে service-গুলোর memory usage হিসাব করা self-host করা যেকোনো software-এর জন্য একটি কার্যকর অভ্যাস, কারণ PhotoPrism এবং Immich-এর প্রকৃত RAM requirement তাদের quick start page-এ বোঝানো পরিমাণের চেয়ে অনেক বেশি।

ইনস্টল করুন: অফিসিয়াল repository clone করুন

সমর্থিত পদ্ধতিতে প্রধান repository থেকে docker directory আপনার নিজের একটি project directory-তে কপি করা হয়। এই পৃথকীকরণ গুরুত্বপূর্ণ, কারণ এর ফলে পরবর্তী git pull আপনার .env overwrite করতে পারে না।

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 download করে। সব service Pulled হিসেবে চিহ্নিত হলে কমান্ডটি সম্পন্ন হয়েছে বলে ধরে নিন। এখানে manifest unknown error দেখালে বুঝতে হবে upstream থেকে নির্ধারিত image tag সরিয়ে ফেলা হয়েছে। tags হাতে edit না করে repository-এর নতুন copy pull করাই এর সমাধান।

প্রথমবার চালুর আগে যে secrets পরিবর্তন করতেই হবে

Stack চালু করার আগে এটি করুন, পরে নয়। প্রথম boot-এ এই মানগুলোর কয়েকটি data-তে লেখা হয়। তাই পরে এগুলো পরিবর্তন করতে হলে database reset করতে হয়।

Repository-তে এমন একটি generator আছে, যা দুটি API key-সহ সব মান সঠিকভাবে তৈরি করে। এই দুটি API key আপনার নতুন 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 token-এর নতুন মান .env-এ লিখে। এটি openssl ব্যবহার করে, যা যেকোনো সাধারণ Ubuntu image-এ থাকে।

দুটি মান এটি সেট করে না। .env-এ আপনাকে সেগুলো হাতে সম্পাদনা করতে হবে:

  • POSTGRES_PASSWORD। শুধু letters এবং digits ব্যবহার করুন। এখানে punctuation ব্যবহার করলে একাধিক 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 দিয়ে sign করা JWT। Gateway প্রতিটি request-এ সেই signature যাচাই করে। তাই আপনার secret-এর সঙ্গে না মেলা key {"message":"Invalid authentication credentials"} দিয়ে প্রত্যাখ্যাত হয়। Self-hosting-এ এটিই সবচেয়ে সাধারণ failure। Operator JWT_SECRET পরিবর্তন করেন, কিন্তু demo key রেখে দেন। তিনটিই সবসময় একসঙ্গে generate করুন।

SERVICE_ROLE_KEY-কে root password-এর মতো সুরক্ষিত রাখুন। এটি সম্পূর্ণ row level security bypass করে। এটি কেবল server-side code-এ থাকবে, অন্য কোথাও নয়।

SITE_URL এবং API_EXTERNAL_URL-এ users যে address-এ সত্যিই পৌঁছাবে, সেটি দিন; যেমন https://supabase.example.com। Auth এই মানগুলো থেকে email confirmation এবং OAuth callback link তৈরি করে। তাই এগুলো http://localhost:8000 রেখে দিলে আপনার সব user নিজের machine-এ পাঠিত হবে।

এরপর আপনার সেট করা মান পরীক্ষা করুন:

sh run.sh secrets

এটি চালু করুন এবং সুস্থ অবস্থায় আছে কি না নিশ্চিত করুন

sh run.sh start
docker compose ps

run.sh start, docker compose up -d --wait-কে wrap করে। তাই health check পাস না করা পর্যন্ত এটি return করে না। প্রতিটি service-এ running (healthy) অথবা running দেখা উচিত। প্রথম boot-এ দুই থেকে চার মিনিট সময় লাগে, কারণ অন্য কোনো কিছু connect করার আগে Postgres তার initialisation script চালায়।

কোনো container যদি বারবার restart হয়, service name দিয়ে তার log পড়ুন:

docker compose logs db
docker compose logs auth

Studio এখন port 8000-এ চালু থাকবে। আপনি যে dashboard username ও password সেট করেছেন, এটি সেগুলো চাইবে।

সর্বসাধারণের Internet-এ port 8000 প্রকাশ করবেন না

8000 port-এ Kong plain HTTP ব্যবহার করে। প্রতিটি API key এবং প্রতিটি user password network-এর মধ্য দিয়ে clear text হিসেবে যায়। Studio credentials হলো basic authentication, যা encryption নয়, base64 encoding।

এর সামনে একটি reverse proxy রাখুন এবং সেখানেই TLS (transport layer security) termination করুন। Kong-কে loopback address-এ bind করুন, যাতে অন্য কোনো service সেখানে পৌঁছাতে না পারে। docker-compose.yml-এ kong port mapping-এর পরিবর্তে 127.0.0.1:8000:8000 হবে, এবং proxy সেটিতে অনুরোধ পাঠাবে। Certificate ব্যবস্থাপনা সম্পর্কে বেশ কয়েকটি Compose app-এর সামনে Traefik অংশে আলোচনা করা হয়েছে। একই proxy এই server-এর অন্য সব service-এর সামনেও থাকবে—এই stack থেকে শুরু করে 90s-এর video store হিসেবে পুনর্নির্মিত একটি Jellyfin library-এর মতো সাধারণ service পর্যন্ত। প্রতিটি service-এর জন্য নতুন open port-এর বদলে একটি hostname ব্যবহার করা উচিত। কোনো dashboard যদি কেবল আপনি ব্যবহার করেন, proxy বাদ দিয়ে SSH tunnel-এর মাধ্যমে loopback port-এ পৌঁছান। self-hosted open-kritt-এও scanning interface-কে সম্পূর্ণ public Internet থেকে দূরে রাখতে একই পদ্ধতি ব্যবহার করা হয়েছে।

Firewall-এ বাকি port-গুলোও বন্ধ করুন। Docker নিজস্ব iptables rule লিখে port প্রকাশ করে, যা সাধারণ ufw configuration দেখতে পায় না। এই সমস্যাটি Docker container কেন আপনার ufw rule উপেক্ষা করে অংশে ব্যাখ্যা করা হয়েছে।

ডিরেক্টরি নয়, database-এর backup নিন

Postgres-এর data ./volumes/db/data-এর একটি bind mount-এ থাকে। Container চলার সময় ওই directory copy করলে অসম্পূর্ণ copy তৈরি হয়, কারণ Postgres write buffer করে এবং disk-এর file-গুলো শুধু checkpoint-এর সময় consistent থাকে। এটি restore করলে সাধারণত কাজ হবে, তবে কখনও কখনও শেষের transaction-গুলো নীরবে হারিয়ে যাবে। Backup-এর ক্ষেত্রে এটিই সবচেয়ে খারাপ ধরনের ব্যর্থতা।

এর পরিবর্তে dump নিন। pg_dumpall container-এর ভিতরে চলে এবং একটি consistent snapshot তৈরি করে:

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

ফাইলটি ব্যবহারযোগ্য ধরে নেওয়ার আগে পরীক্ষা করুন যে এটি empty নয়। এরপর নির্ধারিত সময়সূচি অনুযায়ী ওই dump-গুলো server-এর বাইরে পাঠান। restic দিয়ে encrypted offsite backup-এর কাজ এটাই। নির্ধারিত dump নীরবে ব্যর্থ হলে তার ফল backup না থাকার মতোই। তাই cron বা systemd job non-zero exit করলে সেটিকে আপনার phone-এ alert পাঠাতে বলুন। একই সময়ে আপনার .env-এরও backup নিন। JWT_SECRET হারালে জারি করা প্রতিটি token invalid হয়ে যাবে এবং সংরক্ষিত প্রতিটি encrypted secret পড়া যাবে না।

Uploaded file-গুলো ./volumes/storage-এ থাকে। এগুলো সাধারণ file, তাই সাধারণ copy যথেষ্ট।

ডেটা না হারিয়ে আপডেট

Supabase docker-compose.yml-এ image version নির্দিষ্ট করে রাখে। তাই আপনি পরিবর্তন না করা পর্যন্ত কোনো কিছু আপডেট হয় না। নিজে হাতে তৈরি করা যেকোনো stack-এ এই pinning পদ্ধতি অনুসরণ করা উপযোগী। এই কারণেই একটি self-hosted RustDesk relay পরিবর্তনশীল tag অনুসরণ না করে তার দুটি server image-এর version নির্দিষ্ট করে রাখে। Upgrade এমন সময় করা উচিত, যখন আপনি সেটির জন্য সময় দিতে পারবেন। প্রতিবার আগে dump নিন।

docker compose pull
sh run.sh recreate

recreate stack বন্ধ করে নতুন image দিয়ে আবার চালু করে। আপনার ডেটা অক্ষত থাকে, কারণ এটি container-এর ভেতরে নয়, host-এর bind mount-এ থাকে। Major version পরিবর্তনের আগে repository-র CHANGELOG.md পড়ুন, কারণ Postgres-এর major upgrade স্বয়ংক্রিয় নয় এবং এর জন্য dump ও restore প্রয়োজন।

Compose file-এ নিজস্ব পরিবর্তনগুলোও নিতে হলে upstream repository আবার clone করুন এবং সেটির docker directory আপনার project-এর ওপর copy করুন। তবে .env overwrite না করার বিষয়ে সতর্ক থাকুন।

সম্পূর্ণ reset আলাদা একটি script দিয়ে করা হয়। এতে database-সহ সবকিছু মুছে যায় এবং এটি confirmation চায়:

sh reset.sh

FAQ

আমার API call-এ "Invalid authentication credentials" কেন ফেরত আসে?

আপনার ANON_KEY অথবা SERVICE_ROLE_KEY বর্তমানে .env-এ থাকা JWT_SECRET দিয়ে sign করা হয়নি। Gateway প্রতিটি request-এর signature যাচাই করে এবং অমিল থাকলে request প্রত্যাখ্যান করে। sh utils/generate-keys.sh --update-env দিয়ে তিনটিই একসঙ্গে নতুন করে তৈরি করুন। এরপর sh run.sh recreate চালান, যাতে service-গুলো নতুন value পড়ে।

2 GB VPS-এ কি self-hosted Supabase চালানো যায়?

নির্ভরযোগ্যভাবে নয়। July 2026 অনুযায়ী stack idle অবস্থাতেই প্রায় 3 GB memory ব্যবহার করে, কারণ এতে প্রায় fourteenটি service চলে। তাই 2 GB server-এ out of memory killer container বন্ধ করে দেয় এবং docker compose ps-এ exit code 137 দেখা যায়। Production-এর জন্য 8 GB ব্যবহার করুন। একক developer-এর development environment-এর জন্য 4 GB-কে সর্বনিম্ন সীমা ধরুন।

self-hosted Supabase-এ কি edge function অন্তর্ভুক্ত থাকে?

হ্যাঁ। Compose file-এ Deno ভিত্তিক function runtime অন্তর্ভুক্ত থাকে। ./volumes/functions-এর অধীনে রাখা যেকোনো function এটি serve করে। তবে hosted platform-এর global deployment network এতে অন্তর্ভুক্ত নয়। তাই আপনার function একটি location-এ, আপনার একমাত্র server-এই চলে।

সরাসরি Postgres database-এ কীভাবে সংযোগ করব?

Server-এই interactive shell চালু করতে docker exec -it supabase-db psql -U postgres ব্যবহার করুন। External client-এর জন্য port 5432-এ Supavisor-এর মাধ্যমে সংযোগ করুন। User হিসেবে postgres.<POOLER_TENANT_ID> এবং আপনার POSTGRES_PASSWORD ব্যবহার করুন। এই port Internet-এ উন্মুক্ত করবেন না। VPN অথবা SSH tunnel ব্যবহার করে এতে সংযোগ করুন।

.env-এ SITE_URL এবং API_EXTERNAL_URL-এর default value পরিবর্তন করা হয়নি। Auth service এই দুই value থেকে প্রতিটি confirmation ও password reset link তৈরি করে। তাই configuration-এ যে address দেওয়া আছে, সেটিই পাঠায়। দুটিকেই আপনার প্রকৃত public URL-এ সেট করুন এবং stack পুনরায় তৈরি করুন।