استضافة OpenAnalytics ذاتيًا على VPS: المتطلبات والتثبيت
تعرّف على المتطلبات الفعلية لاستضافة OpenAnalytics: ClickHouse وPostgres وValkey، وذاكرة 4 GB، ومساحة 25 GB، وأربعة سجلات DNS قبل التثبيت.
البصمة قبل الخطوة الأولى
لتشغيل OpenAnalytics على خادم ذاتي الاستضافة، تحتاج إلى VPS يعمل بنظام Linux وبذاكرة RAM بسعة 4 GB تقريباً، ومساحة قرص خالية تبلغ 25 GB، وDocker مع Compose plugin، وأربعة سجلات DNS تشير مسبقاً إلى الخادم. هذه هي المتطلبات الفعلية، ويجب عرضها قبل أول أمر لا بعده.
تتكون الحزمة من ست خدمات للتطبيق وثلاثة مخازن بيانات. يخزّن Postgres مستوى التحكم، بما في ذلك الحسابات والمواقع ومفاتيح API وروابط المشاركة. يخزّن ClickHouse الأحداث الخام والبيانات المجمعة التي تقرأها لوحة المعلومات. يعمل Valkey مرتين: مرة كقائمة انتظار دائمة للأحداث، ومرة كذاكرة تخزين مؤقت يمكن للنظام فقدانها، لأن هاتين المهمتين تحتاجان إلى سياستي إخلاء متعاكستين. لا يُسمح إلا لعملية واحدة، وهي query gateway، بقراءة ClickHouse، وتتحقق هذه العملية من توقيع Ed25519 في كل غلاف استعلام قبل تنفيذه.
إذا كنت تريد ملفاً تنفيذياً واحداً وملف إعداد واحداً، فهذا ليس الحل المناسب. يُعد GoatCounter الخيار ذا الملف التنفيذي الواحد في هذه الفئة: ملف Go تنفيذي واحد، وSQLite افتراضياً، ومن دون قاعدة بيانات خارجية على الإطلاق. تتيح لك الحزمة الأثقل إنشاء مسارات التحويل، وقياس مؤشرات الويب، وإسناد الإيرادات من حساب Stripe الخاص بك، وتشغيل خادم MCP (model context protocol). يناقش المنشور الاختيار بين أدوات التحليلات ذاتية الاستضافة هذه المفاضلة. يفترض هذا الدليل أنك اتخذت القرار مسبقاً.
وجّه سجلات DNS الأربعة إلى الخادم أولاً
يجب أن تحل النطاقات الفرعية الأربعة إلى عنوان IP العام للخادم قبل أن تبدأ، لأن Caddy يطلب شهادات Let's Encrypt عند التشغيل الأول، ويفشل التحقق من الاسم إذا لم يكن يحل بعد.
- يخدم
app.example.comلوحة التحكم. - يخدم
api.example.comواجهة API وعمليات استدعاء OAuth. - يخدم
c.example.comأداة التجميع وscript التتبّع. - يخدم
rt.example.comالبث الفوري.
استخدم أربعة سجلات A، أو سجل A واحداً وثلاثة سجلات CNAME تشير إليه. تحقّق باستخدام dig +short app.example.com قبل المتابعة. قد يظل الاسم الذي أضفته قبل دقيقة واحد مخزّناً مؤقتاً على أنه NXDOMAIN لدى محلّل الأسماء الذي تستخدمه Let's Encrypt، لذلك انتظر قليلاً واقرأ سجلات Caddy إذا فشلت محاولة الشهادة الأولى. إعادة تشغيل التثبيت لا تسرّع انتشار DNS.
كيفية استضافة OpenAnalytics ذاتياً باستخدام Docker Compose
تحقّق من إصدار موسوم. الفرع الافتراضي مخصّص للتطوير، بينما يطابق الإصدار الموسوم الصور المنشورة فعلياً. تفترض الأوامر أدناه أن Docker ومكوّن Compose مثبتان مسبقاً، وتشرح تشغيل خدمات Docker Compose على VPS كيفية ذلك.
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يستبعد sed '/-/d' في سطر النسخ الوسوم التجريبية، لذلك تحصل على أحدث إصدار مستقر بدلاً من إصدار مرشح. يجلب --with-geoip قاعدة بيانات المدن من DB-IP أثناء التوليد. إذا تخطّيت هذه الخطوة، فسيحمل كل حدث قيمة country فارغة، وبالتالي لن يعرض منظور البيانات الجغرافية أي شيء. يمكنك إضافتها لاحقاً بتشغيل infra/selfhost/geoip/fetch-dbip.sh، وضبط GEOIP_DB_PATH=/geoip/dbip-city-lite.mmdb في env/collector.env، ثم إعادة إنشاء collector باستخدام docker compose up -d --force-recreate collector. تُحدَّث قاعدة البيانات شهرياً، لذلك كرّر عملية الجلب كل شهر، وإلا ستصبح بيانات المدن قديمة وغير دقيقة.
انسخ الأسرار المُنشأة احتياطياً قبل المتابعة
يكتب المولّد ثلاثة أشياء. يحتوي .env على أسماء النطاقات ومراجع الصور. ويحتوي env/*.env على ملف أسرار واحد لكل خدمة. ويحتوي docker-compose.override.yml على ثلاثة أزواج مفاتيح Ed25519 بصيغة YAML block scalars، لأن PEM متعدد الأسطر لا يمكن وضعه في ملف env. جميع هذه الملفات مستثناة من Git، ولا يمكن إعادة إنشائها بالقيم نفسها.
انسخ هذه الملفات الآن إلى خارج الجهاز. فقدان كل منها له نتيجة محددة:
- إذا فقدت كلمات مرور مخازن البيانات، فستُمنع من الوصول إلى Postgres وClickHouse. ولا يمكن إعادة ضبطها إلا من داخل الحاويات.
- إذا فقدت
OA_CREDENTIAL_KEYRING، فلا يمكن استعادة أي بيانات اعتماد مخزنة لطرف ثالث. لذلك يجب على كل من ربط حساب Stripe أن يربطه مرة أخرى. - إذا فقدت
ANONYMOUS_IDENTITY_SECRET، فستُعاد تهيئة هوية الزوار: سيُحتسب زوار الأمس جميعاً كزوار جدد، وسيظهر الانقطاع في المخططات. - إذا فقدت
AUTH_SECRET، فستُبطل كل الجلسات، وسيتعين على الجميع تسجيل الدخول مرة أخرى. - إذا فقدت مفتاحاً خاصاً للتوقيع، فبدّل زوج المفاتيح. لن تفقد أي بيانات.
يجب أن تكون قيمتا سرين متطابقتين على مستوى البايت في ملفين لكل منهما. يظهر ANONYMOUS_IDENTITY_SECRET في collector.env وworker.env، لأن collector يحسب تجزئة الزائر، بينما يكتبها worker. ويظهر OA_CREDENTIAL_KEYRING في api.env وworker.env. أما كل ما عدا ذلك فمحدد لخدمة واحدة فقط عن قصد. وإذا مُنحت خدمة سراً لا يجوز لها الاحتفاظ به، فستتوقف بدلاً من أن تبدأ.
شغّل المكدس وتحقق منه
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، ثم يخرج أيضاً. يجب أن تعرض جميع الخدمات الأخرى الحالة healthy في docker compose ps. تعني إعادة تشغيل خدمة في حلقة غالباً أنها تفشل في التحقق من متغيرات البيئة. ويعرض السجل جميع المشكلات في قائمة واحدة بدلاً من عرض مشكلة واحدة في كل إعادة تشغيل. السببان المعتادان هما ترك متغير فارغاً، إذ يُرفض بدلاً من اعتباره غير معيّن، ووضع سر في ملف خدمة غير صحيح.
على 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. لا يعرض النشر الذي لم يسجّل أي شخص الدخول إليه نموذج تسجيل الدخول، بل يتيح إنشاء الحساب الأول. يبقى هذا الحساب صاحب الامتيازات دائماً، وهو الحساب الوحيد الذي يرى شاشة إعدادات النشر. بعد إنشائه، يعيد المسار الاستجابة 409، لذلك لا يستطيع أي شخص الدخول بعدك. نفّذ ذلك فور سلامة المكدس، وليس في الأسبوع التالي.
ثبّت أداة التتبّع
أضف موقعاً في لوحة التحكم، وستعرض لك وسم التتبّع. بنيته ثابتة:
<script
async
src="https://c.example.com/oa.js"
data-key="YOUR_TRACKING_KEY"
data-collector="https://c.example.com"
></script>ضعه في رأس الصفحة. مفتاح التتبّع عام بطبيعته، لذلك يجب أن يكون داخل HTML حيث يمكن لأي شخص قراءته. يثبّت البرنامج النصي window.oa، وتضع الاستدعاءات مثل oa("track", ...) في قائمة انتظار مؤقتة، ثم تُفرَّغ بعد تحميل الملف، لذلك لا يُفقد الحدث المخصّص إذا أُطلق مبكراً. إذا كان هناك مكوّن آخر في الصفحة يستخدم window.oa، فسيثبّت أداة التتبّع نفسها باسم window.openanalytics بدلاً منه. إذا كان الموقع نفسه متاحاً أيضاً بصفته خدمة onion، فأبقِ الوسم خارج تلك النسخة، لأن البرنامج النصي الذي يُجلب من c.example.com يعيد زائر Tor Browser إلى الإنترنت العام، ويربط العنوانين في عملية تحميل الصفحة نفسها.
تحقق بعد ذلك من المسار بالكامل من طرف إلى طرف:
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 وبضعة كيلوبايتات. حمّل صفحة من موقعك، ثم ابحث عن سطر دفعة في سجل العامل خلال ثوانٍ. يجيب جامع الأحداث بـ 202 فور قبوله حدثاً، بينما يعني 202 أن الحدث موضوع في قائمة الانتظار، وليس أنه مخزّن. العامل هو الذي ينقل الأحداث إلى ClickHouse. إذا قُبلت الأحداث ولم يظهر شيء في لوحة التحكم، فهذا يعني أن العامل متعطل، ويؤكد ذلك استمرار ارتفاع عمق قائمة انتظار Valkey. الأسباب المعتادة هي خطأ بيانات اعتماد ClickHouse في worker.env، أو غياب منح الصلاحيات على جدول أضافته عملية ترحيل حديثة.
إبقاء الجامع متاحاً للعامة ولوحة المعلومات خلف المصادقة
يتضمن ملف compose برنامج Caddy، ويحصل على الشهادات للأسماء الأربعة تلقائياً، لذلك لا تحتاج إلى إعداد Proxy إضافي في المسار الافتراضي. إذا كان الخادم يشغّل Reverse Proxy باستخدام 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 الخاص بالعميل، لذلك يجب أن يأخذ هذا العنوان من الاتصال، وألا يأخذه من رأس. يتيح تمرير CF-Connecting-IP من قفزة غير موثوقة لأي مستدعٍ ادعاء استخدام أي عنوان، ما يفسد تحديد الموقع الجغرافي ويضخّم أعداد الزوار في الوقت نفسه.
ينقسم الوصول بوضوح وفق اسم المضيف. يجب أن يكون c. وrt. متاحين لكل زائر لكل موقع تقيسه، لذلك لا تضع basic auth أو قائمة سماح لعناوين IP أمام أيٍّ منهما. لا يحتاج app. وapi. إلى الإتاحة إلا للمستخدمين الذين يسجّلون الدخول. تحمي مصادقة التطبيق الخاصة لوحة المعلومات: يكون تسجيل الدخول بكلمة المرور مفعّلاً افتراضياً عبر AUTH_PASSWORD_SIGNIN=enabled في env/api.env، ولا تظهر زرا Google أو GitHub إلا عند وجود معرّف العميل وسر العميل لكلا المزوّدين. تحتاج الروابط السحرية إلى وسيلة نقل للبريد، ومن دونها لا تكتب API الإرسال إلا في outbox، لذلك لا تُسلّم الرسالة ولا يظهر أي خطأ. إذا كانت تطبيقاتك الأخرى ذاتية الاستضافة تعمل بالفعل خلف تسجيل دخول Authentik موحّد، فحدّد مبكراً ما إذا كانت لوحة المعلومات ستنضم إليها أم ستحتفظ بحساباتها الخاصة، لأن أول حساب تنشئه هنا يبقى الحساب ذي الامتيازات بشكل دائم.
يحدّد إعداد واحد ما إذا كانت لوحة المعلومات ستعمل أصلاً. يجب أن يطابق AUTH_TRUSTED_ORIGINS في env/api.env مصدر لوحة المعلومات تماماً. عند غيابه أو خطئه، لا تصدر API رؤوس CORS (مشاركة الموارد بين المصادر)، ويرفض المتصفح كل استدعاء، فتحصل على لوحة معلومات تعرض تخطيطها ولا تعرض أي بيانات، بينما يشير docker compose ps إلى أن كل شيء سليم.
أثناء وجودك في إعدادات Proxy، عالج حركة المرور الآلية. تصل برامج الزحف إلى الجامع مثل أي زائر آخر، وتُسجّل مشاهدات صفحاتها في ClickHouse وفي أرقامك. يساعد حظر برامج زحف الذكاء الاصطناعي على الخادم في إبقاء جزء من هذه المشاهدات خارج قاعدة البيانات قبل أن يؤثر في الدقة ومساحة القرص معاً.
ما المقصود بعدم استخدام ملفات تعريف الارتباط هنا، وما تكلفته عليك
لا يوجد ملف تعريف ارتباط. هوية الزائر عبارة عن تجزئة مملحة، وتتغير قيمة salt كل يوم، ولا تُخزَّن عناوين IP الخام مطلقاً. تُحدَّد المنطقة الجغرافية محلياً بالرجوع إلى ملف DB-IP الموجود على القرص لديك، لذلك لا يغادر الخادم أي استعلام يتعلق بالزائر. إبقاء عمليات البحث محلية يزيل المورّد، لا البيانات. وهذا هو القيد نفسه الذي يظهر عند تشغيل مثيل SearXNG خاص بك، إذ يصبح عنوان IP الخاص بخادمك هو العنوان الذي تراه محركات البحث.
ما تحصل عليه هو عدم وجود معرّف محفوظ على جهاز الزائر. وهذا تحديداً ما يُخضع أداة التتبع لقواعد الموافقة الخاصة بـEU ePrivacy. لذلك تُشغَّل الإعدادات التي تجمع البيانات المجمّعة فقط، مثل هذا الإعداد، عادةً من دون banner للموافقة. تظل GDPR سارية على كل ما تخزّنه وعلى مدة تخزينه. ويحدّد مستشارك القانوني وضعك، لا ملف README.
ما تخسره هو تحديد الهوية عبر الأيام. يعني تدوير salt أن الشخص الذي يزور الموقع يوم الإثنين ثم يعود يوم الأربعاء يُحتسب كزائرين، وهذا مقصود ولا توجد طريقة لتجاوزه. تكون أعداد الزوار الفريدين اليومية سليمة. أما الأعداد الأسبوعية والشهرية للزوار الفريدين فتُبنى من الأعداد اليومية، ولذلك تبالغ في تقدير الوصول. وعليه، فإن أي رقم طويل الأجل بعنوان "الزائر العائد" لا يقيس ما يشير إليه عنوانه. تكون الجلسات ومسارات الزيارة موثوقة ضمن اليوم الواحد. ويؤدي تدوير ANONYMOUS_IDENTITY_SECRET إلى الأثر نفسه الناتج عن الحد الفاصل بين يومين. لذلك تعامل مع هذا التدوير باعتباره تغييراً في البيانات، لا إجراءً دورياً للنظافة.
يحترم الجامع Do Not Track وGlobal Privacy Control، وهي إشارة من المتصفح تُخبر الموقع بعدم بيع البيانات الشخصية أو مشاركتها. ويتضمن وسم script مفاتيح التبديل الخاصة به للغرض نفسه: data-respect-gpc وdata-respect-dnt وdata-require-consent، الذي يوقف كل عمليات الجمع إلى أن تُمنح الموافقة، ويحفظ الإجابة في localStorage ضمن المفتاح oa.consent. يؤدي ضبط data-storage="none" إلى إيقاف تخزين المتصفح بالكامل.
لماذا يمتلئ القرص بعد ستة أشهر
هذا ما يعطّل خادم التحليلات المستضاف ذاتياً، وعادةً لا تكون الأحداث هي السبب.
ابدأ بالصور. ينشر الإصدار عشر صور، ويبلغ حجمها الإجمالي نحو 13 GB على القرص. يسحب التحديث الجيل الجديد قبل حذف الجيل القديم، لذلك تحتفظ بالجيلين مدةً من الوقت. وهذا يستهلك معظم متطلبات 25 GB قبل وصول مشاهدة صفحة واحدة.
ثم تأتي اللقطات. snapshot.sh يوقف المكدس، ويؤرشف وحدتي البيانات مع كل سر، ثم يعيد التشغيل. النسخ الباردة هي النوع الآمن الوحيد هنا، لأن ClickHouse يدمج الأجزاء في الخلفية، والنسخة التي تُؤخذ أثناء الدمج لا تكون متسقة. ينشئ upgrade.sh نسخة تلقائياً قبل كل تحديث، لذلك تتراكم الأرشيفات على القرص نفسه إلى أن تضع حداً لعددها.
./snapshot.sh create --label before-something-risky
./snapshot.sh list
./snapshot.sh --keep 3على مضيف اقترب من الحد الأقصى، استعد الجيل السابق قبل التحديث. هذا آمن أثناء تشغيل المكدس، لأن الصور التي تعتمد عليها الحاويات قيد التشغيل لا تزال مُشاراً إليها:
docker image prune -a -fثم تأتي الأحداث نفسها. يضغط ClickHouse البيانات العمودية بقوة، لذلك ينمو حجم الأحداث الخام ببطء أكثر مما يتوقعه معظم الأشخاص، كما أن جداول التجميع التي تقرأ منها لوحة المعلومات صغيرة مقارنةً بالجدول الخام. قِس بدلاً من التخمين:
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;سجّل هذه القراءة في الأسبوع الأول ثم كررها في الأسبوع الرابع. تعطيك نقطتان معدل نمو، ويخبرك معدل النمو بموعد الحاجة إلى زيادة حجم وحدة التخزين. لا يوثّق دليل الاستضافة الذاتية أي إعداد للاحتفاظ أو time-to-live للأحداث الخام حتى August 2026، لذلك حدّد حجم القرص وفق معدل النمو الذي قسته، بدلاً من افتراض أن الصفوف القديمة تنتهي صلاحيتها تلقائياً.
هناك فخ يتعلق بالحذف يجدر بك معرفته قبل أن يسبب المشكلة. يؤدي حذف موقع أو حساب إلى وضع مهمة في قائمة انتظار العامل، ويحتاج هذا العامل إلى ضبط CLICKHOUSE_MAINTENANCE_USER وCLICKHOUSE_MAINTENANCE_PASSWORD، مع وجود مستخدم oa_maintenance مطابق في ClickHouse. من دون هذه الإعدادات، تبقى عملية الحذف في قائمة الانتظار إلى الأبد. يختفي الموقع من لوحة المعلومات، بينما تبقى كل صفوفه على القرص، فتحصل على مظهر التنظيف من دون استعادة أي مساحة.
الترقيات والتكاليف الثلاثة
git fetch --tags
git checkout "$(git tag -l 'v*' --sort=-v:refname | sed '/-/d' | head -1)"
cd infra/selfhost
./upgrade.shيطبع upgrade.sh ثلاثة تكاليف قبل أن ينفّذ الإجراء. التوقف عن العمل حقيقي: تُفقد الأحداث التي جرت محاولتها أثناء توقف جامع البيانات، لأن المتتبّع لا يعيد محاولتها. ويؤدي التراجع إلى فقدان البيانات، لأن rollback.sh --to backups/<snapshot> يستبدل مخزني البيانات بالكامل ويتخلّص من كل صف كُتب بعد إنشاء تلك اللقطة. أما القرص فهو التكلفة الثالثة، ويتمثل في تراكم اللقطات الموضح أعلاه.
من السهل تطبيق قاعدتي إعادة التشغيل بشكل خاطئ. شغّل بوابة الاستعلام قبل API، لأن API الأحدث يرسل حقول استعلام ترفضها البوابة الأقدم. ويحتاج ClickHouse إلى إعادة إنشاء الحاوية بدلاً من إعادة تشغيلها، لأن docker compose restart يعيد استخدام البيئة الأصلية للحاوية ويتجاهل تعديلك بصمت:
docker compose up -d --force-recreate clickhouseتتبع لوحة المعلومات النمط نفسه من الأخطاء. تُضمَّن الأصول الثلاثة لـNEXT_PUBLIC_* في env/web.env داخل حزمة المتصفح، وتُستبدل عند بدء الحاوية. لذلك تُصلح لوحة المعلومات التي تستدعي اسم المضيف الخطأ باستخدام docker compose up -d --force-recreate web، وليس باستخدام restart. ويسجّل سجل حاوية الويب الأصول التي بدأت بها، وهذه أسرع طريقة للتأكد من تطبيق الإصلاح.
إذا رفض ClickHouse البدء بعد تعديل الإعدادات، فاقرأ السطر الأول من سجله. السطر الذي يبدأ بـoa-entrypoint: يعني أن نقطة الدخول رفضت قيمة ضبطتها. أما أي شيء آخر فيعني عادةً أن ملف الإعدادات يحتوي على XML غير صالح. والسبب الأكثر شيوعاً هو وجود واصلتين متتاليتين داخل تعليق XML، وهذا غير مسموح به هناك.
AGPL-3.0، والاسم
الشفرة مرخّصة بموجب AGPL-3.0. لا يترتب على تشغيلها من دون تعديل لمواقعك الخاصة أي التزام بالنشر. يبدأ الالتزام عند تعديل الشفرة وتشغيل الإصدار المعدّل كخدمة شبكية؛ إذ تلزمك الرخصة حينها بإتاحة الشفرة المصدرية المعدّلة لمستخدمي تلك الخدمة. ويشمل ذلك منح العملاء لوحات معلومات على مثيلك، كما يشمل دمجها في منتج تبيعه. ويكفي إبقاء تعديلاتك في fork عام للوفاء بهذا الالتزام من دون أي إجراء إضافي.
العلامة التجارية منفصلة عن الشفرة. يحدّد اسم "OpenAnalytics" والنطاق المستضاف للمشروع المثيل الذي يشغّله مؤلفوه، ولا يشملهما منح الرخصة. يشغّل نشرُك البرنامج من دون استخدام العلامة التجارية، لذلك امنح الخدمة اسماً خاصاً بها قبل إتاحتها للعملاء الذين يدفعون مقابلاً.
FAQ
هل يمكنني تشغيل OpenAnalytics على VPS بسعة 1 GB؟
لا. يتطلب المشروع نحو 4 GB من ذاكرة RAM و25 GB من مساحة القرص الحرة، لأن كل عملية نشر تشغّل ست خدمات تطبيقات إلى جانب Postgres وClickHouse ونسختين من Valkey. وClickHouse وحده ليس عملية صغيرة. على خادم بسعة 1 GB، تبدأ الحاويات ثم تنهي النواة إحدى هذه العمليات بسبب نفاد الذاكرة، وعادةً تكون ClickHouse. إذا كانت خطة 1 GB قيداً لا يمكن تجاوزه، فاستخدم أداة تعمل بملف ثنائي واحد، مثل GoatCounter، إذ تعمل على SQLite دون قاعدة بيانات خارجية.
هل أحتاج إلى شريط موافقة على ملفات تعريف الارتباط مع OpenAnalytics؟
هذا سؤال لمحاميك، والوقائع التقنية تصب في صالحك. لا تُستخدم ملفات تعريف ارتباط، وهُوية الزائر عبارة عن hash مملّح يتغير يومياً، ولا تُخزَّن عناوين IP الأولية مطلقاً، لذلك لا تُكتب أي بيانات دائمة لتحديد هوية الزائر. يظل GDPR ناظماً لما تخزّنه والمدة التي تحتفظ فيها به. إذا أردت تقييد الجمع صراحةً، فاضبط data-require-consent في وسم script: عندئذٍ لا يجمع tracker أي بيانات حتى تُمنح الموافقة، ويحفظ الإجابة في localStorage ضمن oa.consent.
لماذا تُرجع الأحداث 202 لكنها لا تظهر مطلقاً في لوحة المعلومات؟
يعني 202 أن collector قبل الحدث ووضعه في قائمة الانتظار، وليس أنه خزّنه. يفرّغ worker قائمة الانتظار في ClickHouse، لذلك تشير لوحة المعلومات الفارغة مع نجاح الطلبات إلى وجود مشكلة في worker. اقرأ docker compose logs --tail=50 worker وراقب عمق قائمة Valkey. نمو قائمة الانتظار باستمرار يعني أن worker متوقف، والأسباب المعتادة هي بيانات اعتماد ClickHouse الخاطئة في worker.env أو غياب grant على جدول أنشأته migration حديثة.
لماذا تكون لوحة المعلومات فارغة رغم أن كل حاوية تعمل بصورة سليمة؟
تحقق أولاً من AUTH_TRUSTED_ORIGINS في env/api.env. يجب أن يطابق مصدر لوحة المعلومات تماماً. وعندما لا يتطابقان، لا تُصدر API رؤوس CORS، لذلك يرفض المتصفح كل استدعاء، وتظهر لك واجهة عاملة دون بيانات. والشيء الثاني الذي يجب التحقق منه هو قيم NEXT_PUBLIC_* الثلاث في env/web.env، إذ تُستبدل عند بدء web container. يتطلب تصحيحها docker compose up -d --force-recreate web، لأن إعادة التشغيل العادية تُبقي القيم القديمة.
هل يمنعني AGPL-3.0 من تقديم هذا البرنامج للعملاء؟
لا، لكنه يفرض شرطاً واحداً. شغّل الكود دون تعديل، ولن تدين بشيء لأي شخص. إذا عدّلته وشغّلت النسخة المعدّلة كخدمة يستخدمها أشخاص آخرون، فيجب أن تتيح لهؤلاء المستخدمين المصدر المعدّل، وهو ما يحققه public fork. وبشكل منفصل، لا يشمل الترخيص اسم "OpenAnalytics" مع الكود، لذلك يحتاج أي شيء تبيعه إلى اسم خاص به.