SSD Nodes Learn 🎉 VPS $5.50/ماہ سے
تعلیمی Matt Connorتحریر: Matt Connor

OpenAnalytics کو VPS پر self-host کرنے کا طریقہ

OpenAnalytics کے لیے 4 GB RAM، 25 GB خالی جگہ، Docker Compose اور 4 DNS records درکار ہیں۔ ClickHouse، Postgres اور Valkey کا مکمل setup اور disk استعمال دیکھیں۔

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

OpenAnalytics کو self-host کرنے کے لیے آپ کو تقریباً 4 GB RAM، 25 GB خالی disk space، Compose plugin کے ساتھ Docker، اور پہلے سے اس سرور کی طرف اشارہ کرنے والے چار DNS records والا Linux VPS درکار ہے۔ یہی اصل ضروریات ہیں، اور انہیں پہلے command سے پہلے بیان کیا جانا چاہیے، بعد میں نہیں۔

اس stack میں چھ application services اور تین data stores شامل ہیں۔ Postgres control plane کا data محفوظ کرتا ہے، جس میں accounts، sites، API keys اور share links شامل ہیں۔ ClickHouse خام events اور وہ rollups محفوظ کرتا ہے جنہیں dashboard پڑھتا ہے۔ Valkey دو مرتبہ چلتا ہے: ایک بار durable event queue کے طور پر اور دوسری بار ایسے cache کے طور پر جسے ضائع ہونے پر نظام برداشت کر سکتا ہے، کیونکہ ان دونوں کاموں کے لیے eviction policies ایک دوسرے کے برعکس درکار ہیں۔ صرف ایک process، query gateway، کو ClickHouse پڑھنے کی اجازت ہے، اور یہ ہر query envelope پر موجود Ed25519 signature کی تصدیق کرنے کے بعد ہی اسے چلاتا ہے۔

اگر آپ کو ایک binary اور ایک config file درکار تھی تو یہ وہ حل نہیں ہے۔ اس category میں GoatCounter single-binary option ہے: ایک Go executable، default طور پر SQLite، اور کسی external database کی بالکل ضرورت نہیں۔ یہ زیادہ بھاری stack funnels، web vitals، آپ کے اپنے Stripe account سے revenue attribution، اور MCP (model context protocol) server فراہم کرتا ہے۔ self-hosted analytics tools کے درمیان انتخاب وہ post ہے جس میں اس trade-off کا جائزہ لیا گیا ہے۔ یہ guide فرض کرتی ہے کہ آپ پہلے ہی فیصلہ کر چکے ہیں۔

پہلے چار DNS records کو box کی طرف point کریں

کسی بھی کام کو شروع کرنے سے پہلے چار subdomains کا server کے public IP پر resolve ہونا ضروری ہے، کیونکہ Caddy پہلی بار شروع ہوتے وقت Let's Encrypt certificates کی درخواست کرتا ہے اور جو name ابھی resolve نہ ہو رہا ہو، اس پر challenge ناکام ہو جاتا ہے۔

  • app.example.com dashboard فراہم کرتا ہے۔
  • api.example.com API اور OAuth callbacks فراہم کرتا ہے۔
  • c.example.com collector اور tracker script فراہم کرتا ہے۔
  • rt.example.com realtime stream فراہم کرتا ہے۔

چار A records استعمال کریں، یا ایک A record اور اس کی طرف point کرنے والے تین CNAMEs استعمال کریں۔ آگے بڑھنے سے پہلے dig +short app.example.com کے ذریعے تصدیق کریں۔ جو name آپ نے ایک منٹ پہلے شامل کیا ہے، وہ اب بھی اس resolver کے پاس NXDOMAIN کے طور پر cached ہو سکتا ہے جسے Let's Encrypt استعمال کرے۔ اس لیے certificate کی پہلی ناکام کوشش پر کچھ دیر انتظار کریں اور Caddy logs پڑھیں۔ Install دوبارہ چلانے سے DNS تیزی سے propagate نہیں ہوتا۔

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

