SSD Nodes Learn Hosting plans →
تعلیمی Matt Connorتحریر: Matt Connor · اپ ڈیٹ شدہ 2026-08-29

OpenAnalytics کو اپنے VPS پر کیسے انسٹال کریں؟

OpenAnalytics کی تنصیب کے لیے 4 GB RAM اور 25 GB ڈسک درکار ہے۔ اس گائیڈ میں ClickHouse، Postgres اور Valkey کے ساتھ مکمل سیٹ اپ اور ضروری DNS کنفیگریشن کی تفصیلات موجود ہیں۔

پہلے مرحلے سے قبل، درکار وسائل

OpenAnalytics کو self-host کرنے کے لیے آپ کو 4 GB RAM، 25 GB خالی ڈسک، Docker بمعہ Compose پلگ ان، اور چار DNS ریکارڈز کے ساتھ ایک Linux VPS درکار ہے جو پہلے سے اس سرور کی طرف اشارہ کر رہے ہوں۔ یہ ایک دیانتدارانہ خلاصہ ہے، اور اسے پہلے کمانڈ سے پہلے ہونا چاہیے، نہ کہ بعد میں۔

یہ اسٹیک چھ ایپلیکیشن سروسز اور تین ڈیٹا اسٹورز پر مشتمل ہے۔ Postgres کنٹرول پلین کو سنبھالتا ہے: اکاؤنٹس، سائٹس، API کیز اور شیئر لنکس۔ ClickHouse خام ایونٹس اور وہ رول اپس (rollups) رکھتا ہے جنہیں ڈیش بورڈ پڑھتا ہے۔ Valkey دو بار چلتا ہے، ایک بار پائیدار ایونٹ کیو (durable event queue) کے طور پر اور دوسری بار کیشے کے طور پر جسے سسٹم کھو سکتا ہے، کیونکہ ان دونوں کاموں کے لیے متضاد eviction پالیسیوں کی ضرورت ہوتی ہے۔ صرف ایک عمل، یعنی query gateway، کو ClickHouse پڑھنے کی اجازت ہے، اور یہ ہر کوئری لفافے پر موجود Ed25519 دستخط کی تصدیق کرتا ہے اس سے پہلے کہ وہ اسے چلائے۔

اگر آپ ایک بائنری اور ایک کنفیگریشن فائل تلاش کر رہے تھے، تو یہ وہ نہیں ہے۔ GoatCounter اس زمرے میں سنگل بائنری آپشن ہے: ایک Go ایگزیکیوٹیبل، بائی ڈیفالٹ SQLite، اور کوئی بیرونی ڈیٹا بیس نہیں۔ یہ بھاری اسٹیک آپ کو فنلز (funnels)، ویب وائٹلز، اپنے Stripe اکاؤنٹ سے ریونیو ایٹری بیوشن، اور ایک MCP (ماڈل کانٹیکسٹ پروٹوکول) سرور فراہم کرتا ہے۔ Self-hosted اینالیٹکس ٹولز کے درمیان انتخاب وہ پوسٹ ہے جو اس موازنے کا جائزہ لیتی ہے۔ یہ گائیڈ فرض کرتی ہے کہ آپ پہلے ہی فیصلہ کر چکے ہیں۔

سب سے پہلے DNS ریکارڈز کو سرور کی طرف پوائنٹ کریں

کسی بھی کام کو شروع کرنے سے پہلے چاروں سب ڈومینز کا سرور کے public IP پر resolve ہونا ضروری ہے، کیونکہ Caddy پہلی بار چلنے پر Let's Encrypt سرٹیفکیٹس کی درخواست کرتا ہے اور اگر نام resolve نہ ہو رہا ہو تو یہ challenge ناکام ہو جاتا ہے۔

  • app.example.com ڈیش بورڈ کو سرو کرتا ہے۔
  • api.example.com API اور OAuth کال بیکس کو سرو کرتا ہے۔
  • c.example.com کلیکٹر اور ٹریکر اسکرپٹ کو سرو کرتا ہے۔
  • rt.example.com ریئل ٹائم اسٹریم کو سرو کرتا ہے۔

چار A ریکارڈز استعمال کریں، یا ایک A ریکارڈ اور تین CNAMEs جو اس کی طرف اشارہ کرتے ہوں۔ آگے بڑھنے سے پہلے dig +short app.example.com کے ساتھ تصدیق کریں۔ ایک منٹ پہلے شامل کیا گیا نام بھی کسی بھی resolver کی طرف سے NXDOMAIN کے طور پر کیش (cache) ہو سکتا ہے جسے Let's Encrypt استعمال کر رہا ہو، لہذا اگر سرٹیفکیٹ کی پہلی کوشش ناکام ہو جائے تو انتظار کرنا اور Caddy کے لاگز پڑھنا بہتر ہے۔ انسٹالیشن کو دوبارہ چلانے سے DNS کی propagation تیز نہیں ہوتی۔

Docker Compose کے ساتھ OpenAnalytics کو self-host کرنے کا طریقہ

