Docker Compose দিয়ে openGym সেলফ-হোস্ট করার নিয়ম
Docker Compose ব্যবহার করে VPS-এ openGym ডিপ্লয় করার পূর্ণাঙ্গ গাইড। এখানে পিন করা git tag ব্যবহার, TLS কনফিগারেশন, JSON ডাটা লোকেশন এবং রিড-অনলি MCP সার্ভার সেটআপের খুঁটিনাটি দেখুন।
openGym সেলফ-হোস্ট করলে আপনি যা পাবেন
আপনি openGym-এর রিপোজিটরি ক্লোন করে, .env-এ দুটি লাইন এডিট করে এবং TLS (transport layer security) টার্মিনেট করে এমন একটি reverse proxy-এর পেছনে docker compose up -d --build চালিয়ে এটি সেলফ-হোস্ট করতে পারেন। openGym হলো একটি জিম এবং বডি ওয়েট ট্র্যাকার: এতে সাপ্তাহিক পরিকল্পনা, গাইডেড ওয়ার্কআউট, প্রতিটি সেটের লগ এবং সময়ের সাথে ওজনের পরিবর্তনের হিসাব রাখা যায়। এটি AGPL-3.0 লাইসেন্সভুক্ত এবং এটি সবকিছু আপনার ডিস্কে সাধারণ JSON ফাইলে সংরক্ষণ করে, তাই আলাদা কোনো ডাটাবেস সার্ভার চালানোর প্রয়োজন নেই।
এই স্ট্যাকটিতে দুটি দীর্ঘস্থায়ী কন্টেইনার রয়েছে: একটি nginx কন্টেইনার যা React বিল্ড সার্ভ করে এবং একটি Node কন্টেইনার যা API ধারণ করে। এছাড়া, প্রথমবার চালু করার সময় প্রায় 140 MB এক্সারসাইজ ইমেজ এবং GIF ডাউনলোড করার জন্য একটি one-shot জব রান করে।
পাবলিক সার্ভারে ডিপ্লয় করার ক্ষেত্রে প্রজেক্টের README-তে দুটি বিষয় ইঙ্গিত করা হয়েছে কিন্তু স্পষ্টভাবে বলা হয়নি। Passkey লগইন একটি হোস্টনামের সাথে আবদ্ধ, তাই প্রথম লগইনের আগেই ডোমেইন এবং এর সার্টিফিকেট তৈরি থাকতে হবে। এছাড়া, ঐচ্ছিক MCP সার্ভারটি রিড-অনলি এবং এটি সেই মেশিনে চলে যেখানে আপনার AI ক্লায়েন্ট চলে, স্ট্যাকের ভেতরে নয়। যখন ডাটা কোনো VPS-এ থাকে, তখন এটি আপনার কাজের ধরনে পরিবর্তন আনে।
openGym একটি নতুন প্রজেক্ট। প্রথম ট্যাগ করা রিলিজ, v1.0.0, 20 জুলাই 2026 তারিখে এসেছে এবং v1.2.7 এসেছে 18 আগস্ট 2026 তারিখে। প্রায় এক মাসে তেরোটি ট্যাগ আসার অর্থ হলো অ্যাপটি এখনো দ্রুত পরিবর্তিত হচ্ছে, তাই ডিফল্ট ব্রাঞ্চে যা আছে তা বিল্ড না করে একটি নির্দিষ্ট রিলিজ ট্যাগ চেক আউট করুন।
প্রথম লগইনের আগেই ডোমেইন পরিকল্পনা করুন
openGym-এ সাইন ইন করার জন্য Passkeys ব্যবহার করা হয়। একটি passkey একটি relying party ID (RP ID)-এর সাথে যুক্ত থাকে, যা হলো সেই ডোমেইন যেখানে credential-টি তৈরি করা হয়েছে। ব্রাউজার শুধুমাত্র HTTPS-এর মাধ্যমেই passkey তৈরি করে। এর একমাত্র ব্যতিক্রম হলো localhost।
এর একটি ফলাফল ব্যবহারকারীরা তাদের ফোনে দেখতে পান। অন্য কোনো ডিভাইস থেকে http://203.0.113.10:8080 খুললে কোনো passkey প্রম্পট দেখা যায় না, কারণ ব্রাউজার plain HTTP origin বা সরাসরি IP address-এ কোনো credential তৈরি করতে অস্বীকার করে। প্রজেক্টের নিজস্ব ট্রাবলশুটিং নোটেও একই কথা বলা হয়েছে: কোনো প্রম্পট না আসার অর্থ হলো আপনি http:// অথবা কোনো IP-তে আছেন।
আরও খারাপ বিষয় হলো, RP ID প্রতিটি credential-এর ভেতরেই গেঁথে থাকে যা আপনার ব্যবহারকারীরা ইতিমধ্যে রেজিস্টার করেছেন। পরবর্তীতে RP_ID পরিবর্তন করলে তাদের ডিভাইসে সংরক্ষিত passkey-গুলো আর মিলবে না, ফলে কেউ সাইন ইন করতে পারবে না। তাই সবার আগে hostname নির্ধারণ করুন, DNS-কে VPS-এর দিকে পয়েন্ট করুন এবং কেউ Create profile-এ ট্যাপ করার আগেই certificate-এর কাজ সম্পন্ন করুন।
Docker Compose দিয়ে openGym ডেপ্লয় করা
এই compose ফাইলটি ./data এবং ./media-কে এর নিজস্ব অবস্থানের সাপেক্ষে bind-mount করে, তাই আপনি যে ডিরেক্টরিতে ক্লোন করবেন সেটিই আপনার ডেটাবেস হিসেবে কাজ করবে। এটিকে এমন কোনো জায়গায় রাখুন যা দীর্ঘস্থায়ী।
sudo install -d -o "$USER" -g "$USER" /opt/opengym
git clone https://gitea.com/DuarteSantos/openGym /opt/opengym
cd /opt/opengym
cp .env.example .envREADME ফাইলে এখনো একটি github.com ক্লোন URL দেওয়া আছে। সেই ঠিকানাটি এখন আর কাজ করে না, এবং উপরের Gitea রিপোজিটরিই হলো এই প্রজেক্টের বর্তমান ঠিকানা।
.env ফাইলটি এডিট করুন। একটি VPS-এর ক্ষেত্রে তিনটি লাইন গুরুত্বপূর্ণ।
RP_ID=gym.example.com
ORIGIN=https://gym.example.com
WEB_PORT=127.0.0.1:8080RP_ID হলো মূল হোস্টনাম এবং ORIGIN হলো স্কিমসহ সম্পূর্ণ URL। এগুলোকে ব্রাউজারের অ্যাড্রেস বারের সাথে হুবহু মিলতে হবে, অন্যথায় লগইন করার সময় verification failed এরর আসবে। WEB_PORT ভ্যালুটি পোর্ট 8080 প্রাইভেট রাখার সেকশনে ব্যাখ্যা করা হয়েছে।
docker compose up -d --build
docker compose ps
docker compose logs mediadocker compose ps কমান্ডটি চালালে web এবং api কে running অবস্থায় এবং media কে 0 কোডসহ exited অবস্থায় দেখানো উচিত। এই exit হওয়াটি সঠিক: media জবটি restart: "no" সম্পন্ন করেছে কারণ এর কাজ ছিল একবারই ডাউনলোড করা। এর লগের শেষ লাইনে ✓ Exercise media ready দিয়ে শুরু হওয়া একটি লাইন থাকবে এবং ls media/img | wc -l কমান্ডটি 0 এর পরিবর্তে কয়েকশ ফাইল দেখাবে। ডিরেক্টরি খালি থাকার অর্থ হলো ডাউনলোড ব্যর্থ হয়েছে, যার ফলে অ্যাপটি এক্সারসাইজ কার্ডগুলো খালি ছবিসহ প্রদর্শন করবে।
এখানে --build ফ্ল্যাগটি ঐচ্ছিক নয়। compose ফাইলে ghcr.io-এ থাকা প্রি-বিল্ট ইমেজগুলোর নাম উল্লেখ করা আছে যা এখন আর পাবলিশ করা হয় না, তাই docker compose pull কমান্ডটি চালালে denied বা manifest unknown এরর আসবে। এর পরিবর্তে, আপনি যে সোর্স কোডটি ক্লোন করেছেন তা থেকেই সার্ভিস দুটি বিল্ড করা হয়। উভয় সার্ভিসেই এর জন্য একটি build সেকশন রয়েছে। আপনি যদি Compose-এর ব্যবহারে নতুন হন, তবে প্রথমে Docker Compose on a VPS পড়ে এখানে ফিরে আসুন।
ভার্সন পিন করুন, কারণ এই প্রজেক্টটি নতুন
যেহেতু সেই রেজিস্ট্রি নেমস্পেসটি আর নেই, তাই পিন করার মতো কোনো ইমেজ ট্যাগ অবশিষ্ট নেই। এর পরিবর্তে আপনি ডিস্কে থাকা চেকআউটটি পিন করুন, কারণ এটিই নির্ধারণ করে যে অ্যাপ্লিকেশনের কোন ভার্সনটি কন্টেইনারে থাকবে।
cd /opt/opengym
git fetch --tags
git checkout v1.2.7git status এখন সেই ট্যাগে একটি detached HEAD রিপোর্ট করে, সার্ভারে আপনার ঠিক এটাই প্রয়োজন। আপনি অন্য কোনো ট্যাগ চেকআউট না করা পর্যন্ত কোনো কিছুই পরিবর্তিত হবে না।
এরপর Compose-কে নির্দেশ দিন যেন এটি আর রেজিস্ট্রির সাথে যোগাযোগ না করে। এটি docker-compose.override.yml ফাইলে রাখুন, যা Compose স্বয়ংক্রিয়ভাবে লোড করে এবং ট্র্যাক করা ফাইলের সাথে মার্জ করে। স্কেলার কি (scalar keys) ওভাররাইড দ্বারা প্রতিস্থাপিত হয়, তাই git-এ কোনো কিছু এডিট করার প্রয়োজন হয় না এবং git pull ক্লিন থাকে। মার্জ করার সম্পূর্ণ নিয়ম জানতে Compose কীভাবে একটি ওভাররাইড ফাইল মার্জ করে দেখুন।
services:
api:
pull_policy: build
web:
pull_policy: buildএটি কার্যকর করার পর, পরবর্তী docker compose up -d কমান্ডটি পুল করার সময় ব্যর্থ না হয়ে আপনার কাছে থাকা সোর্স থেকে বিল্ড হবে। মার্জটি কার্যকর হয়েছে কি না তা যাচাই করুন, তারপর সেই ট্যাগে পুনরায় বিল্ড করুন।
docker compose config | grep pull_policy
docker compose up -d --buildএকটি reverse proxy ব্যবহার করে TLS termination
কন্টেইনারগুলো plain HTTP-তে কাজ করে। তাই সামনে এমন কিছু থাকতে হবে যা certificate-টি ধারণ করবে। Caddy হলো সবচেয়ে সহজ সমাধান, কারণ এটি নিজে থেকেই Let's Encrypt থেকে certificate অনুরোধ এবং নবায়ন করতে পারে।
gym.example.com {
reverse_proxy 127.0.0.1:8080
}nginx, Traefik এবং Nginx Proxy Manager—সবগুলোই একইভাবে কাজ করে। Cloudflare Tunnel-ও একই কাজ করে, যা এই প্রজেক্টের ডকুমেন্টেশনে উল্লেখ আছে এবং এর জন্য কোনো inbound port খোলার প্রয়োজন হয় না।
curl -sI https://gym.example.com | head -1এটি কোনো certificate warning ছাড়াই HTTP/2 200 প্রদান করবে। এখন ব্রাউজারে সাইটটি খুলুন এবং Create profile-এ ট্যাপ করুন। যদি passkey প্রম্পট আসে এবং লগইন করার সময় verification failed, RP_ID অথবা ORIGIN দেখায়, তবে বুঝবেন এটি address bar-এর URL-এর সাথে মিলছে না। .env ঠিক করুন এবং পুনরায় docker compose up -d চালান, যা কন্টেইনারগুলোকে নতুন মানসহ পুনরায় তৈরি করবে। একটি docker compose restart কমান্ড .env-কে রিলোড করে না।
পোর্ট 8080-কে পাবলিক ইন্টারনেট থেকে দূরে রাখুন
ডিফল্টভাবে ওয়েব সার্ভিস প্রতিটি ইন্টারফেসে 8080 প্রকাশ করে, তাই প্রক্সি একই বক্সে HTTPS পরিবেশন করলেও অ্যাপটি আপনার পাবলিক IP-তে সাধারণ HTTP-এর মাধ্যমে অ্যাক্সেসযোগ্য থাকে। একটি ফায়ারওয়াল রুল দিয়ে এটি সমাধান করা যায় না। Docker একটি DNAT রুলের মাধ্যমে nat টেবিলে পোর্ট প্রকাশ করে এবং সেই ট্রাফিক তখন FORWARD চেইনে হ্যান্ডেল করা হয়, যেখানে Docker-এর নিজস্ব রুলগুলো তা গ্রহণ করে, অথচ ufw-এর রুলগুলো INPUT পাথে অবস্থান করে। তাই sudo ufw deny 8080/tcp কোনো কিছুই ব্লক করতে পারে না।
এর সমাধান হলো শুধুমাত্র লুপব্যাক অ্যাড্রেসে পোর্ট প্রকাশ করা। কম্পোজ ফাইলটি "${WEB_PORT:-8080}:${NGINX_PORT:-80}" ম্যাপ করে, তাই আপনি WEB_PORT-এ যা সেট করবেন তা সেই ম্যাপিংয়ের বাম দিকে প্রতিস্থাপিত হবে এবং Docker-এর সংক্ষিপ্ত সিনট্যাক্স সেখানে একটি ip:port জোড়া গ্রহণ করে। এই কারণেই WEB_PORT=127.0.0.1:8080 কাজ করে।
docker compose config
sudo ss -ltnp | grep 8080মার্জ করা কনফিগারেশনে, ওয়েব সার্ভিসের ports-এর অধীনে আপনি host_ip: 127.0.0.1 দেখতে পাবেন। ss-এ 127.0.0.1:8080 দেখানো উচিত, 0.0.0.0:8080 নয়। অন্য কোনো মেশিন থেকে, curl http://<your-vps-ip>:8080 এখন রিফিউজ বা টাইম আউট হওয়া উচিত, তবে HTTPS হোস্টনাম কাজ করতে থাকবে।
আপনার প্রোফাইল তৈরি হওয়ার পর সাইনআপ বন্ধ করুন
ডিফল্টভাবে সাইনআপ খোলা থাকে এবং গেস্ট মোড চালু থাকে। একটি পাবলিক হোস্টনামে এর অর্থ হলো, যে কেউ URL খুঁজে পেলে আপনার সার্ভারে একটি প্রোফাইল তৈরি করতে পারবে। প্রথমে আপনার নিজের প্রোফাইলটি রেজিস্টার করুন, তারপর আপনার ইউজার আইডি খুঁজে বের করুন: ls data/ প্রতিটি ইউজারের জন্য state-<uid>.json নামে একটি ফাইল তালিকাভুক্ত করে এবং সেই <uid> হলো আপনার প্রয়োজনীয় মান।
ADMIN_UIDS=<your-uid>
INVITE_ONLY=1
ALLOW_GUEST=0আবার docker compose up -d চালান। সেটিংস-এ এখন একটি অ্যাডমিন ড্যাশবোর্ড দেখা যাবে, যেখানে আপনি ইনভাইট কোড তৈরি এবং বাতিল করতে পারবেন। ফলে আপনি যাদের সাথে প্রশিক্ষণ নিচ্ছেন কেবল তারাই রেজিস্টার করতে পারবে এবং অন্য কেউ পারবে না। openGym বাইরের কোনো আইডেন্টিটি প্রোভাইডার সম্পর্কে জানে না, তাই এই ইনভাইট কোডগুলো কেবল এই অ্যাপটির জন্যই কাজ করবে, সার্ভারের অন্য কোনো কিছুর জন্য নয়। আপনি যদি আপনার সার্ভারের সব অ্যাপের জন্য প্রতি ব্যক্তির বিপরীতে একটি মাত্র অ্যাকাউন্ট রাখতে চান, তবে Authentik-কে ফরওয়ার্ড অথ প্রক্সি হিসেবে সামনে বসিয়ে openGym-এর নিজস্ব পাসকি লগইন লোড হওয়ার আগেই হোস্টনামটিকে সুরক্ষিত করতে পারেন।
ডেটা যেখানে থাকে এবং যে ব্যাকআপ তা সুরক্ষিত রাখে
সবকিছু ./data ডিরেক্টরিতে থাকে, যা API কন্টেইনারের /data পাথে মাউন্ট করা। এখানে চার ধরনের ফাইল আছে: db.json-এ প্রোফাইল এবং পাবলিক পাসকি ক্রেডেনশিয়াল থাকে, state-<uid>.json-এ একজন ব্যবহারকারীর রুটিন, ওয়ার্কআউট এবং শরীরের ওজনের তথ্য থাকে, secret হলো সেশন কুকি কি (key), এবং vapid.json-এ প্রথমবার রান করার সময় তৈরি হওয়া পুশ নোটিফিকেশন কিগুলো থাকে।
cd /opt/opengym
docker compose stop api
tar czf ~/opengym-$(date +%F).tar.gz data/
docker compose start apiপ্রথমে API বন্ধ করুন, কারণ tar ফাইল কপি করার সময় API কোনো ফাইলে লিখতে পারে, আর অর্ধেক কপি হওয়া JSON ফাইল রিস্টোর করলে তা নষ্ট হয়ে যায়। বন্ধ এবং চালু করতে প্রায় দুই সেকেন্ড সময় লাগে। এরপর আর্কাইভটি সার্ভার থেকে কপি করে সরিয়ে নিন, কারণ VPS-এ রাখা আর্কাইভ VPS নষ্ট হয়ে গেলে আর পাওয়া যাবে না। ব্যাকআপ থেকে media/ বাদ দিন: এটি 140 MB এক্সারসাইজ ইমেজ, যা মিডিয়া জব পুনরায় বিনামূল্যে ডাউনলোড করে নিতে পারে।
রিস্টোর করার অর্থ হলো একই ডোমেইন সার্ভ করা কোনো হোস্টে একই পাথে ফাইলগুলো untar করা। আপনার ফোনে সংরক্ষিত একটি পাসকি যে RP ID-তে তৈরি হয়েছিল, তার সাথেই যুক্ত থাকে। তাই নতুন কোনো হোস্টনামে রিস্টোর করলে আপনি এমন একটি কার্যকর ডেটাবেস পাবেন যেখানে কেউ লগইন করতে পারবে না। ডোমেইনটি একই রাখুন, অথবা প্রতিটি পাসকি পুনরায় রেজিস্টার করার পরিকল্পনা রাখুন। একই নিয়ম আপনার চালানো অন্যান্য সবকিছুর ক্ষেত্রেও প্রযোজ্য, এবং Docker Compose স্ট্যাক ব্যাকআপ এবং আপগ্রেড করা অংশে সাধারণ নিয়মগুলো আলোচনা করা হয়েছে।
MCP সার্ভারটি রিড-অনলি এবং এটি আপনার মেশিনে চলে
MCP (model context protocol) হলো এমন একটি মাধ্যম যার সাহায্যে Claude Desktop বা Cursor-এর মতো ক্লায়েন্ট একটি লোকাল টুল সার্ভারের সাথে যোগাযোগ করে। openGym একটি টুল সার্ভার mcp/-এ সরবরাহ করে। এটি compose ফাইলের অংশ নয়, এটি কোনো কন্টেইনার নয় এবং এটি কোনো পোর্টে লিসেন করে না। ক্লায়েন্ট এটিকে একটি চাইল্ড প্রসেস হিসেবে চালু করে এবং stdio-এর মাধ্যমে যোগাযোগ করে, যে কারণে README-তে বলা হয়েছে এটি কখনোই আপনার মেশিন ছেড়ে বাইরে যায় না।
সার্ভারে নয়, বরং যেখানে ক্লায়েন্ট চলে সেখানে এটি ইনস্টল করুন:
cd openGym/mcp
npm installএরপর এটিকে claude_desktop_config.json-এ যোগ করুন:
{
"mcpServers": {
"opengym": {
"command": "node",
"args": ["/absolute/path/to/openGym/mcp/src/index.js"],
"env": {
"OPENGYM_DATA": "/absolute/path/to/openGym/data",
"OPENGYM_UID": "<your-uid>"
}
}
}
}সিঙ্গেল-ইউজার ইনস্টলেশনের ক্ষেত্রে OPENGYM_UID ঐচ্ছিক, যেখানে সার্ভার স্বয়ংক্রিয়ভাবে একমাত্র প্রোফাইলটি শনাক্ত করে নেয়। এটি আটটি টুল এক্সপোজ করে: list_routines, get_routine, get_week_plan, list_workouts, get_workout, get_bodyweight, estimate_1rm এবং muscle_balance। এগুলোর প্রতিটিই কেবল ডেটা রিড করে। এগুলোর কোনোটিই রাইট করতে পারে না, তাই একজন অ্যাসিস্ট্যান্ট গত সপ্তাহে আপনি কী বেঞ্চ করেছেন তা জানাতে পারলেও কোনো সেট লগ করতে, রুটিন এডিট করতে বা কিছু ডিলিট করতে পারে না। এই তালিকাটি এজেন্ট ডিজাইনের সেই মূল সিদ্ধান্তের একটি সংক্ষিপ্ত উদাহরণ, যা হলো—আপনি যে টুলগুলো এক্সপোজ করবেন, মডেল কেবল সেটুকুই করতে পারবে। আর নিজে লুপ লিখে এজেন্ট কীভাবে কাজ করে তা শেখা হলো এটি বোঝার দ্রুততম উপায় যে, কেন রিড-অনলি টুল সেট একটি সীমাবদ্ধতা নয় বরং একটি ডিজাইন চয়েস।
VPS ব্যবহারকারীদের জন্য এখানে একটি সমাধান প্রয়োজন। OPENGYM_DATA হলো একটি ফাইলসিস্টেম পাথ, এবং আপনার ডেটা থাকে VPS-এ, অথচ আপনার AI ক্লায়েন্ট থাকে ল্যাপটপে। এই সমস্যার দুটি সৎ সমাধান নিচে দেওয়া হলো:
- ডেটা কপি করে লোকাল মেশিনে নিয়ে আসুন এবং সার্ভারকে সেই কপির দিকে নির্দেশ করুন:
rsync -a --delete user@gym.example.com:/opt/opengym/data/ ~/opengym-data/, এরপরOPENGYM_DATA-কে~/opengym-dataহিসেবে সেট করুন। সার্ভার যেহেতু কেবল রিড করে, তাই কপি করলে কোনো তথ্য হারায় না। নতুন ডেটা পেতে চাইলে rsync আবার চালান। - ssh-এর মাধ্যমে সার্ভারটি চালান, যেখানে
command-কেsshএবংargs-কে["-T", "user@gym.example.com", "OPENGYM_DATA=/opt/opengym/data node /opt/opengym/mcp/src/index.js"]হিসেবে সেট করতে হবে। এর জন্য VPS-এ Node ইনস্টল থাকা প্রয়োজন এবং এমন একটি লগইন প্রয়োজন যা stdout-এ কিছু প্রিন্ট করে না, কারণ stdout হলো প্রোটোকল চ্যানেল।
উভয় বিকল্পেই agent আপনার laptop-এ চলে বলে ধরে নেওয়া হয়েছে। তবে agent-টি যদি data থাকা একই box-এ চালাতে চান, OneCLI server-এ প্রত্যেক ব্যক্তির জন্য একটি sandboxed agent দেয়, ফলে data/-এ stdio hop-টি আবার local থাকে।
যদি cat data/db.json কমান্ডটি Permission denied রিটার্ন করে, তবে বুঝতে হবে API কন্টেইনার ফাইলগুলো root হিসেবে রাইট করেছে এবং আপনার লগইন ইউজার সেগুলো রিড করতে পারছে না। sudo ব্যবহার করে ফাইলগুলো কপি করুন অথবা হোস্ট মেশিনে ফাইলগুলোর মালিকানা পরিবর্তন করুন। যে সার্ভারগুলো stdio-এর পরিবর্তে নেটওয়ার্কের মাধ্যমে লিসেন করার জন্য তৈরি, তাদের ক্ষেত্রে VPS-এ MCP সার্ভার চালানো দেখুন।
openGym নাকি wger: কোনটি আপনার চালানো উচিত?
এই ক্ষেত্রে wger একটি প্রতিষ্ঠিত বিকল্প এবং এটি অনেক বড় একটি সফটওয়্যার। এর compose stack-এ nginx-এর পেছনে gunicorn দ্বারা পরিচালিত একটি Django অ্যাপ্লিকেশন, PostgreSQL, Redis এবং একটি Celery worker থাকে। এর বিনিময়ে আপনি পুষ্টি ও উপাদানের ট্র্যাকিং, একটি ডকুমেন্টড REST API, ব্যায়ামের একটি বিশাল কমিউনিটি ডেটাবেস এবং অন্যদের পরিকল্পনা পরিচালনার জন্য ট্রেইনারদের উপযোগী ফিচার পাবেন।
openGym হলো দুটি কন্টেইনার এবং JSON ফাইলের একটি ফোল্ডার, যেখানে passkeys ছাড়া আর কোনো অ্যাকাউন্ট পরিচালনার প্রয়োজন নেই। মূল পার্থক্য এখানেই। আপনি যদি কখনো Chatwoot ইনস্টলেশন চালু রেখে থাকেন, যেখানে ব্যাকআপ মানে হলো Postgres ডাম্প এবং আপলোড ডিরেক্টরি সংরক্ষণ করা এবং প্রতিটি ভার্সন আপডেটে ডেটাবেস মাইগ্রেশন চালানো, তবে আপনি জানেন যে wger রক্ষণাবেক্ষণের জন্য কী ধরনের প্রস্তুতির প্রয়োজন।
আপনি যদি প্রশিক্ষণের পাশাপাশি খাবারের হিসাব রাখতে চান অথবা কোনো অ্যাপ তৈরির জন্য API-এর প্রয়োজন হয়, তবে wger ব্যবহার করুন। আর যদি এমন একটি ছোট স্ট্যাক চান যা এক বিকেলে পুরোপুরি পড়ে বোঝা সম্ভব এবং পাসওয়ার্ডহীন লগইন সুবিধা চান, তবে openGym বেছে নিন। এই পছন্দের মূল্য হলো পরিপক্কতা: 19 আগস্ট 2026 অনুযায়ী openGym-এর প্রথম রিলিজটি মাত্র এক মাস পুরনো, অন্যদিকে wger-এর পেছনে রয়েছে বহু বছরের রিলিজের ইতিহাস। আপনার ভার্সন পিন করে রাখুন, ব্যাকআপ রাখুন এবং প্রতিটি আপডেটের আগে রিলিজ নোটগুলো পড়ুন।
আপনার সার্ভারে কোনটি রাখা উচিত তা নিয়ে যদি এখনো সিদ্ধান্ত নিতে না পারেন, তবে 2026 সালে কোনগুলো সেলফ-হোস্ট করা সার্থক নিবন্ধটি পড়ুন। এই অ্যাপটি একই ছোট VPS-এ রেসিপির জন্য Mealie বা অর্থের হিসাবের জন্য Actual Budget-এর পাশাপাশি অনায়াসেই চলতে পারে।
কোনো কিছু না হারিয়ে আপডেট করা
cd /opt/opengym
docker compose stop api
tar czf ~/opengym-$(date +%F).tar.gz data/
docker compose start api
git fetch --tagsgit checkout v<new> ব্যবহার করে আপনার কাঙ্ক্ষিত release-টি চেক আউট করুন, তারপর docker compose up -d --build কমান্ডটি চালান যাতে সেই tag থেকে কন্টেইনারগুলো পুনরায় তৈরি (rebuild) হয়। প্রতিবারই আগে ব্যাকআপ নিন, কারণ ডিস্কে থাকা JSON ফাইলগুলো রিস্টোর করার প্রক্রিয়াটি মাত্র একটি tar কমান্ডের বিষয় এবং এতে কয়েক সেকেন্ড সময় লাগে।
FAQ
কেন আমার ফোনে openGym কখনোই passkey প্রম্পট দেখায় না?
ব্রাউজারটি credential তৈরি করতে অস্বীকার করছে কারণ আপনি http:// অথবা http://192.168.1.20:8080-এর মতো কোনো bare IP ঠিকানায় আছেন। ব্রাউজার শুধুমাত্র HTTPS অরিজিনে passkey ব্যবহারের অনুমতি দেয়, যেখানে localhost হলো একমাত্র ব্যতিক্রম। openGym-কে একটি আসল hostname-এর জন্য আসল certificate থাকা reverse proxy-এর পেছনে রাখুন, .env ফাইলে RP_ID=gym.example.com এবং ORIGIN=https://gym.example.com সেট করুন, এবং docker compose up -d চালান যাতে কন্টেইনারগুলো নতুন মানগুলো গ্রহণ করতে পারে। যদি প্রম্পট আসে কিন্তু লগইন করার সময় verification failed ত্রুটি দেখায়, তবে বুঝতে হবে এই দুটি মান ব্রাউজারের address bar-এ থাকা URL-এর সাথে হুবহু মিলছে না।
openGym আমার ডেটা কোথায় জমা রাখে এবং আমি কীভাবে এর ব্যাকআপ নেব?
এটি compose ফাইলের পাশে থাকা ./data ডিরেক্টরিতে থাকে, যা API কন্টেইনারে /data হিসেবে মাউন্ট করা হয়। এতে প্রোফাইল এবং পাবলিক passkey credential-এর জন্য db.json, ওয়ার্কআউট ও শরীরের ওজনের জন্য প্রতি ব্যবহারকারীর একটি করে state-<uid>.json, সেশন কুকি কী-এর জন্য secret এবং পুশ নোটিফিকেশন কী-এর জন্য vapid.json থাকে। docker compose stop api, তারপর tar czf ~/opengym-$(date +%F).tar.gz data/ এবং সবশেষে docker compose start api ব্যবহার করে এর ব্যাকআপ নিন এবং আর্কাইভটি সার্ভার থেকে কপি করে অন্য কোথাও রাখুন। media/ বাদ দিন, কারণ এটি 140 মেগাবাইটের এক্সারসাইজ ইমেজ যা মিডিয়া জব নিজেই আবার ডাউনলোড করে নিতে পারে।
Claude কি আমার openGym ওয়ার্কআউট হিস্ট্রি পড়তে পারে?
হ্যাঁ, mcp/ ডিরেক্টরিতে থাকা ঐচ্ছিক MCP সার্ভারের মাধ্যমে এটি সম্ভব, তবে শুধুমাত্র পড়ার জন্য। এটি রুটিন, সাপ্তাহিক পরিকল্পনা, লগ করা ওয়ার্কআউট, শরীরের ওজন, আনুমানিক one-rep max এবং মাসল ব্যালেন্স সম্পর্কিত আটটি টুল উন্মুক্ত করে, যার কোনোটিই ডেটা পরিবর্তন করতে পারে না। এটি কোনো কন্টেইনার নয় এবং কোনো পোর্ট খোলে না: আপনার ক্লায়েন্ট এটিকে stdio-এর মাধ্যমে শুরু করে এবং এটি সরাসরি OPENGYM_DATA-এ থাকা JSON ফাইলগুলো পড়ে। যেহেতু এটি একটি ফাইলসিস্টেম পাথ, তাই VPS-এ openGym চালানোর অর্থ হলো হয় ক্লায়েন্ট মেশিনে data/-এর একটি কপি সিঙ্ক করা, অথবা ক্লায়েন্ট কনফিগারেশন থেকে ssh-এর মাধ্যমে সার্ভারটি চালু করা।
আমার কি openGym নাকি wger সেলফ-হোস্ট করা উচিত?
আপনি যদি আপনার ট্রেনিং লগের পাশাপাশি খাবার ও পুষ্টির হিসাব রাখতে চান অথবা কোনো ডকুমেন্টেশনসহ REST API-এর ওপর ভিত্তি করে কাজ করতে চান, তবে wger বেছে নিন। এটি একটি বড় স্ট্যাক চালায়: nginx-এর পেছনে gunicorn-এর অধীনে Django, PostgreSQL, Redis এবং একটি Celery worker। আপনি যদি মাত্র দুটি কন্টেইনার, cat দিয়ে পড়া যায় এমন JSON ফাইল এবং পাসওয়ার্ডবিহীন passkey লগইন চান, তবে openGym বেছে নিন। 19 আগস্ট 2026 অনুযায়ী, openGym-এর প্রথম tagged release মাত্র এক মাস পুরনো, তাই আপডেট করার আগে অবশ্যই git tag চেক করুন এবং data/-এর ব্যাকআপ নিন।