Tagged release چیک آؤٹ کریں۔ Default branch پر development ہوتی ہے، جبکہ release tag اس published image کے عین مطابق ہوتا ہے۔ نیچے دیے گئے commands یہ فرض کرتے ہیں کہ Docker اور Compose plugin پہلے ہی installed ہیں، جس کا احاطہ VPS پر Docker Compose services چلانا میں کیا گیا ہے۔

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 line میں موجود 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 set کر کے، اور docker compose up -d --force-recreate collector کے ساتھ collector دوبارہ create کر کے شامل کر سکتے ہیں۔ یہ database ہر ماہ refresh ہوتا ہے، اس لیے fetch ہر ماہ دوبارہ کریں، ورنہ city data میں بتدریج فرق آتا رہے گا۔

آگے بڑھنے سے پہلے generated secrets کا backup لیں

Generator تین چیزیں لکھتا ہے۔ .env میں domain names اور image references شامل ہوتے ہیں۔ env/*.env میں ہر service کے لیے secrets کی ایک file شامل ہوتی ہے۔ docker-compose.override.yml میں Ed25519 key pairs بطور YAML block scalars شامل ہوتے ہیں، کیونکہ multi-line PEM کو env file میں محفوظ نہیں کیا جا سکتا۔ ان تمام files کو git-ignore کیا گیا ہے، اور ان میں سے کسی کو بھی انہی values کے ساتھ دوبارہ generate نہیں کیا جا سکتا۔

اب ان files کو machine سے باہر copy کریں۔ ہر file ضائع ہونے کی مخصوص قیمت ہے:

  • Store passwords ضائع ہونے پر آپ Postgres اور ClickHouse سے lock out ہو جائیں گے۔ انہیں صرف containers کے اندر سے reset کیا جا سکتا ہے۔
  • OA_CREDENTIAL_KEYRING ضائع ہونے پر محفوظ شدہ ہر third-party credential ناقابل بازیافت ہو جائے گا۔ اس لیے جس شخص نے Stripe account connect کیا ہے، اسے دوبارہ connect کرنا ہوگا۔
  • ANONYMOUS_IDENTITY_SECRET ضائع ہونے پر visitor identity دوبارہ baseline سے شروع ہوگی۔ کل کے تمام visitors نئے شمار ہوں گے، اور یہ تبدیلی charts میں نمایاں ہوگی۔
  • AUTH_SECRET ضائع ہونے پر ہر session invalid ہو جائے گا، اس لیے سب کو دوبارہ sign in کرنا ہوگا۔
  • Signing private key ضائع ہونے پر key pair rotate کریں۔ کوئی data ضائع نہیں ہوگا۔

دو secrets کو دو، دو files میں byte-identical ہونا ضروری ہے۔ ANONYMOUS_IDENTITY_SECRET، collector.env اور worker.env میں موجود ہے، کیونکہ collector visitor hash compute کرتا ہے اور worker اسے لکھتا ہے۔ OA_CREDENTIAL_KEYRING، api.env اور worker.env میں موجود ہے۔ باقی ہر secret جان بوجھ کر صرف ایک service تک محدود ہے، اور جس service کو ایسا secret دیا جائے جو اسے نہیں رکھنا چاہیے، وہ start ہونے کے بجائے exit ہو جاتی ہے۔

Stack شروع کریں اور اس کی جانچ کریں

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

migrate Postgres اور ClickHouse schemas لاگو کرنے کے بعد بند ہو جاتا ہے، اس لیے stopped migrate container آخری درست حالت ہے۔ tracker-build، oa.js کو ایک volume میں compile کرتا ہے جسے Caddy serve کرتا ہے، اور یہ بھی بند ہو جاتا ہے۔ باقی تمام services کو docker compose ps میں healthy پڑھنا چاہیے۔ اگر کوئی service مسلسل restart loop میں ہو تو تقریباً ہمیشہ environment validation ناکام ہو رہی ہوتی ہے۔ Log ہر restart کے لیے الگ الگ دکھانے کے بجائے تمام مسائل ایک ہی فہرست میں دکھاتا ہے۔ عام طور پر دو وجوہات ہوتی ہیں: کوئی variable خالی رہ جاتا ہے، جسے unset سمجھنے کے بجائے reject کر دیا جاتا ہے، یا کوئی secret غلط service file میں رکھا جاتا ہے۔

arm64 پر، یا کسی branch سے کام کرتے وقت، published images دستیاب نہیں ہوتیں، اس لیے docker compose up -d --build کے ذریعے images مقامی طور پر build کریں۔ 4 GB host اس build کے دوران memory ختم کر دیتا ہے۔ پہلے swap شامل کریں۔ اس کی ضرورت صرف build کے دوران ہوتی ہے:

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

Build مکمل ہونے میں تقریباً دس منٹ لگتے ہیں۔ Pulling میں چند منٹ لگتے ہیں، اسی لیے release images دستیاب ہیں۔

پہلا اکاؤنٹ فوراً بنائیں

https://app.example.com کھولیں۔ ایسی deployment جس میں ابھی تک کسی نے sign in نہ کیا ہو، sign-in form نہیں دکھاتی؛ اس کے بجائے پہلا account بنانے کا اختیار دیتی ہے۔ یہ account مستقل طور پر privileged account ہوتا ہے، اور deployment settings screen صرف اسی account کو دکھائی دیتی ہے۔ account بن جانے کے بعد یہ route 409 کا جواب دیتا ہے، اس لیے کوئی شخص آپ کے بعد داخل نہیں ہو سکتا۔ یہ کام stack کے healthy ہوتے ہی کریں، اگلے ہفتے تک مؤخر نہ کریں۔

tracker انسٹال کریں

dashboard میں ایک site شامل کریں، پھر یہ آپ کو tag دے گا۔ اس کی ساخت مقرر ہے:

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

اسے page head میں رکھیں۔ tracking key ڈیزائن کے لحاظ سے public ہے، اس لیے اسے اپنے HTML میں رکھیں جہاں ہر شخص اسے پڑھ سکتا ہے۔ script window.oa انسٹال کرتی ہے، اور oa("track", ...) جیسی calls کو ایک stub queue میں رکھتا ہے اور file load ہونے کے بعد انہیں flush کر دیتا ہے، اس لیے پہلے trigger کیا گیا custom event ضائع نہیں ہوتا۔ اگر page پر کوئی دوسری چیز پہلے ہی window.oa استعمال کر رہی ہو تو tracker اس کے بجائے window.openanalytics انسٹال کرتا ہے۔

اب پورے path کو end to end چیک کریں:

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

پہلی command کو 200 اور چند kilobytes دکھانے چاہییں۔ اپنی site پر کوئی page load کریں، پھر چند seconds کے اندر worker log میں batch line تلاش کریں۔ collector event قبول کرتے ہی 202 واپس کرتا ہے، اور 202 کا مطلب queued ہے، stored نہیں۔ Events کو ClickHouse میں منتقل کرنے کا کام worker کرتا ہے۔ Events قبول ہو رہے ہوں لیکن dashboard میں کچھ نظر نہ آئے تو worker blocked ہے، اور Valkey queue depth کا مسلسل بڑھنا اس کی تصدیق کرتا ہے۔ عام وجوہات worker.env میں ClickHouse کے غلط credentials، یا ایسی table پر missing grant ہیں جسے کسی migration نے ابھی شامل کیا ہے۔

Collector کو public رکھیں اور dashboard کو auth کے پیچھے رکھیں

Caddy compose file کے اندر شامل ہے اور چاروں names کے لیے خود certificates حاصل کرتا ہے، اس لیے default path میں آپ کو proxy کی کوئی configuration کرنے کی ضرورت نہیں۔ اگر اس box پر پہلے ہی nginx reverse proxy چل رہا ہو تو فراہم کردہ infra/selfhost/nginx.conf.example کے ذریعے stack کو اس کے پیچھے رکھیں، اور اس کی header handling برقرار رکھیں:

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 "";

Collector روزانہ visitor hash، client IP سے اخذ کرتا ہے۔ اس لیے اسے یہ address connection سے لینا چاہیے، header سے کبھی نہیں۔ کسی غیر معتبر hop سے CF-Connecting-IP کو آگے بھیجنے کی اجازت دینے سے ہر caller کسی بھی address کا دعویٰ کر سکتا ہے۔ اس سے geolocation کا data خراب ہوتا ہے اور visitor counts بیک وقت بڑھ جاتے ہیں۔

Access کو hostname کے لحاظ سے واضح طور پر تقسیم کریں۔ c. اور rt. ہر اس site کے ہر visitor کے لیے reachable ہونے چاہییں جسے آپ measure کرتے ہیں۔ اس لیے ان دونوں کے سامنے basic auth یا IP allowlist نہ لگائیں۔ app. اور api. صرف sign in کرنے والے لوگوں کے لیے reachable ہونے چاہییں۔ Dashboard کی حفاظت application کی اپنی auth کرتی ہے۔ AUTH_PASSWORD_SIGNIN=enabled کے ذریعے env/api.env میں password sign-in default طور پر enabled ہوتا ہے۔ Google یا GitHub کے buttons صرف اس وقت ظاہر ہوتے ہیں جب متعلقہ provider کے لیے client ID اور client secret دونوں موجود ہوں۔ Magic links کے لیے mail transport درکار ہوتا ہے۔ اس کے بغیر API صرف send کو outbox میں لکھتی ہے، اس لیے نہ message deliver ہوتا ہے اور نہ کوئی error ظاہر ہوتا ہے۔

ایک setting طے کرتی ہے کہ dashboard بالکل کام کرے گا یا نہیں۔ env/api.env میں AUTH_TRUSTED_ORIGINS کو dashboard origin سے عین match کرنا چاہیے۔ اگر value غلط یا missing ہو تو API کوئی CORS (cross-origin resource sharing) headers جاری نہیں کرتی۔ Browser ہر call کو مسترد کر دیتا ہے۔ نتیجتاً dashboard اپنا layout render کرتا ہے مگر کوئی data نہیں دکھاتا، جبکہ docker compose ps ہر چیز کو healthy report کرتا رہتا ہے۔

جب آپ proxy config میں ہوں تو automated traffic کو بھی handle کریں۔ Crawlers بھی collector کو عام visitors کی طرح hit کرتے ہیں، اور ان کے page views ClickHouse اور آپ کے numbers میں شامل ہو جاتے ہیں۔ Server پر AI crawlers کو block کرنا اس traffic کا کچھ حصہ database میں جانے سے پہلے روک دیتا ہے۔ اس سے accuracy اور disk space دونوں کے نقصان سے بچا جا سکتا ہے۔

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

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

اس کا فائدہ یہ ہے کہ وزیٹر کے device پر کوئی identifier مستقل طور پر محفوظ نہیں رہتا۔ یہی وہ مخصوص چیز ہے جو کسی tracker کو EU ePrivacy کی consent rules کے دائرے میں لاتی ہے۔ اسی وجہ سے اس طرح کے صرف aggregate data پر مبنی setups عام طور پر consent banner کے بغیر چلائے جاتے ہیں۔ GDPR پھر بھی اس بات پر لاگو ہوتا ہے کہ آپ کیا محفوظ کرتے ہیں اور کتنی مدت تک محفوظ کرتے ہیں۔ آپ کے معاملے کا فیصلہ آپ کا counsel کرے گا، README نہیں۔

اس کی قیمت cross-day identity کا ختم ہونا ہے۔ salt کی تبدیلی کا مطلب ہے کہ جو شخص Monday کو آتا ہے اور پھر Wednesday کو دوبارہ آتا ہے، اسے ڈیزائن کے مطابق دو وزیٹر شمار کیا جاتا ہے، اور اس کے لیے کوئی workaround نہیں ہے۔ روزانہ کے unique counts درست رہتے ہیں۔ ہفتہ وار اور ماہانہ unique counts روزانہ کے counts سے بنائے جاتے ہیں اور reach کو زیادہ ظاہر کریں گے۔ اس لیے طویل مدت کا کوئی بھی "returning visitor" figure وہ چیز نہیں ناپتا جس کا اس کا label دعویٰ کرتا ہے۔ ایک ہی دن کے اندر sessions اور journeys قابل اعتماد رہتے ہیں۔ ANONYMOUS_IDENTITY_SECRET کو rotate کرنے کا اثر بھی day boundary جیسا ہوتا ہے، اس لیے اس rotation کو معمول کی hygiene کے بجائے data change سمجھیں۔

collector Do Not Track اور Global Privacy Control کو تسلیم کرتا ہے۔ یہ browser signal ہے جو site کو personal data فروخت یا share نہ کرنے کی ہدایت دیتا ہے۔ اسی مقصد کے لیے script tag میں اپنے switches موجود ہیں: data-respect-gpc، data-respect-dnt، اور data-require-consent۔ data-require-consent consent ملنے تک تمام collection روک کر رکھتا ہے اور جواب کو localStorage میں oa.consent key کے تحت یاد رکھتا ہے۔ data-storage="none" set کرنے سے browser storage مکمل طور پر بند ہو جاتی ہے۔

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

یہی چیز self-hosted analytics server کو ناکارہ بناتی ہے، اور عموماً events اس کی وجہ نہیں ہوتے۔

سب سے پہلے images دیکھیں۔ ایک release ان میں سے دس جاری کرتی ہے، اور ڈسک پر ان کا حجم تقریباً 13 GB ہوتا ہے۔ Upgrade پرانی generation کو ہٹانے سے پہلے نئی generation pull کرتا ہے، اس لیے کچھ وقت تک دونوں generations موجود رہتی ہیں۔ ایک بھی page view آنے سے پہلے ہی 25 GB کی ضرورت کا زیادہ تر حصہ اسی طرح پورا ہو جاتا ہے۔

پھر snapshots آتے ہیں۔ snapshot.sh stack کو روکتا ہے، دونوں data volumes کو ہر secret سمیت archive کرتا ہے، اور پھر stack دوبارہ شروع کرتا ہے۔ یہاں صرف cold copies محفوظ قسم ہیں، کیونکہ ClickHouse پس منظر میں parts merge کرتا ہے اور merge کے دوران بنائی گئی copy consistent نہیں ہوتی۔ upgrade.sh ہر upgrade سے پہلے خودکار snapshot لیتا ہے، اس لیے archives اسی ڈسک پر جمع ہوتے رہتے ہیں، جب تک آپ ان کی تعداد محدود نہ کر دیں۔

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

حد کے قریب موجود host پر upgrade سے پہلے پچھلی generation reclaim کریں۔ یہ stack کے چلتے ہوئے محفوظ ہے، کیونکہ running containers کو فراہم کرنے والی images اب بھی referenced ہوتی ہیں:

docker image prune -a -f

پھر خود events آتے ہیں۔ ClickHouse columnar data کو بہت زیادہ compress کرتا ہے، اس لیے raw event volume زیادہ تر لوگوں کی توقع سے آہستہ بڑھتا ہے، اور dashboard جن rollup tables کو پڑھتا ہے وہ raw table کے مقابلے میں چھوٹی ہوتی ہیں۔ اندازہ لگانے کے بجائے پیمائش کریں:

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

ہر table کا حجم معلوم کرنے کے لیے اسے ان ClickHouse credentials کے ساتھ چلائیں جو generator نے 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;

یہ پیمائش پہلے ہفتے میں اور پھر چوتھے ہفتے میں کریں۔ دو پیمائشیں growth rate معلوم کرنے کے لیے کافی ہیں، اور growth rate سے پتا چلتا ہے کہ volume کو کب resize کرنا ہوگا۔ August 2026 تک self-hosting guide میں raw events کے لیے retention یا time-to-live knob درج نہیں ہے، اس لیے ڈسک کا سائز اپنی measured rate کے مطابق مقرر کریں۔ یہ فرض نہ کریں کہ پرانی rows خود بخود expire ہو جاتی ہیں۔

ایک deletion trap کو نقصان پہنچانے سے پہلے سمجھ لینا ضروری ہے۔ کسی site یا account کو delete کرنے سے worker کے لیے کام queue ہوتا ہے، اور اس worker کے لیے CLICKHOUSE_MAINTENANCE_USER اور CLICKHOUSE_MAINTENANCE_PASSWORD set ہونا ضروری ہے، جبکہ ClickHouse میں matching oa_maintenance user بھی موجود ہونا چاہیے۔ ان کے بغیر deletion ہمیشہ queue میں رہتی ہے۔ site dashboard سے غائب ہو جاتی ہے، لیکن ہر row ڈسک پر موجود رہتی ہے۔ یوں cleanup مکمل ہونے کا تاثر ملتا ہے، مگر کوئی disk space واپس نہیں ملتی۔

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

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

upgrade.sh کارروائی سے پہلے تین اخراجات دکھاتا ہے۔ downtime حقیقی ہے: collector کے بند ہونے کے دوران کی گئی events ضائع ہو جاتی ہیں، کیونکہ tracker انہیں دوبارہ کوشش نہیں کرتا۔ rollback سے data ضائع ہوتا ہے، کیونکہ rollback.sh --to backups/<snapshot> دونوں stores کو مکمل طور پر تبدیل کرتا ہے اور اس snapshot کے بعد لکھی گئی ہر row کو خارج کر دیتا ہے۔ disk تیسرا خرچ ہے، یعنی اوپر بیان کیا گیا snapshots کا ذخیرہ۔

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

docker compose up -d --force-recreate clickhouse

dashboard میں بھی اسی نوعیت کا مسئلہ ہے۔ env/web.env میں موجود تین NEXT_PUBLIC_* origins browser bundle میں compile کیے جاتے ہیں اور container شروع ہونے پر ان کی جگہ values رکھی جاتی ہیں، اس لیے غلط hostname کو call کرنے والا dashboard docker compose up -d --force-recreate web سے درست ہوتا ہے، restart سے کبھی نہیں۔ web container کا log ان origins کو دکھاتا ہے جن کے ساتھ وہ شروع ہوا تھا۔ یہ تصدیق کرنے کا تیز ترین طریقہ ہے کہ fix لاگو ہو گئی ہے۔

اگر config میں ترمیم کے بعد ClickHouse شروع ہونے سے انکار کرے تو اس کے log کی پہلی line پڑھیں۔ oa-entrypoint: سے شروع ہونے والی line اس entrypoint کی جانب سے ہوتی ہے جو آپ کی مقرر کردہ value کو مسترد کر رہا ہے۔ اس کے علاوہ عموماً config file میں invalid XML ہوتا ہے۔ اس کی سب سے عام وجہ XML comment کے اندر double hyphen ہے، جو وہاں غیر قانونی ہے۔

AGPL-3.0 اور نام

یہ code AGPL-3.0 کے تحت licensed ہے۔ اسے اپنی سائٹس کے لیے بغیر ترمیم کے چلانے سے کسی قسم کی publishing obligation پیدا نہیں ہوتی۔ یہ obligation اس وقت شروع ہوتی ہے جب آپ code میں ترمیم کر کے اس modified version کو network service کے طور پر چلاتے ہیں۔ اس صورت میں license کا تقاضا ہے کہ آپ اس service کے users کو modified source فراہم کریں۔ اس میں اپنی instance پر clients کو dashboards فراہم کرنا بھی شامل ہے، اور اسے کسی ایسی چیز میں شامل کرنا بھی جسے آپ فروخت کرتے ہیں۔ اپنی تبدیلیاں public fork میں رکھنا اس تقاضے کو پورا کرنے کے لیے کافی ہے؛ مزید کسی process کی ضرورت نہیں۔

Brand code سے الگ ہے۔ "OpenAnalytics" نام اور project کا hosted domain اس instance کی شناخت کرتے ہیں جسے اس کے authors چلاتے ہیں، اور یہ license grant کا حصہ نہیں ہیں۔ آپ کی deployment brand استعمال کیے بغیر software چلاتی ہے۔ اس لیے اسے paying customers کے سامنے پیش کرنے سے پہلے service کو اپنا نام دیں۔

FAQ

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

نہیں۔ اس project کو تقریباً 4 GB RAM اور 25 GB خالی disk درکار ہوتی ہے، کیونکہ ایک deployment میں Postgres، ClickHouse اور دو Valkey instances کے ساتھ چھ application services چلتی ہیں۔ صرف ClickHouse ہی کوئی ہلکا process نہیں ہے۔ 1 GB کے server پر containers start ہوتے ہیں، پھر kernel کا out-of-memory killer ان میں سے کسی ایک کو ختم کر دیتا ہے، عموماً ClickHouse کو۔ اگر 1 GB plan ہی لازمی شرط ہے تو GoatCounter جیسے single-binary tool استعمال کریں، جو SQLite پر external database کے بغیر چلتا ہے۔

اس سوال کا جواب آپ کا lawyer دے گا، لیکن technical facts آپ کے حق میں ہیں۔ کوئی cookie نہیں ہے، visitor identity ایک salted hash ہوتی ہے جو روزانہ rotate ہوتی ہے، اور raw IP addresses کبھی store نہیں کیے جاتے؛ اس لیے visitor کی شناخت کے لیے کوئی مستقل data نہیں لکھا جاتا۔ GDPR پھر بھی اس بات پر لاگو ہوتا ہے کہ آپ کیا store کرتے ہیں اور کتنے عرصے تک رکھتے ہیں۔ اگر آپ collection کو واضح consent کے ساتھ مشروط کرنا چاہتے ہیں تو script tag پر data-require-consent set کریں: اس کے بعد consent ملنے تک tracker کچھ collect نہیں کرے گا، اور جواب oa.consent کے تحت localStorage میں رکھے گا۔

events 202 واپس کیوں کرتے ہیں لیکن dashboard میں کبھی ظاہر نہیں ہوتے؟

202 کا مطلب ہے کہ collector نے event قبول کرکے queue میں ڈال دیا ہے، یہ نہیں کہ اسے store بھی کر دیا ہے۔ worker اس queue کو ClickHouse میں منتقل کرتا ہے، اس لیے successful requests کے باوجود خالی dashboard کا مسئلہ worker کی طرف اشارہ کرتا ہے۔ docker compose logs --tail=50 worker پڑھیں اور Valkey queue depth کو monitor کریں۔ اگر queue مسلسل بڑھ رہی ہو تو worker blocked ہے۔ عام وجوہات میں worker.env میں غلط ClickHouse credentials یا اس table پر missing grant شامل ہے جسے حالیہ migration نے بنایا ہے۔

جب ہر container healthy ہو تو dashboard خالی کیوں ہوتا ہے؟

پہلے env/api.env میں AUTH_TRUSTED_ORIGINS چیک کریں۔ اسے dashboard origin سے بالکل match کرنا چاہیے۔ اگر match نہ کرے تو API کوئی CORS headers جاری نہیں کرتی، اس لیے browser ہر call مسترد کر دیتا ہے اور آپ کو data کے بغیر working layout نظر آتا ہے۔ دوسری چیز جسے چیک کرنا چاہیے وہ env/web.env میں موجود تین NEXT_PUBLIC_* values ہیں۔ web container start ہوتے وقت یہ values substitute کی جاتی ہیں۔ انہیں درست کرنے کے لیے docker compose up -d --force-recreate web درکار ہے، کیونکہ plain restart پرانی values برقرار رکھتا ہے۔

کیا AGPL-3.0 مجھے یہ service clients کو فراہم کرنے سے روکتا ہے؟

نہیں، اس کے ساتھ صرف ایک شرط منسلک ہے۔ code کو بغیر ترمیم کے چلائیں تو آپ کسی کے بھی پابند نہیں ہیں۔ اگر آپ code میں ترمیم کرکے اس modified version کو ایسی service کے طور پر چلائیں جسے دوسرے لوگ استعمال کرتے ہیں تو آپ کو ان users کو اپنا modified source فراہم کرنا ہوگا۔ public fork اس شرط کو پورا کرتا ہے۔ الگ بات یہ ہے کہ "OpenAnalytics" نام code کے ساتھ licensed نہیں ہے، اس لیے آپ جو بھی فروخت کریں اسے اپنا الگ نام دینا ہوگا۔