ایک tagged release کو checkout کریں۔ default branch پر development ہوتی ہے، جبکہ release tag ان images سے مطابقت رکھتا ہے جو باقاعدہ شائع کی جاتی ہیں۔ نیچے دی گئی commands یہ فرض کرتی ہیں کہ Docker اور Compose plugin پہلے سے نصب ہیں، جس کا احاطہ VPS پر Docker Compose سروسز چلانے کے گائیڈ میں کیا گیا ہے۔

git clone https://github.com/OpenLabs-so/openanalytics
cd openanalytics
git checkout "$(git tag -l 'v*' --sort=-v:refname | sed '/-/d' | head -1)"
cd infra/selfhost
./generate-secrets.sh --domain example.com --email you@example.com --with-geoip
docker compose pull && docker compose up -d

checkout لائن میں موجود sed '/-/d' pre-release tags کو ہٹا دیتا ہے، تاکہ آپ release candidate کے بجائے تازہ ترین stable version پر پہنچ جائیں۔ --with-geoip generation کے دوران DB-IP city database کو fetch کرتا ہے۔ اگر آپ اسے چھوڑ دیں گے تو ہر event میں country null رہے گی، جس کی وجہ سے geography view میں کچھ بھی دکھائی نہیں دے گا۔ آپ اسے بعد میں infra/selfhost/geoip/fetch-dbip.sh چلا کر، env/collector.env میں GEOIP_DB_PATH=/geoip/dbip-city-lite.mmdb سیٹ کر کے، اور پھر docker compose up -d --force-recreate collector کے ساتھ collector کو دوبارہ بنا کر شامل کر سکتے ہیں۔ یہ database ماہانہ بنیادوں پر refresh ہوتا ہے، لہذا اسے ہر ماہ fetch کریں ورنہ آپ کا city data غیر درست ہو جائے گا۔

مزید آگے بڑھنے سے پہلے تیار کردہ secrets کا بیک اپ لیں

جنریٹر تین چیزیں لکھتا ہے۔ .env میں ڈومین کے نام اور امیج کے حوالے (references) موجود ہوتے ہیں۔ env/*.env میں ہر سروس کے لیے secrets کی ایک فائل ہوتی ہے۔ docker-compose.override.yml میں تین Ed25519 کی جوڑیاں YAML بلاک اسکیلرز کے طور پر موجود ہوتی ہیں، کیونکہ ایک ملٹی لائن PEM فائل env فائل میں نہیں رہ سکتی۔ یہ تمام فائلیں git-ignored ہیں، اور ان میں سے کسی کو بھی انہی قدروں (values) کے ساتھ دوبارہ تخلیق نہیں کیا جا سکتا۔

ان فائلوں کو ابھی مشین سے باہر کاپی کر لیں۔ ہر نقصان کی ایک مخصوص قیمت ہے:

  • اسٹور کے پاس ورڈز کھونے کی صورت میں آپ Postgres اور ClickHouse سے باہر ہو جائیں گے، جنہیں صرف کنٹینرز کے اندر سے ہی ری سیٹ کیا جا سکتا ہے۔
  • OA_CREDENTIAL_KEYRING کھونے پر ہر محفوظ شدہ تھرڈ پارٹی کریڈنشل ناقابلِ بازیابی ہو جاتا ہے، لہذا جس نے بھی Stripe اکاؤنٹ منسلک کیا تھا اسے دوبارہ منسلک کرنا پڑے گا۔
  • ANONYMOUS_IDENTITY_SECRET کھونے پر وزیٹر کی شناخت دوبارہ شروع (re-baseline) ہو جاتی ہے: کل کے تمام وزیٹرز نئے شمار ہوں گے، اور یہ وقفہ چارٹس میں واضح نظر آئے گا۔
  • AUTH_SECRET کھونے پر ہر سیشن منسوخ ہو جاتا ہے، لہذا ہر کسی کو دوبارہ سائن ان کرنا پڑے گا۔
  • سائننگ پرائیویٹ کی (signing private key) کھونے پر آپ جوڑی کو تبدیل (rotate) کر دیتے ہیں۔ کچھ بھی ضائع نہیں ہوتا۔

دو secrets کا دو فائلوں میں بائٹ کے اعتبار سے ایک جیسا ہونا ضروری ہے۔ ANONYMOUS_IDENTITY_SECRET، collector.env اور worker.env دونوں میں ظاہر ہوتا ہے، کیونکہ کلیکٹر وزیٹر ہیش کا حساب لگاتا ہے اور ورکر اسے لکھتا ہے۔ OA_CREDENTIAL_KEYRING، api.env اور worker.env میں ظاہر ہوتا ہے۔ باقی ہر چیز جان بوجھ کر صرف ایک سروس تک محدود رکھی گئی ہے، اور اگر کسی سروس کو ایسا secret دیا جائے جو اس کے پاس نہیں ہونا چاہیے تو وہ شروع ہونے کے بجائے بند ہو جاتی ہے۔

اسٹیک کو چلائیں اور اس کی جانچ کریں

grep OA_IMAGE .env
docker compose pull
docker compose up -d
docker compose logs -f migrate
docker compose ps

migrate، Postgres اور ClickHouse کے اسکیماز لاگو کرنے کے بعد بند ہو جاتا ہے، لہذا ایک رکا ہوا migrate کنٹینر درست اختتامی حالت ہے۔ tracker-build، oa.js کو ایک ایسے والیوم میں کمپائل کرتا ہے جسے Caddy پیش کرتا ہے اور پھر یہ بھی بند ہو جاتا ہے۔ باقی تمام سروسز کی حالت docker compose ps میں healthy ہونی چاہیے۔ اگر کوئی سروس بار بار ری اسٹارٹ ہو رہی ہے تو اس کا مطلب تقریباً ہمیشہ یہ ہوتا ہے کہ وہ انوائرمنٹ ویلیڈیشن میں ناکام ہو رہی ہے، اور لاگ ہر مسئلے کو ایک ہی فہرست میں پرنٹ کرتا ہے نہ کہ ہر ری اسٹارٹ پر ایک۔ اس کی دو عام وجوہات یہ ہیں: ایک ویری ایبل کا خالی رہ جانا، جسے unset سمجھنے کے بجائے مسترد کر دیا جاتا ہے، اور کسی سیکرٹ کا غلط سروس فائل میں رکھا جانا۔

arm64 پر، یا کسی برانچ سے، کوئی پبلش شدہ امیجز موجود نہیں ہوتیں اور آپ کو docker compose up -d --build کے ساتھ مقامی طور پر بلڈ کرنا پڑتا ہے۔ 4 GB ریم والا ہوسٹ اس بلڈ کے دوران میموری ختم ہونے کی وجہ سے رک سکتا ہے۔ پہلے swap شامل کریں، جس کی ضرورت صرف بلڈ کے دوران ہوتی ہے:

fallocate -l 4G /swapfile && chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab

بلڈنگ میں تقریباً دس منٹ لگتے ہیں۔ امیجز پل کرنے میں کچھ منٹ لگتے ہیں، اسی لیے ریلیز امیجز موجود ہیں۔

پہلے اکاؤنٹ کا فوری دعویٰ کریں

https://app.example.com کو کھولیں۔ ایسی deployment جس میں ابھی تک کسی نے لاگ ان نہیں کیا، وہاں سائن ان فارم نظر نہیں آتا: یہ پہلا اکاؤنٹ بنانے کی پیشکش کرتا ہے۔ یہ اکاؤنٹ مستقل طور پر مراعات یافتہ (privileged) ہوتا ہے، اور یہ واحد اکاؤنٹ ہے جو deployment settings کی اسکرین دیکھ سکتا ہے۔ ایک بار جب یہ بن جائے تو یہ روٹ 409 کا جواب دیتا ہے، تاکہ کوئی دوسرا شخص آپ کے بعد رسائی حاصل نہ کر سکے۔ یہ کام اسی وقت کریں جب stack مکمل طور پر فعال ہو جائے، نہ کہ اگلے ہفتے۔

Tracker کو انسٹال کریں

ڈیش بورڈ میں ایک سائٹ شامل کریں، یہ آپ کو ٹیگ فراہم کرے گا۔ اس کی شکل مقرر ہے:

<script
  async
  src="https://c.example.com/oa.js"
  data-key="YOUR_TRACKING_KEY"
  data-collector="https://c.example.com"
></script>

اسے صفحے کے head میں رکھیں۔ ٹریکنگ کی (tracking key) ڈیزائن کے لحاظ سے عوامی ہے، لہذا یہ آپ کے HTML میں وہاں ہونی چاہیے جہاں کوئی بھی اسے پڑھ سکے۔ اسکرپٹ window.oa کو انسٹال کرتا ہے، اور oa("track", ...) جیسی کالز کو ایک stub کے ذریعے قطار میں لگایا جاتا ہے اور فائل لوڈ ہوتے ہی انہیں flush کر دیا جاتا ہے، لہذا جلد فائر ہونے والا کوئی custom event ضائع نہیں ہوتا۔ اگر صفحے پر موجود کوئی اور چیز پہلے سے window.oa کی مالک ہے، تو ٹریکر اس کے بجائے window.openanalytics کے طور پر انسٹال ہوتا ہے۔ اگر وہی سائٹ onion service کے طور پر بھی جواب دیتی ہے، تو اس build میں ٹیگ شامل نہ کریں، کیونکہ c.example.com سے حاصل کردہ اسکرپٹ Tor Browser کے وزیٹر کو واپس clearnet پر لے آتا ہے اور ایک ہی صفحہ لوڈ ہونے کے دوران دونوں پتوں کو آپس میں جوڑ دیتا ہے۔

پھر پورے راستے (path) کو شروع سے آخر تک چیک کریں:

curl -s https://c.example.com/oa.js -o /dev/null -w '%{http_code} %{size_download}\n'
curl -s https://api.example.com/health | head -c 200
docker compose logs --tail=50 worker | grep -i batch

پہلی کمانڈ کو 200 اور چند کلو بائٹس پرنٹ کرنے چاہئیں۔ اپنی سائٹ پر ایک صفحہ لوڈ کریں، پھر چند سیکنڈ کے اندر ورکر لاگ میں batch لائن تلاش کریں۔ کلیکٹر (collector) ایونٹ قبول کرتے ہی 202 کا جواب دیتا ہے، اور 202 کا مطلب ہے کہ ایونٹ قطار میں ہے، محفوظ نہیں ہوا۔ ورکر ہی وہ چیز ہے جو ایونٹس کو ClickHouse میں منتقل کرتی ہے۔ اگر ایونٹس قبول ہو رہے ہیں لیکن ڈیش بورڈ میں کچھ ظاہر نہیں ہو رہا تو اس کا مطلب ہے کہ ورکر بلاک ہے، اور Valkey کی قطار کی گہرائی (queue depth) کا مسلسل بڑھنا اس کی تصدیق کرتا ہے۔ اس کی عام وجوہات worker.env میں غلط ClickHouse اسناد، یا حال ہی میں شامل کی گئی migration ٹیبل پر اجازت (grant) کا نہ ہونا ہیں۔

Collector کو عوامی رکھیں اور ڈیش بورڈ کو تصدیق (auth) کے پیچھے رکھیں

Caddy کمپوز فائل کے اندر موجود ہوتا ہے اور خود بخود چاروں ناموں کے لیے سرٹیفکیٹ حاصل کر لیتا ہے، لہذا ڈیفالٹ پاتھ کے لیے آپ کو کسی پراکسی ورک کی ضرورت نہیں ہے۔ اگر سرور پر پہلے سے ایک nginx ریورس پراکسی چل رہی ہے، تو اس کے بجائے فراہم کردہ infra/selfhost/nginx.conf.example کو اسٹیک کے سامنے رکھیں، اور اس کی ہیڈر ہینڈلنگ کو برقرار رکھیں:

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header CF-Connecting-IP "";
proxy_set_header True-Client-IP "";
proxy_set_header Fly-Client-IP "";

کلیکٹر روزانہ وزیٹر ہیش کلائنٹ کے IP سے اخذ کرتا ہے، لہذا اسے یہ ایڈریس کنکشن سے لینا چاہیے نہ کہ ہیڈر سے۔ کسی غیر معتبر ہاپ (hop) سے CF-Connecting-IP کو پاس کرنے سے کوئی بھی کالر کسی بھی ایڈریس کا دعویٰ کر سکتا ہے، جو جیو لوکیشن کو خراب کرتا ہے اور وزیٹر کی تعداد کو بلاوجہ بڑھا دیتا ہے۔

رسائی ہوسٹ نیم کے لحاظ سے واضح طور پر تقسیم ہوتی ہے۔ c. اور rt. کو ان تمام سائٹس کے ہر وزیٹر کے لیے قابل رسائی ہونا چاہیے جنہیں آپ ٹریک کر رہے ہیں، لہذا ان دونوں کے سامنے کبھی بھی basic auth یا IP allowlist نہ لگائیں۔ app. اور api. تک صرف ان لوگوں کی رسائی ہونی چاہیے جو سائن ان کرتے ہیں۔ ایپلیکیشن کی اپنی تصدیق (auth) ہی ڈیش بورڈ کی حفاظت کرتی ہے: پاس ورڈ سائن ان ڈیفالٹ طور پر env/api.env میں AUTH_PASSWORD_SIGNIN=enabled کے ذریعے فعال ہوتا ہے، اور Google یا GitHub کے بٹن تب ہی ظاہر ہوتے ہیں جب اس پرووائیڈر کے لیے کلائنٹ آئی ڈی اور کلائنٹ سیکرٹ دونوں موجود ہوں۔ میجک لنکس کے لیے میل ٹرانسپورٹ کی ضرورت ہوتی ہے، اور اس کے بغیر API صرف بھیجے گئے پیغام کو آؤٹ باکس میں لکھتا ہے، لہذا کچھ بھی ڈیلیور نہیں ہوتا اور کوئی ایرر بھی نہیں آتا۔ اگر آپ کی دیگر self-hosted ایپس پہلے سے ایک ہی Authentik لاگ ان کے پیچھے ہیں، تو جلد فیصلہ کریں کہ آیا یہ ڈیش بورڈ ان میں شامل ہوگا یا اپنے الگ اکاؤنٹس رکھے گا، کیونکہ یہاں جو پہلا اکاؤنٹ آپ بنائیں گے وہ مستقل طور پر مراعات یافتہ (privileged) ہوگا۔

ایک سیٹنگ یہ طے کرتی ہے کہ آیا ڈیش بورڈ کام کرے گا یا نہیں۔ env/api.env میں AUTH_TRUSTED_ORIGINS کا ڈیش بورڈ اوریجن سے بالکل مماثل ہونا ضروری ہے۔ غلط یا غائب ہونے کی صورت میں، API کوئی CORS (cross-origin resource sharing) ہیڈرز جاری نہیں کرتا، براؤزر ہر کال کو مسترد کر دیتا ہے، اور آپ کو ایک ایسا ڈیش بورڈ ملتا ہے جو لے آؤٹ تو دکھاتا ہے لیکن ڈیٹا نہیں، جبکہ docker compose ps سب کچھ ٹھیک ہونے کی رپورٹ دیتا ہے۔

جب آپ پراکسی کنفیگریشن میں ہوں، تو خودکار ٹریفک کو سنبھالیں۔ کرالرز کلیکٹر کو کسی بھی دوسری چیز کی طرح ہٹ کرتے ہیں، اور ان کے پیج ویوز ClickHouse اور آپ کے اعداد و شمار میں شامل ہو جاتے ہیں۔ AI کرالرز کو سرور پر بلاک کرنا اس ڈیٹا کا ایک حصہ ڈیٹا بیس میں جانے سے روکتا ہے، جس سے آپ کی درستگی برقرار رہتی ہے اور ڈسک کی جگہ بھی بچتی ہے۔

یہاں cookieless کا کیا مطلب ہے اور اس کی قیمت کیا ہے

یہاں کوئی cookie استعمال نہیں ہوتی۔ وزیٹر کی شناخت ایک salted hash ہے، یہ salt ہر دن تبدیل ہوتا ہے، اور raw IP addresses کو کبھی محفوظ نہیں کیا جاتا۔ Geolocation کو مقامی طور پر آپ کی اپنی ڈسک پر موجود DB-IP فائل کے ذریعے resolve کیا جاتا ہے، لہذا وزیٹر کے بارے میں کوئی بھی معلومات کبھی host سے باہر نہیں جاتیں۔ تلاش کو مقامی رکھنے سے وینڈر ختم ہوتا ہے، ڈیٹا نہیں، اور یہی وہ حد ہے جو تب سامنے آتی ہے جب آپ اپنی SearXNG instance چلاتے ہیں اور آپ کے سرور کا IP وہ چیز بن جاتا ہے جسے سرچ انجنز دیکھتے ہیں۔

اس کا فائدہ یہ ہے کہ وزیٹر کے آلے پر کوئی مستقل شناخت کنندہ (identifier) موجود نہیں ہوتا، جو کہ خاص طور پر وہ چیز ہے جو کسی ٹریکر کو EU ePrivacy کی رضامندی کے قوانین کے دائرہ کار میں لاتی ہے۔ اسی وجہ سے اس طرح کے صرف مجموعی (aggregate-only) سیٹ اپ عام طور پر بغیر کسی consent banner کے چلائے جاتے ہیں۔ GDPR اب بھی اس بات کا احاطہ کرتا ہے کہ آپ کیا محفوظ کرتے ہیں اور کتنی دیر کے لیے، اور آپ کے کیس کا فیصلہ آپ کے اپنے قانونی مشیر کرتے ہیں، نہ کہ کوئی README۔

اس کی قیمت یہ ہے کہ آپ دنوں کے درمیان شناخت برقرار نہیں رکھ سکتے۔ Salt کی تبدیلی کا مطلب ہے کہ جو شخص پیر کو وزٹ کرتا ہے اور پھر بدھ کو دوبارہ آتا ہے، اسے ڈیزائن کے مطابق دو الگ وزیٹر گنا جاتا ہے اور اس کا کوئی متبادل حل نہیں ہے۔ روزانہ کے unique counts درست ہوتے ہیں۔ ہفتہ وار اور ماہانہ unique counts روزانہ کے اعداد و شمار سے بنائے جاتے ہیں اور یہ رسائی کو بڑھا چڑھا کر پیش کریں گے، لہذا طویل مدتی "returning visitor" کا کوئی بھی عدد اس چیز کی پیمائش نہیں کر رہا جو اس کے لیبل پر لکھا ہے۔ Sessions اور journeys ایک ہی دن کے اندر قابل اعتماد ہیں۔ ANONYMOUS_IDENTITY_SECRET کو تبدیل کرنے کا اثر دن کی حد جیسا ہی ہوتا ہے، لہذا اس تبدیلی کو معمول کی صفائی کے بجائے ڈیٹا میں تبدیلی سمجھیں۔

یہ کلیکٹر Do Not Track اور Global Privacy Control کا احترام کرتا ہے، جو کہ براؤزر کا وہ سگنل ہے جو کسی سائٹ کو ذاتی ڈیٹا فروخت یا شیئر نہ کرنے کا کہتا ہے۔ اسکرپٹ ٹیگ میں اسی مقصد کے لیے اپنے سوئچز موجود ہیں: data-respect-gpc، data-respect-dnt، اور data-require-consent، جو رضامندی ملنے تک تمام کلیکشن کو روک کر رکھتا ہے اور جواب کو localStorage میں oa.consent کی کلید کے تحت یاد رکھتا ہے۔ data-storage="none" کو سیٹ کرنے سے براؤزر اسٹوریج مکمل طور پر بند ہو جاتی ہے۔

چھ ماہ بعد ڈسک کے بھر جانے کی وجہ

یہ وہ مسئلہ ہے جو self-hosted اینالیٹکس باکس کو ناکارہ بنا دیتا ہے، اور عام طور پر اس کی وجہ ایونٹس نہیں ہوتے۔

تصاویر (images) سے شروعات کریں۔ ایک release میں دس تصاویر جاری کی جاتی ہیں، اور یہ ڈسک پر تقریباً 13 GB جگہ لیتی ہیں۔ ایک اپ گریڈ پرانی جنریشن کو ہٹانے سے پہلے نئی جنریشن کو ڈاؤن لوڈ کرتا ہے، اس لیے کچھ وقت کے لیے آپ کے پاس دو جنریشنز موجود رہتی ہیں۔ ایک بھی پیج ویو آنے سے پہلے یہ 25 GB کی ضرورت کا بڑا حصہ ہے۔

پھر اسنیپ شاٹس (snapshots) کا معاملہ ہے۔ snapshot.sh اسٹیک کو روکتا ہے، دونوں ڈیٹا والیومز کو تمام سیکریٹس کے ساتھ آرکائیو کرتا ہے، اور پھر دوبارہ اسٹارٹ کرتا ہے۔ یہاں صرف cold copies ہی محفوظ طریقہ ہیں، کیونکہ ClickHouse پس منظر میں پارٹس کو ضم (merge) کرتا ہے اور مرجنگ کے دوران لی گئی کاپی مستقل (consistent) نہیں ہوتی۔ upgrade.sh ہر اپ گریڈ سے پہلے خود بخود ایک کاپی لے لیتا ہے، اس لیے جب تک آپ ان پر حد مقرر نہ کریں، آرکائیوز اسی ڈسک پر جمع ہوتے رہتے ہیں۔

./snapshot.sh create --label before-something-risky
./snapshot.sh list
./snapshot.sh --keep 3

حد کے قریب پہنچے ہوئے ہوسٹ پر، اپ گریڈ کرنے سے پہلے پچھلی جنریشن کو ہٹا دیں۔ یہ اسٹیک کے چلتے ہوئے بھی محفوظ ہے، کیونکہ چلنے والے کنٹینرز کے پیچھے موجود تصاویر کا حوالہ (reference) برقرار رہتا ہے:

docker image prune -a -f

پھر خود ایونٹس کی باری آتی ہے۔ ClickHouse کالم ڈیٹا کو بہت زیادہ کمپریس کرتا ہے، اس لیے خام ایونٹ کا حجم توقع سے کہیں زیادہ آہستہ بڑھتا ہے، اور ڈیش بورڈ جن rollup tables کو پڑھتا ہے وہ خام ٹیبل کے مقابلے میں چھوٹی ہوتی ہیں۔ اندازہ لگانے کے بجائے پیمائش کریں:

docker system df -v
docker compose exec clickhouse df -h /var/lib/clickhouse

فی ٹیبل حجم کے لیے، اسے ان ClickHouse اسناد کے ساتھ چلائیں جو جنریٹر نے infra/selfhost/env/ کے تحت لکھی تھیں:

SELECT table, formatReadableSize(sum(bytes_on_disk)) AS size, sum(rows) AS row_count
FROM system.parts
WHERE active
GROUP BY table
ORDER BY sum(bytes_on_disk) DESC;

پہلے ہفتے میں یہ ریڈنگ لیں اور پھر چوتھے ہفتے میں دوبارہ لیں۔ دو پوائنٹس آپ کو گروتھ ریٹ بتا دیں گے، اور گروتھ ریٹ سے معلوم ہو جائے گا کہ والیوم کو کب ری سائز کرنے کی ضرورت ہے۔ اگست 2026 تک، self-hosting گائیڈ میں خام ایونٹس کے لیے کوئی retention یا time-to-live کا آپشن موجود نہیں ہے، اس لیے پرانی قطاروں کے خود بخود ختم ہونے کا فرض کرنے کے بجائے اپنی پیمائش کردہ شرح کے مطابق ڈسک کا سائز رکھیں۔

ڈیلیشن (حذف کرنے) کا ایک ایسا جال ہے جس کے بارے میں جاننا ضروری ہے تاکہ آپ اس سے بچ سکیں۔ کسی سائٹ یا اکاؤنٹ کو ڈیلیٹ کرنے سے ورکر کے لیے کام کی قطار بن جاتی ہے، اور اس ورکر کو CLICKHOUSE_MAINTENANCE_USER اور CLICKHOUSE_MAINTENANCE_PASSWORD سیٹ کرنے کی ضرورت ہوتی ہے، جس کے ساتھ ClickHouse میں ایک مماثل oa_maintenance صارف کا ہونا ضروری ہے۔ ان کے بغیر، ڈیلیشن ہمیشہ کے لیے قطار میں رہتی ہے۔ سائٹ ڈیش بورڈ سے غائب ہو جاتی ہے لیکن ہر قطار ڈسک پر موجود رہتی ہے، اس لیے آپ کو صفائی کا تاثر تو ملتا ہے لیکن جگہ واپس نہیں ملتی۔

اپ گریڈز، اور تین اخراجات

git fetch --tags
git checkout "$(git tag -l 'v*' --sort=-v:refname | sed '/-/d' | head -1)"
cd infra/selfhost
./upgrade.sh

upgrade.sh عمل کرنے سے پہلے تین اخراجات ظاہر کرتا ہے۔ Downtime ایک حقیقت ہے: کلیکٹر کے بند ہونے کے دوران جو ایونٹس موصول ہوتے ہیں وہ ضائع ہو جاتے ہیں، کیونکہ ٹریکر انہیں دوبارہ بھیجنے (retry) کی کوشش نہیں کرتا۔ Rollback کرنے سے ڈیٹا کا نقصان ہوتا ہے، کیونکہ rollback.sh --to backups/<snapshot> دونوں اسٹورز کو مکمل طور پر تبدیل کر دیتا ہے اور اس اسنیپ شاٹ کے بعد لکھی گئی ہر قطار (row) کو ضائع کر دیتا ہے۔ ڈسک تیسرا خرچ ہے، جو کہ اوپر بیان کردہ اسنیپ شاٹ کا ڈھیر ہے۔

ری اسٹارٹ کے دو اصول ایسے ہیں جن میں غلطی کا امکان زیادہ ہوتا ہے۔ API سے پہلے query gateway کو آن کریں، کیونکہ نیا API ایسے query fields بھیجتا ہے جنہیں پرانا گیٹ وے مسترد کر دیتا ہے۔ اور ClickHouse کو ری اسٹارٹ کے بجائے دوبارہ تخلیق (recreate) کرنے کی ضرورت ہوتی ہے، کیونکہ docker compose restart کنٹینر کے اصل ماحول کو دوبارہ استعمال کرتا ہے اور آپ کی تبدیلیوں کو خاموشی سے نظر انداز کر دیتا ہے:

docker compose up -d --force-recreate clickhouse

ڈیش بورڈ میں بھی اسی قسم کا جال موجود ہے۔ env/web.env میں موجود تینوں NEXT_PUBLIC_* اوریجنز براؤزر بنڈل میں کمپائل ہوتے ہیں اور کنٹینر شروع ہونے پر تبدیل ہو جاتے ہیں، لہذا غلط ہوسٹ نیم پر کال کرنے والا ڈیش بورڈ docker compose up -d --force-recreate web سے ٹھیک ہوتا ہے، نہ کہ restart سے۔ ویب کنٹینر کا لاگ ان اوریجنز کو پرنٹ کرتا ہے جن کے ساتھ وہ شروع ہوا تھا، اور یہ تصدیق کرنے کا سب سے تیز طریقہ ہے کہ اصلاح لاگو ہو گئی ہے۔

اگر کنفیگریشن میں تبدیلی کے بعد ClickHouse شروع ہونے سے انکار کر دے، تو اس کے لاگ کی پہلی لائن پڑھیں۔ oa-entrypoint: سے شروع ہونے والی لائن کا مطلب ہے کہ انٹری پوائنٹ آپ کی سیٹ کردہ ویلیو کو مسترد کر رہا ہے۔ اس کے علاوہ کچھ بھی ہونے کا مطلب عام طور پر یہ ہے کہ کنفیگریشن فائل میں XML غلط ہے، اور اس کی سب سے عام وجہ XML کمنٹ کے اندر ڈبل ہائفن کا استعمال ہے، جو وہاں غیر قانونی ہے۔

AGPL-3.0، اور نام

یہ کوڈ AGPL-3.0 لائسنس کے تحت ہے۔ اپنی سائٹس کے لیے اسے بغیر کسی تبدیلی کے چلانے پر اشاعت (publishing) کی کوئی ذمہ داری عائد نہیں ہوتی۔ ذمہ داری تب شروع ہوتی ہے جب آپ کوڈ میں ترمیم کریں اور اس ترمیم شدہ ورژن کو نیٹ ورک سروس کے طور پر چلائیں: ایسی صورت میں لائسنس کا تقاضا ہے کہ آپ اپنے ترمیم شدہ سورس کوڈ کو اس سروس کے صارفین کے لیے پیش کریں۔ اس میں کلائنٹس کو آپ کے انسٹینس پر ڈیش بورڈز فراہم کرنا اور اسے کسی ایسی چیز میں شامل کرنا جسے آپ فروخت کرتے ہیں، دونوں شامل ہیں۔ اپنی تبدیلیوں کو ایک پبلک fork میں رکھنے سے یہ تقاضا بغیر کسی اضافی عمل کے پورا ہو جاتا ہے۔

برانڈ کوڈ سے الگ ہے۔ "OpenAnalytics" کا نام اور پروجیکٹ کا ہوسٹڈ ڈومین اس انسٹینس کی شناخت کرتے ہیں جسے اس کے مصنفین چلاتے ہیں، اور یہ لائسنس گرانٹ کا حصہ نہیں ہیں۔ آپ کی ڈیپلائمنٹ اس سافٹ ویئر کو برانڈ کے بغیر چلاتی ہے، لہذا ادائیگی کرنے والے صارفین کے سامنے لانے سے پہلے سروس کو اپنا ایک الگ نام دیں۔

FAQ

کیا میں 1 GB RAM والے VPS پر OpenAnalytics چلا سکتا ہوں؟

نہیں۔ یہ پروجیکٹ تقریباً 4 GB RAM اور 25 GB فری ڈسک کا تقاضا کرتا ہے، کیونکہ ایک ڈیپلائمنٹ میں Postgres، ClickHouse اور دو Valkey انسٹینسز کے ساتھ ساتھ چھ ایپلیکیشن سروسز چلتی ہیں۔ صرف ClickHouse ہی ایک چھوٹا پروسیس نہیں ہے۔ 1 GB والے باکس پر کنٹینرز شروع تو ہو جاتے ہیں لیکن کرنل کا out-of-memory killer ان میں سے کسی ایک کو، عام طور پر ClickHouse کو، بند کر دیتا ہے۔ اگر 1 GB کا پلان ہی حتمی حد ہے، تو GoatCounter جیسا سنگل بائنری ٹول استعمال کریں، جو بغیر کسی بیرونی ڈیٹا بیس کے SQLite پر چلتا ہے۔

کیا مجھے OpenAnalytics کے ساتھ کوکی بینر کی ضرورت ہے؟

یہ آپ کے وکیل سے پوچھنے کا سوال ہے، اور تکنیکی حقائق آپ کے حق میں ہیں۔ اس میں کوئی کوکی نہیں ہوتی، وزیٹر کی شناخت ایک salted hash ہوتی ہے جو روزانہ تبدیل ہوتی ہے، اور خام IP ایڈریسز کبھی سٹور نہیں کیے جاتے، لہذا وزیٹر کی شناخت کے لیے کوئی مستقل ڈیٹا نہیں لکھا جاتا۔ GDPR اب بھی اس بات کا تعین کرتا ہے کہ آپ کیا سٹور کرتے ہیں اور اسے کتنی دیر تک رکھتے ہیں۔ اگر آپ ڈیٹا اکٹھا کرنے کے لیے واضح اجازت (consent) چاہتے ہیں، تو اسکرپٹ ٹیگ پر data-require-consent سیٹ کریں: اس صورت میں ٹریکر تب تک کچھ جمع نہیں کرے گا جب تک اجازت نہ مل جائے اور وہ اس جواب کو oa.consent کے تحت localStorage میں محفوظ رکھے گا۔

ایونٹس 202 کیوں دیتے ہیں لیکن ڈیش بورڈ پر کبھی ظاہر نہیں ہوتے؟

202 کا مطلب ہے کہ کلیکٹر نے ایونٹ کو قبول کر کے قطار (queue) میں لگا دیا ہے، نہ کہ یہ کہ اس نے اسے سٹور کر لیا ہے۔ ورکر اس قطار سے ڈیٹا نکال کر ClickHouse میں ڈالتا ہے، لہذا کامیاب درخواستوں کے باوجود خالی ڈیش بورڈ کا مطلب ہے کہ مسئلہ ورکر میں ہے۔ docker compose logs --tail=50 worker پڑھیں اور Valkey کی قطار کی گہرائی (queue depth) دیکھیں۔ اگر قطار مسلسل بڑھ رہی ہے تو اس کا مطلب ہے کہ ورکر بلاک ہے، اور اس کی عام وجوہات worker.env میں غلط ClickHouse اسناد یا کسی حالیہ مائیگریشن کے بعد ٹیبل پر درکار اجازت (grant) کا نہ ہونا ہے۔

جب ہر کنٹینر ہیلتھی ہے تو ڈیش بورڈ خالی کیوں ہے؟

سب سے پہلے env/api.env میں AUTH_TRUSTED_ORIGINS کو چیک کریں۔ اسے ڈیش بورڈ کے اوریجن (origin) سے بالکل مطابقت رکھنی چاہیے، اور اگر ایسا نہ ہو تو API کوئی CORS ہیڈرز جاری نہیں کرتا، جس کی وجہ سے براؤزر ہر کال کو مسترد کر دیتا ہے اور آپ کو ڈیٹا کے بغیر ایک کام کرنے والا لے آؤٹ نظر آتا ہے۔ دوسری چیز جو چیک کرنی ہے وہ env/web.env میں موجود تین NEXT_PUBLIC_* ویلیوز ہیں، جو ویب کنٹینر شروع ہونے پر تبدیل (substitute) ہوتی ہیں۔ انہیں درست کرنے کے لیے docker compose up -d --force-recreate web کی ضرورت ہوتی ہے، کیونکہ سادہ ری سٹارٹ پرانی ویلیوز کو ہی برقرار رکھتا ہے۔

کیا AGPL-3.0 مجھے کلائنٹس کو یہ سروس پیش کرنے سے روکتی ہے؟

نہیں۔ یہ صرف ایک شرط عائد کرتی ہے۔ کوڈ کو بغیر ترمیم کے چلائیں تو آپ کسی کے مقروض نہیں ہیں۔ اگر آپ اس میں ترمیم کرتے ہیں اور اس ترمیم شدہ ورژن کو بطور سروس چلاتے ہیں جسے دوسرے لوگ استعمال کرتے ہیں، تو آپ کو ان صارفین کو اپنا ترمیم شدہ سورس کوڈ فراہم کرنا ہوگا، جسے ایک پبلک فورک (fork) کے ذریعے پورا کیا جا سکتا ہے۔ اس کے علاوہ، "OpenAnalytics" کا نام کوڈ کے ساتھ لائسنس یافتہ نہیں ہے، لہذا آپ جو کچھ بھی فروخت کریں اسے اپنا نام دینا ہوگا۔