
مراقبة مركزية لحالات Nextcloud المتعددة
مراقبة مركزية لعدة مثيلات Nextcloud
NcStatusCheck هي أداة مراقبة تتيح لك تتبع حالة خوادم Nextcloud المتعددة من واجهة ويب واحدة. تقوم بتحليل إصدارات Nextcloud وPHP وتقديم توصيات التحديث.

< 15d / < 7d)occ app:list مقابل متجر تطبيقات Nextcloud للإشارة إلى التطبيقات التي تحتاج مراجعة — الحاجزة (التي تمنع الترقية، غير متوافقة، تطبيقات اختبار في الإنتاج) بالإضافة إلى إشارات النضج/التقلب المعلوماتية (منشورة مؤخرًا، قبل 1.0، إصدار alpha/beta/rc، دفعة إصدارات، إصدار صدر حديثًا)📦) وكتلة توأم "حاويات للمراقبة" (🐳) تجمع كل تطبيق / صورة Docker تم الإشارة إليها عبر جميع المثيلات في إدخال واحد، مع مرشحات نوع لكل مجموعة ونافذة منبثقة تسرد المثيلات المتأثرة وإصداراتهاALERT_WEBHOOK_URL)، و/أو بريد إلكتروني ملخص لكل دفعة (ALERT_EMAIL_TO) يُرسل عبر إرسال SMTP مباشر إلى خادم البريد الخاص بك (PHPMailer مُضمّن؛ يتراجع إلى MTA المحلي عند عدم تكوين مرحّل SMTP). كما يغطي الإشارات بطيئة الحركة (ALERT_CHECKS): انتهاء شهادة SSL (مستويات)، إصدار Nextcloud ضعيف/قديم، فحص دفع قديم، تقرير تدقيق حرج، نتيجة تطبيق حاجز — تنبيه واحد لكل حالة جديدة، بدون رسائل مزعجة متكررةnc_update_grace_days)، لتجنب ملاحقة إصدار خاطئ في نفس اليوم⚠️ تحذيرات، 📦 تطبيقات، 🔄 Docker، 🔒 SSL، 🔴 غير متصل، 🚧 صيانة) عندما يكون هناك ما يجب الإبلاغ عنهnc-audit.sh الشهريlocalStoragechmod 700) للمثيل البعيد لـ Nextcloud، يتم تحديثه تلقائيًا مع تغيير الخياراتncstatuscheck/ ├── Frontend │ ├── index.php # Main entry point │ ├── template.html # HTML template (dashboard) │ ├── admin.html # Administration interface │ ├── detail.php # Server detail page │ ├── audit.php # Server-audit script distribution page (nc-audit.sh) │ ├── troubleshooting.php # Probe troubleshooting guide │ ├── app.js / admin.js / detail.js / audit.js / troubleshooting.js │ └── style*.css # One stylesheet per page family ├── APIs (HTTP) │ ├── api.php # Main monitoring API │ ├── detail-api.php # Detail page API (serverinfo + warnings + acks + availability) │ ├── push-api.php # Push reception + trigger + audit-report reception │ ├── ack-api.php # Warning acknowledge / unmute │ ├── admin-api.php # Version configuration routing │ ├── servers-admin-api.php # Server list management │ ├── nextcloud-versions-api.php # Official version scraping │ ├── nextcloud-apps-api.php # App store catalog (slim cache) for the apps audit │ ├── php-versions-api.php # PHP branch support data │ └── apps-warnings-api.php # Manual app warnings (known-bug list) CRUD ├── Shared modules (lib/) │ ├── auth.php # Auth + CSRF + URL redaction (defense in depth) │ ├── csrf-client.js # Auto-inject X-CSRF-Token in fetch() │ ├── nextcloud-client.php # Centralized HTTP client → remote Nextclouds │ ├── servers-store.php # Single source of truth for servers.json │ ├── uptime-state.php # Up/down state machine + transition journal + availability │ ├── alerts.php # Proactive alert dispatch: webhook + email digest │ ├── alerts-checks.php # Slow-signal alerts (SSL/version/push/audit/apps) + dedup state │ ├── smtp-mailer.php # SMTP transport adapter over vendored PHPMailer │ ├── phpmailer/ # Vendored PHPMailer (3 files + LICENSE, pinned in VERSION) │ ├── apps-warnings-manager.php # Manual app warnings storage │ ├── ui-common.js # NcUI: notify / confirm / prompt + shared app-audit messages │ ├── url-guard.php # Anti-SSRF (loopback, RFC1918, link-local…) │ ├── json-cache.php # Locked JSON read/write helpers │ └── version-config-manager.php # Version rules CRUD ├── Business logic │ ├── version-rules.php # NC / PHP status analysis engine │ ├── warnings-rules.php # Configuration warning engine │ ├── apps-rules.php # Installed-apps audit engine (store catalog cross-check) │ ├── cron-update.php # Full collection script, CLI only (twice a day) │ └── cron-ping.php # Lightweight up/down probe, CLI only (every 5 min) ├── Tools (never web-served — blocked by nginx/.htaccess) │ ├── tools/nc-audit.sh # Standalone server audit script (root, read-only) │ └── tools/ncstatuscheck-push-core.sh # Generic Push probe core (fleet-shared) ├── Tests │ └── tests/run.php # Plain-PHP test suite (no framework): php tests/run.php ├── Configuration │ ├── config.php # Central configuration (git-ignored) │ └── servers.json # Server list with tokens (git-ignored) └── Cache ├── servers_data.json # All server data ├── serverinfo_.json # Raw per-server cache (Extended) ├── push_.json # Last push payload per server ├── ack_.json # Acknowledged warnings per server ├── audit_.json # Last nc-audit.sh report per server ├── version-config.json # Version configuration ├── uptime_state.json # Up/down state per server (mini uptime) ├── uptime_history.json # Bounded up/down transition journal (availability % + incidents) ├── alerts_state.json # "Already alerted" memory of the check alerts ├── nextcloud_versions.json # Official NC versions ├── nextcloud_apps.json # App store slim catalog (apps audit) ├── apps-warnings.json # Manual app warnings (admin-curated) ├── .csrf_secret # CSRF HMAC secret (binary, 0600) └── *.log # Activity logs
deploy/ansible/ # Fleet deployment of the Push core (Ansible / scp) deploy/docker/ # Container packaging of the monitor itself
## 🔌 أوضاع الجمع
الأوضاع ليست حصرية — يمكن للخادم أن يكون Extended و Push في نفس الوقت.
| الوضع | الشارة | المصدر | البيانات المجمعة |
|------|-------|--------|----------------|
| **Basic** | *(لا شيء)* | `/status.php` + رؤوس HTTP | إصدار Nextcloud (PHP/خادم الويب إذا كان مكشوفًا) |
| **Extended** | `⚡ Extended` (أرجواني → برتقالي عند الخطأ/القديم) | `/ocs/v2.php/apps/serverinfo/api/v1/info` مع `NC-Token` | إصدار NC، PHP، خادم الويب، OPcache، Redis، قاعدة البيانات، المستخدمون النشطون... |
| **Push** | `📡 Push` (أزرق → برتقالي عند الخطأ/القديم) | POST إلى `push-api.php` | البيانات التي يدفعها مثيل NC البعيد عبر سكربت cron |
**رمز NC-Token لـ serverinfo** متاح في **إعدادات Nextcloud → الإدارة → النظام**.
**رمز push** يتم إنشاؤه من واجهة الإدارة؛ يقدم المسؤول سكربت cron bash جاهز للاستخدام (`chmod 700`) لنشره على المثيل المراقب.
بيانات الوضع الموسع يتم توفيرها بواسطة تطبيق [nextcloud/serverinfo](https://github.com/nextcloud/serverinfo)، والذي يجب تثبيته وتفعيله على المثيل المراقب.
**سلوك التراجع**: إذا كانت واجهة API الموسعة غير قابلة للوصول (خطأ في الاتصال، رمز غير صالح، التطبيق غير مثبت)، يقوم NcStatusCheck تلقائيًا بالتراجع إلى `/status.php` لاسترداد إصدار Nextcloud على الأقل.
**حد العتاقة لـ Push**: يعتبر خادم push قديمًا إذا لم يتم استقبال أي بيانات خلال `auto_push_interval + 30 دقيقة`. الفاصل الزمني الافتراضي للـ push هو 12 ساعة.
### أعمدة جدول لوحة القيادة
تعرض لوحة القيادة الرئيسية 5 أعمدة: **الخادم** | **إصدار NC** | **PHP** | **المسبارات** | **الصحة**
يعرض عمود **المسبارات** أوضاع الجمع النشطة لكل خادم:
- شارة `⚡ Extended` (أرجواني، يتحول إلى برتقالي عند خطأ الاتصال أو البيانات القديمة)
- شارة `📡 Push` (أزرق، يتحول إلى برتقالي عندما لا يتم استقبال بيانات ضمن الحد)
- يمكن أن تظهر كلتا الشارتين في نفس الوقت إذا كان كلا الوضعين نشطين
- لا شارة = وضع Basic فقط
### عمود الصحة
يعرض عمود الصحة شيئًا فقط عندما يكون هناك شيء يجب اتخاذ إجراء بشأنه:
| المؤشر | الشارة | المعنى |
|-----------|-------|---------|
| غير متصل | `🔴 Offline` | المثيل غير قابل للوصول (فشل اختبار HTTP)، مع "غير متصل لمدة X" |
| تحذيرات نشطة | `⚠️ N` | N مشكلة تكوين |
| تدقيق التطبيقات | `📦 N` | N تطبيق مثبت للمراجعة (يعيق الترقية/غير متوافق) |
| انتهاء SSL | `🔒 N d` | الشهادة ستنتهي قريبًا — برتقالي `< 15d`، أحمر `< 7d` أو منتهية الصلاحية |
| تحديثات Docker | `🔄 M` | M تحديث حاوية متاحة |
| كل شيء جيد | *(فارغ)* | لا شيء للإبلاغ |
| لا بيانات | `?` | وضع Basic بدون بيانات push |
#### حالة الاتصال وانتهاء SSL
يحتفظ NcStatusCheck بحالة **أدنى** للاتصال/الانقطاع لكل خادم (الحالة الحالية + تاريخ آخر تغيير فقط — لا سلاسل زمنية، لا صفحة تاريخ). "متصل" يعني أن اختبار HTTPS الصادر وصل إلى المثيل؛ تظهر شارة **غير متصل** الحمراء فقط عند الانقطاع. خلال نفس اختبار HTTPS، تتم قراءة **انتهاء صلاحية شهادة SSL** مجانًا (`CURLOPT_CERTINFO`) وتظهر عندما تصبح قريبة. كلاهما مرئيان بالكامل في صفحة التفاصيل. *ملاحظة: هذه الفحوصات الصادرة لا تنطبق على مثيلات Push-only التي لا يتصل بها المراقب أبدًا.*
#### تدقيق التطبيقات (`📦`)
عندما يبلغ خادم Push عن تطبيقاته المثبتة (`occ app:list`، إصدار سكربت push v3+)، يتحقق NcStatusCheck منها مقابل كتالوج متجر تطبيقات Nextcloud ويضع علامات على التطبيقات التي تستحق المراجعة. **إشارات فقط** — الأداة لا تقوم أبدًا بتعطيل أي شيء؛ تعرض المرشحين (لا يمكنها معرفة ما إذا كان التطبيق قيد الاستخدام فعليًا). يتم استخدام **إشارات واقعية وثنائية** فقط. تحتسب شارة `📦 N` النتائج العرقلة (لا يوجد إصدار متوافق مع إصدار NC الحالي، لا يوجد إصدار لـ NC N+1 → يعيق الترقية، أو تطبيق اختبار/تطوير متروك مفعلًا في الإنتاج). يتم عرض النتائج المعلوماتية (التطبيق قديم على المثيل، مهجور من الأعلى، غير متوافق مع PHP) في صفحة التفاصيل فقط. يمكن كتم النتائج عبر نفس آلية الإقرار المستخدمة للتحذيرات.
### تنسيق `servers.json````json
[
{"url": "https://cloud.example.com"},
{"url": "https://cloud2.example.com", "serverinfo_token": "abc123def456"},
{"url": "https://cloud3.example.com", "serverinfo_token": "...", "push_token": "xyz789"}
]
server { server_name monitoring.your-domain.com; root /var/www/ncstatuscheck; index index.php;
# HTTP Basic Authentication
auth_basic "Monitoring Access";
auth_basic_user_file /etc/nginx/.htpasswd;
# Protect sensitive files/dirs (tests/run.php has no CLI-only guard — it must
# never be reachable over HTTP; same blocklist as deploy/docker/nginx.conf)
location ~ ^/(cache/|\.git|deploy/|tools/|tests/) {
deny all;
return 404;
}
# .txt covers servers.txt (legacy server list — real monitored URLs)
location ~* \.(log|json|txt)$ {
deny all;
return 404;
}
# Security headers for static HTML pages (admin.html, template.html).
# PHP pages (index.php, detail.php) send the same headers themselves
# via send_security_headers() in lib/auth.php.
location ~* \.html$ {
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
add_header Referrer-Policy no-referrer always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'" always;
try_files $uri =404;
}
# Standard PHP configuration (adjust the socket to your PHP version —
# use a security-supported one: 8.2 has been EOL since December 2025)
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location / {
try_files $uri $uri/ =404;
}
}
> **أباتشي**: يحتوي المستودع على ملفات `.htaccess` تعكس قواعد الـ `deny` أعلاه (الجذر: يحظر `*.log`/`*.json`/`*.txt` و `.git`؛ `cache/`، `tools/`، `deploy/`، `tests/`: `Require all denied`). تعمل هذه الملفات فقط إذا كان المضيف الافتراضي يحدد `AllowOverride FileInfo AuthConfig` (أو `All`) — الإعداد الافتراضي لـ Debian لـ `/var/www` هو `AllowOverride None`، وفي هذه الحالة قم بنسخ القواعد مباشرة في المضيف الافتراضي. لا يزال يتعين تكوين توثيق HTTP الأساسي (Basic auth) في المضيف الافتراضي في كلتا الحالتين.
### النشر
1. **استنساخ المستودع**```bash
git clone https://gitlab.com/jp.louvel/ncstatuscheck.git
cd ncstatuscheck
قم بتعديل `config.php` وضبط المسارات وعنوان URL لبيئتك:```php
define('MONITOR_PATH', '/var/www/ncstatuscheck');
define('MONITOR_URL', 'https://monitoring.your-domain.com'); // your public URL
define('CACHE_DIR', MONITOR_PATH . '/cache');
تتم إدارة الخوادم مباشرة من واجهة الإدارة (زر ⚙️ Admin).
يمكنك أيضًا إنشاء servers.json يدويًا:```json
[
{"url": "https://cloud.example.com"},
{"url": "https://nextcloud.mycompany.org", "serverinfo_token": "your_token_here"}
]
> **الترحيل من `servers.txt`**: إذا كان ملف `servers.txt` موجودًا، فسيتم تحويله تلقائيًا إلى `servers.json` عند الوصول الأول. يمكنك بعد ذلك حذف `servers.txt`.
4. **تعيين الأذونات**
nginx/PHP-FPM تعمل كمستخدمين خاصين بهم (`www-data` على Debian/Ubuntu، `nginx`/`apache` على عائلة RHEL — اضبط حسب ما يناسب) — إذا قمت باستنساخ المستودع كمستخدم تسجيل الدخول الخاص بك، فمن شبه المؤكد أن هذا المستخدم ليس `www-data` أو ضمن مجموعته، لذا فإن `chmod` وحده يترك خادم الويب **بدون وصول على الإطلاق**، ولا حتى القراءة (كل طلب يعيد 403/404):```bash
chown -R www-data:www-data /var/www/ncstatuscheck # adjust the user:group to your distro
chmod 750 /var/www/ncstatuscheck
chmod 750 cache img
chmod 640 *.php *.html *.js *.css *.md
chmod 600 config.php servers.json servers.txt # secrets / serverinfo & push tokens
chmod 660 cache/*.json cache/*.log
إذا لم يكن ملف
servers.jsonموجودًا بعد (أنت تسمح لواجهة الإدارة بإنشائه بدلاً من الخطوة اليدوية أعلاه)، فإن الأمرchmod 600أعلاه ليس لديه شيء ليعمل عليه — هذا جيد: يقومServersStore::save()بتغيير صلاحيات الملف إلى0600بنفسه عند كل كتابة، لذا فإن ملفservers.jsonالذي يتم إنشاؤه (أو إعادة إنشائه) عبر واجهة الإدارة لا يبقى أبدًا مقروءًا للمجموعة/العالم مع رموز serverinfo/push tokens بداخله.
6. **المهام المجدولة (اختياري)**
كرونان متكاملان — قم بتثبيتهما **في نفس استدعاء `crontab -`**:
`crontab -` يقوم بتثبيت crontab جديد بالكامل من stdin، ولا يقوم بالإلحاق، لذا
تشغيله مرتين (مرة لكل سطر) يترك فقط المهمة *الثانية* — الأولى
تختفي بصمت، بدون خطأ. هذا يحافظ أيضًا على أي شيء موجود بالفعل في crontab الخاص بك
(`crontab -l` الذي تم توجيهه أولاً) بدلاً من مسحه:```bash
(crontab -l 2>/dev/null; cat <<'EOF'
# Full collection (NC/PHP versions, serverinfo, app-store catalog) — twice a day
0 6,18 * * * cd /var/www/ncstatuscheck && php cron-update.php
# Lightweight reachability probe (status.php only -> up/down state) — every 5 min
*/5 * * * * cd /var/www/ncstatuscheck && php cron-ping.php
EOF
) | crontab -
إعادة تشغيل هذا يؤدي إلى إضافة نسخ مكررة إذا كانت هذه الأسطر موجودة بالفعل — تحقق باستخدام crontab -l أولاً إذا كنت غير متأكد.
cron-ping.php بسيط عمداً: فهو يتحقق فقط من status.php لكل مثيل ويُحدّث حالة التشغيل/الإيقاف (cache/uptime_state.json)، لذا يمكن تشغيله بشكل متكرر دون تحميل. يتم وضع علامة إيقاف على المثيل فقط بعد UPTIME_FAIL_THRESHOLD محاولة فاشلة متتالية (الافتراضي 2 → ~10 دقائق مع وتيرة 5 دقائق)؛ الاسترداد إلى تشغيل فوري. يبقى cron-update.php الكامل دون تغيير لكل شيء آخر.
بدلاً من الخطوات من 1 إلى 6 أعلاه، يمكن تشغيل NcStatusCheck أيضاً كمكدس docker compose صغير (PHP-FPM + nginx + حاوية cron) — يتم ربط المستودع كما هو، بدون خطوة بناء أو Composer، لذا فهو يعكس تخطيط التثبيت المباشر تماماً، ولكن داخل حاويات. يخدم HTTP عادي فقط (المنفذ 8080 افتراضياً) — ضع وكيل عكسي خاص بك ينهي TLS أمامه.
الإعداد الكامل — التكوين، مشاكل الأذونات (uid 82، الإنشاء المسبق لـ servers.json)، المصادقة الأساسية HTTP، cron، التحديثات والنسخ الاحتياطية — موجود بالكامل في deploy/docker/README.md. ابدأ من هناك؛ هذا القسم هو مجرد مؤشر عمداً، لتجنب الاحتفاظ بنسختين من نفس الخطوات بشكل متزامن.
https://monitoring.your-domain.comيمكن الوصول إليها بالنقر على أي اسم خادم أو مؤشر صحته.
بالنسبة للخوادم الأساسية (بدون فحص ممتد أو دفعي)، تعرض صفحة مبسطة البيانات المتاحة (إصدار NC، خادم الويب، بروتوكول HTTP) مع إشعار واقتراح لتمكين الفحص.
بالنسبة للخوادم الممتدة / الدفعية، تعرض صفحة التفاصيل الكاملة أقساماً منفصلة:
يكشف NcStatusCheck عن عدة نقاط نهاية REST:
واجهة API الرئيسية (api.php)
GET ?action=get_data — جلب البيانات (ذاكرة التخزين المؤقت أو تحديث)POST ?action=refresh_data — فرض تحديث جميع الخوادمواجهة API للدفع (push-api.php)
POST مع رأس push_token — استقبال بيانات الدفع من مثيل NC عن بُعدPOST ?action=request_push_all — طلب دفع فوري من جميع خوادم الدفع المُكوّنة (يضع علامة تشغيل يستهلكها نص cron البعيد)نص cron الذي يولده واجهة الإدارة مقسم إلى جزئين: نواة عامة
/usr/local/bin/ncstatuscheck-push.sh— متطابقة على كل خادم (كل المنطق) — تُدار بواسطة تكوين صغير لكل مثيل/etc/ncstatuscheck/<slug>.conf(SERVER_URL,SLUG,OCC_CMD,DOCKER_ENABLED,SKOPEO_ENABLED). يتم استدعاؤه كـncstatuscheck-push.sh /etc/ncstatuscheck/<slug>.conf [--test]. ترفض النواة استخدام تكوين قابل للكتابة من قبل المجموعة أو الكل (لمنع حقن الكود).إنه متعدد الأهداف (fan-out): يتم جمع البيانات مرة واحدة ودفعها إلى كل مراقب مدرج في
/etc/ncstatuscheck/targets-<slug>.conf(سطر واحدurl|push_token[|http_user|http_pass]لكل مراقب). يصدر مسؤول كل مراقب أمراً غير قابل للتغيير (idempotent) لتسجيل نفسه.عدة مثيلات Nextcloud على مضيف واحد: يتم لصق
<slug>المستمد من عنوان URL المراقب كبادئة للمسارات الخاصة بكل مثيل (مثال: ← ): , , , , الحالة . فقط النواة مشتركة، لذا لا تتصادم المثيلات المتواجدة في نفس المكان.
واجهة API للتفاصيل (detail-api.php)
GET ?server=<url> — بيانات serverinfo كاملة + تحذيرات محسوبة لخادم ممتد/دفعيواجهات API للإدارة
admin-api.php — تكوين الإصدارservers-admin-api.php — إدارة الخادم (get_servers, add_server, remove_server, update_server_token, generate_push_token, remove_push_token)nextcloud-versions-api.php — الإصدارات الرسميةnc-audit.sh)نظام فرعي منفصل عن المراقبة: نص bash مستقل للقراءة فقط
(tools/nc-audit.sh) يُشغّل كجذر على خادم Nextcloud لتدقيق لمرة واحدة / شهري
لضبط خادم الويب + PHP + قاعدة البيانات، مع التحقق المتبادل مقابل السعة
المادية للجهاز (RAM, CPU, نوع القرص). يستهدف عرض إشراف مُدار:
يقوم العميل بتثبيته، ويتلقى المراقب التقارير فقط — لا يتطلب الوصول إلى الجهاز/الشبكة.
النص يقرأ فقط التكوين (بدون تغييرات)، ويطبع تقريراً ملوناً ويكتب نسخة إلى /tmp.
ما يقوم بفحصه: سعة الخادم (RAM/CPU/SSD-HDD، swappiness، كشف المشاركة) · Nextcloud (الإصدارات، cron، ذاكرة التخزين المؤقت، وقت تشغيل Redis، نوع قاعدة البيانات، السجلات) · PHP/PHP-FPM (SAPI الخدمة الفعلية، وقت تشغيل OPcache، ذاكرة متعددة المجموعات) · Apache (ذاكرة العامل المدركة لـ MPM) · Nginx · PostgreSQL · MariaDB · النظافة الأمنية (fail2ban أو CrowdSec + bouncer + قائمة حظر المجتمع؛ التحديثات المعلقة / إعادة التشغيل / الخدمات على مكتبات قديمة) · تسوية ميزانية RAM (InnoDB + FPM + Apache مقابل RAM الفعلية) · تحليل عميق بأدوات اختيارية إذا كانت موجودة بالفعل (mysqltuner, pt-variable-advisor, apache2buddy, sar/iostat).```bash
curl -fsSL https://gitlab.com/jp.louvel/ncstatuscheck/-/raw/master/tools/nc-audit.sh -o /usr/local/bin/nc-audit.sh chmod 700 /usr/local/bin/nc-audit.sh
sudo nc-audit.sh # auto-detect, dedicated server sudo nc-audit.sh /var/www/nextcloud # explicit path (or NC_PATH=…) sudo NC_RAM_BUDGET_PCT=50 nc-audit.sh # shared host: size to 50% of RAM
**مضيفات متعددة المثيلات** (عدة Nextclouds + قاعدة بيانات مشتركة). `NC_RAM_BUDGET_PCT`
هي ميزانية **المكدس الإجمالية**؛ `NC_PHP_SHARE_PCT`% منها (الافتراضي 60، والباقي
يغطي DB + web + OS — اخفضه على الخوادم الثقيلة بقاعدة البيانات) هي حصة PHP، وتُقسم عبر
مجموعات FPM حسب **الوزن** (أهمية نسبية — ليست نسبة مئوية، ولا ميغابايت) لإعطاء هدف
`pm.max_children` لكل مجموعة:```
target = PHP_share × (weight / Σ weights) / ~50 MB per process
الهدف هو سقف يسمح به الميزانية، وليس قيمة يجب عليك تعيينها (فقط ارفع مجمعًا يشبع فعليًا). الأوزان هي اختيارك — الأداة لا تخمنها أبدًا.```bash
sudo NC_RAM_BUDGET_PCT=70 NC_INSTANCES="poolA:4,poolB:2,poolC:1" nc-audit.sh
sudo NC_RAM_BUDGET_PCT=70 nc-audit.sh --tune-fpm
**إرجاع التقرير** (اختياري، يعيد استخدام بنية الدفع): `nc-audit.sh --push
/etc/ncstatuscheck/<slug>.conf` يقوم بتشغيل التدقيق وإرسال التقرير عبر POST إلى جهاز (أجهزة) المراقبة، التي تخزنه وتظهره في صفحة تفاصيل الخادم (قسم "🩺 تدقيق الخادم"). عادةً ما يكون مهمة كرون شهرية. تقوم صفحة الويب (الإدارة، بيتا) على `audit.php` بتوزيع البرنامج النصي (تحميل + مضمن + سطر واحد لـ GitLab) وتظهر إصداره.
> **لا يتم تثبيت أدوات التحليل العميق** أبدًا بواسطة البرنامج النصي — فهي تعمل فقط إذا كانت موجودة بالفعل (لا `curl | bash`، لا تثبيت تلقائي)، كل منها محدود بـ `timeout`.
## 🔧 التكوين المتقدم
### تخصيص قواعد الإصدار
قواعد التقييم قابلة للتكوين عبر واجهة الإدارة:
**حالات Nextcloud:**
- `dev` — إصدار التطوير
- `stable` — الإصدار المستقر الحالي
- `oldstable` — الإصدار المستقر المدعوم السابق
- `deprecated` — إصدار مهمل
**حالات PHP:**
- `recommended` — الإصدار الموصى به
- `supported` — الإصدار المدعوم
- `deprecated` — إصدار مهمل
### متغيرات التكوين
قم بتحرير `config.php` لتكييف التكوين:```php
// Environment: 'dev' or 'prod'
define('ENV', 'prod');
// Paths and URLs
define('MONITOR_PATH', '/var/www/ncstatuscheck');
define('MONITOR_URL', 'https://monitoring.your-domain.com');
// Main server cache duration
define('CACHE_MAX_AGE', 86400); // 24 hours
// Official Nextcloud versions cache duration
define('VERSIONS_CACHE_AGE', 86400);
// Consecutive failed probes before a server is marked "down" (min 1)
define('UPTIME_FAIL_THRESHOLD', 2);
// Proactive alerts — webhook on a confirmed up/down state change.
// Empty URL = disabled. Format: 'slack' (default, also Mattermost/Google Chat),
// 'discord', or 'raw' (structured JSON). The URL usually carries a secret, so it
// is never logged in full — see config-example.php for details.
define('ALERT_WEBHOOK_URL', '');
define('ALERT_WEBHOOK_FORMAT', 'slack');
// Check alerts on top of up/down (cron-update cadence, 2×/day): SSL expiry
// tiers, vulnerable (below min_secure) or deprecated Nextcloud version, stale
// Push data, critical audit report, blocking apps-audit finding. Edge-triggered with a persisted state
// (cache/alerts_state.json): one alert per NEW condition, no reminders, re-arms
// when resolved (renewed cert, fixed/acked app…). First run arms silently.
define('ALERT_CHECKS', 'ssl,version,push_stale,audit,apps'); // '' = up/down only
define('ALERT_SSL_DAYS', '30,14,7'); // days-left tiers
// Email channel, independent of the webhook (either one arms the alerting).
// One digest mail per batch. Recommended transport: direct SMTP submission to
// your mail server (vendored PHPMailer, lib/phpmailer/ — nothing to set up on
// the host). Without ALERT_SMTP_HOST it falls back to PHP mail() (local MTA).
define('ALERT_EMAIL_TO', ''); // comma list of recipients, '' = off
define('ALERT_EMAIL_FROM', ''); // default: ncstatuscheck@<hostname>
define('ALERT_SMTP_HOST', ''); // e.g. 'mail.example.org', '' = mail() fallback
define('ALERT_SMTP_PORT', 587);
define('ALERT_SMTP_SECURITY', 'starttls'); // 'starttls' | 'tls' | 'none'
define('ALERT_SMTP_USER', '');
define('ALERT_SMTP_PASS', '');
انظر
config-example.phpللحصول على القائمة الكاملة المعلقة للخيارات (بما في ذلكDEMO_MODEوPUSH_SCRIPT_VERSION).
lib/csrf-client.js + csrf_require()).htaccess المرفوعة لـ Apache؛ يتم تعيين صلاحيات servers.json تلقائيًا إلى 0600 (الرموز بداخلها)X-Frame-Options, nosniff, Referrer-Policy) على كل صفحة تقدم عبر PHPhash_equals() على رمز الإدخال، بحيث لا يستطيع الخادم المراقب المخترق قراءة بيانات خادم آخر أو استبدالها. / خلف مصادقة المسؤول + CSRF. تم التحقق من النهاية إلى النهاية ضد سيناريو عميل مخترقconfig.php مهمل في git ويتم تعديله يدويًا لكل خادم، لذلك يبتعد — بصمت، نظرًا لأن كل ثابت تقريبًا لديه بديل في الكود. لافتة في أعلى صفحة المسؤول تُبلغ ما هو خطأ بالفعل، وفقط عندما يكون هناك شيء: PUSH_SCRIPT_VERSION متروك بعد ترقية، عدم وجود نقل إنذار مهيأ على الإطلاق، علامة إغلاق زائدة تبعث بايت قبل أي header()، دليل ذاكرة تخزين مؤقت غير قابل للكتابة، ثوابت مفقودة وتقع بصمت إلى القيم الافتراضية.
للقراءة فقط حسب التصميم وبدون إجراء حفظ، لنفس سبب علامة تبويب الإشعارات: config.php مملوك للجذر ويحتوي على أسرار. محتوى الملف لا يسافر أبدًا — فقط الحقائق عنه — ولا يتم قراءة أي سر.
كل ما سبق هو على مستوى التطبيق: لا يزال بإمكان أي شخص على الإنترنت الوصول إلى المراقب واستكشافه، ولا يوقفه إلا كلمة المرور. علامة تبويب تصفية IP تولد القواعد التي تضع قائمة السماح أمام التطبيق، بحيث لا تستطيع المضيفات غير المعروفة التحدث إليه على الإطلاق. إنه دفاع في العمق، وليس بديلاً عن مصادقة Basic أو رموز الدفع — ولا ينتج إلا نصًا للمراجعة واللصق، ولا يكتب أبدًا تكوين خادم الويب أو جدار الحماية.
فئتان من المصادر، غير متساويتين عمدًا، بحيث لا يستطيع الخادم المراقب المخترق الوصول إلى المسؤول:
| الفئة | من | يمكنه الوصول إلى |
|---|---|---|
push | المثيلات المراقبة في وضع الدفع فقط | /push-api.php، لا شيء آخر |
admin | الحصن / VPN / IP مكتب ثابت | كل شيء |
المثيلات التي يتم استطلاعها في الوضع الأساسي/الموسع لا تفتح أي اتصال وارد ولا تحصل على أي إدخال في قائمة السماح إطلاقًا.
تأتي العناوين من مصدرين، والفرق مهم: سجل DNS لنطاق مراقب هو عنوان الدخول الخاص به، بينما يغادر دفعه من عنوان الخروج. حيث يختلفان، يعمل الثاني فقط. لذلك يسجل push-api.php عنوان المصدر الحقيقي لكل دفعة (source_ip في ذاكرة التخزين المؤقت للدفع)، وتضع علامة التبويب ذلك في قائمة السماح، مع الإبلاغ عن عدم التطابق. حتى يدفع الخادم مرة واحدة، يعود إلى DNS A+AAAA ويقول ذلك.
ثلاثة مخرجات:
conf.d مستقل (geo + map) بالإضافة إلى سطر واحد if ($ncsc_forbidden) { return 403; } في vhost. لا حاجة لتكرار كتلة fastcgi، الملفات الثابتة مغطاة أيضًا (admin.html واحد منها)، و /.well-known/acme-challenge/ يظل مفتوحًا حتى لا ينقطع تجديد الشهادة بصمت.<LocationMatch> مع نظرة سلبية للأمام بالإضافة إلى <Location> لنقطة نهاية الدفع، بحيث لا يمكن للقسمين التداخل ولا شيء يعتمد على ترتيب الدمج في Apache. جميع عناوين قاعدة تذهب في سطر Require ip واحد: عدة أسطر داخل <RequireAll> يتم دمجها بـ AND، ولا يمكن لأي شخص تلبيتها.يرفض المولد إخراج أي شيء عندما لا يتم تقديم عنوان إداري، ويحذر عندما لا يكون عنوان المشغل نفسه مغطى، ويحذر عندما جاء الطلب عبر وكيل (كلا من geo و Require ip يقرآن النظير الناقل، لذلك خلف وكيل يبدو كل عميل متشابهًا). يضع المقتطف ufw المولد قاعدة SSH أولاً، ويبقي المنفذ 80 مفتوحًا لتحدي HTTP-01، ويوضح فخ IPv6: على عكس nginx، الذي يرفض عنوان v6 غير مدرج، لا يقوم ufw بتصفية v6 على الإطلاق ما لم يتم تعيين IPV6=yes — وإلا سيكون مضيف مزدوج التعشيش مفتوحًا بالكامل عبر IPv6.
حد معروف، يظهر في الصفحة نفسها: بمجرد تطبيق القواعد، لا تكتشف علامة التبويب هذه شيئًا جديدًا. يتم رفض الدفع المرفوض من قبل خادم الويب قبل وصوله إلى PHP، لذا يظل العنوان المسجل آخر عنوان تم تمريره — ويظل يبدو موثوقًا. نتيجتان: إضافة خادم دفع يعني إعادة توليد القواعد وإعادة تطبيقها، أو يتم رفض أول دفعة له؛ وإذا تغير عنوان مثيل، لا يمكن قراءة العنوان الجديد إلا في سجل وصول خادم الويب (grep 'push-api.php' access.log | grep ' 403 '). لذلك تظهر علامة التبويب تاريخ آخر مشاهدة لكل عنوان تم رصده وتضع عليه علامة بمجرد أن يصبح أقدم من دورة دفع كاملة مفقودة — نفس الحد مثل إنذار push_stale، الذي يغطي نفس النقطة العمياء من الجانب الآخر.
التمييز بين مشكلة تصفية وأي أخرى: GET عاري على نقطة نهاية الدفع يفصل الطبقات بوضوح، بدون تأثير جانبي وبدون حاجة لرمز — قم بتشغيله من الجهاز المعني، لأن ما يتم الحكم عليه هو عنوان الخروج لذلك الجهاز:```bash
curl -sS -o /dev/null -w '%{http_code}\n' https://your-monitor/push-api.php
| الإجابة | المعنى |
|---|---|---|
| `403` | محظور بواسطة تصفية IP |
| `401` | تم اجتياز التصفية، المصادقة الأساسية تستجيب — المشكلة في مكان آخر |
| `405` | وصل الطلب إلى التطبيق (GET ليست طريقة مقبولة هناك) |
| لا شيء / مهلة | ليس التصفية: الفلتر يجيب، لا يصبح صامتًا |
أعد التشغيل باستخدام `-u user:password` لحل شك حول رمز `403`: إذا لم يتغير الرمز، فهو بالفعل التصفية. تم التحقق على كل من nginx وApache (بما في ذلك مع تمكين `Require valid-user`)، يستجيب الفلتر *قبل* المصادقة — ورمز `403` القادم من التطبيق نفسه يحمل دائمًا JSON في الجسم.
منطق المقتطفات موجود في `lib/hardening-rules.php`، وهو نقي ومغطى بواسطة `tests/run.php`: المقتطفات هي المنتج هنا، والمقتطف الخاطئ إما يقفل المشغل خارجًا أو يترك ثغرة. تم التحقق من مخرجات كل من nginx وApache سلوكيًا (خوادم حقيقية، عناوين مصدر حقيقية، بما في ذلك محاولات اجتياز المسار من فئة `push`).
### التحليل الآلي (مرحلة CI `security`)
فحص التبعيات (`npm/pnpm audit`, Snyk Open Source, Dependabot) هو عملية فارغة هنا: لا يوجد `package.json` ولا `composer.json` — لا شيء لفحصه. الخطر يكمن في الكود المخصص (~15 ألف سطر من PHP، ~6 آلاف من JS) وفي نصوص shell التي تعمل **كجذر** على الحالات المراقبة (`tools/*.sh`). خط الأنابيب موجه هناك:
| المهمة | الأداة | حظر | النطاق |
|---|---|---|---|
| `secrets_scan` | gitleaks | نعم | الأسرار الملتزمة (شجرة العمل) |
| `sast_semgrep` | semgrep (`p/php`, `p/javascript`, `p/owasp-top-ten`) | نعم | SSRF، مفقود authz/CSRF، XSS |
| `shellcheck` | shellcheck (`--severity=warning`) | نعم | `tools/*.sh` — جذر على مضيفي العميل |
| `dockerfile_misconfig` | trivy misconfig | نعم | `deploy/docker/` |
| `container_cve` | trivy image | لا (`allow_failure`) | الصورة التي يبنيها `deploy/docker`، بالإضافة إلى `nginx:alpine` |
| `ui_tests` | node (بدون تبعيات) | نعم | ثوابت الهروب في `lib/ui-common.js` (كلتا الانتكاسات السابقة لـ XSS) |
| `phpmailer_freshness` | GitHub API | لا (`allow_failure`) | النسخة المخزنة مقابل الإصدار الرئيسي |
| `deploy_selfcheck` | nc-selfcheck.sh | نعم | مجموعة قواعد nginx المشحونة (قواعد الرفض + رؤوس الأمان) المنصوبة في حاوية مؤقتة |
جميع وظائف الحظر لها **خط أساس خالٍ من الاكتشافات**، لذا أي تنبيه جديد هو إشارة حقيقية. خياران متعمدان، موثقان داخل `.gitlab-ci.yml`:
- **`php.lang.security.injection.echoed-request` مستبعد** من semgrep: فهو يضع علامة على كل `echo json_encode()` كـ XSS، وهو ما يفعله كل نقطة نهاية API هنا بشكل شرعي (استجابات JSON، وليس HTML). لقد شكل 10 من أصل 10 اكتشافات في التشغيل الأول، كلها خاطئة. الإبقاء عليه سيدرب الجميع على تجاهل المهمة.
- **الوظيفتان `allow_failure` تبلّغان عن حقائق منبعية** (CVE في `nginx:alpine` أو واحدة لم يصل إصلاحها إلى فرع Alpine بعد، إصدار PHPMailer جديد) لا يمكن لطلب دمج إصلاحها. الأحمر ولكن المسموح به هو الإشارة الدقيقة — "حان وقت إعادة البناء / تحديث التخزين" — وليس سببًا لحظر العمل غير المرتبط. `phpmailer_freshness` يبلغ عن GitHub API غير قابل للوصول أو محدود المعدل كـ *تخطي*، أبدًا كـ "قديم".
- **`container_cve` يفحص الصورة التي يبنيها، وليس علامة `FROM`.** ملف Dockerfile يقوي القاعدة بـ `apk --no-cache upgrade` (صورة PHP الرسمية تتأخر عن مستودعات Alpine — فقد شحنت c-ares 1.34.6-r0 بينما 1.34.8-r0، التي تصلح CVE-2026-33630، كانت قد نُشرت بالفعل). فحص علامة القاعدة سيبَلّغ إذن عن CVEs ليس للصورة المشحونة: وظيفة برتقالية دائمة لا يقرأها أحد.
قوائم السماح ضيقة عمدًا: `.gitleaks.toml` يعفي **الحرفي** من سلاسل العناصر النائبة، أبدًا ملفات التوثيق الكاملة (السماح لـ `README.md` سيعمي الفحص في اليوم الذي يُلصق فيه سر حقيقي فيه) — لذا يجب إضافة رمز مثال جديد في التوثيق هناك. `.trivyignore` يحتوي على إدخال واحد، `DS-0002`، مُجادَل في الملف: يجب أن يبدأ سيد php-fpm كجذر لإسقاط عماله إلى `www-data` (uid 82).
### التحقق بعد النشر (`nc-selfcheck.sh`)
يمكن لـ CI قفل التكوين *المشحون* (وظيفة `deploy_selfcheck` أعلاه تنصب مجموعة قواعد nginx في حاوية وتفحصها)، لكنها لا تستطيع التحقق من الخادم الذي نشرته فعليًا — مضيف مختلف، بيانات اعتماد المصادقة الأساسية، أذونات نظام الملفات. `tools/nc-selfcheck.sh` يسد تلك الفجوة. إنه نص bash مستقل للقراءة فقط (نفس نموذج `nc-audit.sh`) تقوم بتشغيله بعد كل نشر:```bash
# Black-box, no credentials: confirms Basic auth is enforced (401) and that
# sensitive files are blocked (cache/, servers.*, .git, config.php source).
bash tools/nc-selfcheck.sh https://monitoring.example.com
# + security headers behind Basic auth:
bash tools/nc-selfcheck.sh -u user:pass https://monitoring.example.com
# + filesystem checks (run ON the host): servers.json / config.php / CSRF-secret
# permissions, and a stray closing "?>" in config.php.
bash tools/nc-selfcheck.sh --webroot /var/www/ncstatuscheck https://monitoring.example.com
يخرج برمز غير صفري عند أي اكتشاف حرج (تسرب المصدر، ملف سري غير محظور، مخزن رمز قابل للقراءة عالميًا، عدم وجود توثيق أساسي)، لذا يمكنه منع الإطلاق — قم بتوصيله في السكربت الخاص بالمزامنة/النشر كخطوة لاحقة. تحذيرات/معلومات لا تتسبب أبدًا في فشل التشغيل.
// In config.php define('ENV', 'dev');
في وضع التطوير، يتم عرض معلومات إضافية (إصدار PHP، خادم الويب).
### اختبار الخادم
استخدم واجهة الإدارة لإضافة خادم عبر عنوان URL. سيتم استقصاء الخادم في المرة التالية التي يتم فيها تحديث البيانات.
### سجلات التصحيح
تحقق من ملفات السجل في `cache/`:
- `monitor.log` — سجلات التطبيق العامة
- `cron.log` — سجلات نص التجميع الكامل (`cron-update.php`)
- `ping.log` — سجلات اختبار الاتصال الخفيفة للتشغيل/الإيقاف (`cron-ping.php`)
- `alerts.log` — إرسال التنبيهات الاستباقية (webhook/بريد إلكتروني)، لا يسجل أبدًا أسرار webhook أو بيانات اعتماد SMTP
### مجموعة الاختبارات```bash
php tests/run.php # plain-PHP assertions, no framework — exit 0 = all green
يغطي منطق الأعمال الخالص (قواعد الإصدارات/التطبيقات، التحذيرات، آلة حالة وقت التشغيل والتوفر، آلة حالة إلغاء التكرار/إعادة التسليح للتنبيهات، منشئو البريد الإلكتروني).
افتح مشكلة جديدة مع:
هذا المشروع مرخص تحت GNU AGPL v3.
NcStatusCheck تم تطويره بواسطة ézéo، وهي تعاونية رقمية متخصصة في حلول المصادر المفتوحة.
هل تحتاج إلى مساعدة؟ تحقق من المشكلات أو اتصل بفريق ézéo.
| القسم | الحقول |
|---|
| نظام Nextcloud | الإصدار، وضع التصحيح، ذاكرة التخزين المؤقت المحلية/الموزعة، قفل الملفات، مساحة القرص |
| PHP | الإصدار، memory_limit، upload_max_filesize، max_execution_time، FPM، OPcache |
| خادم الويب | الاسم + الإصدار، بروتوكول HTTP |
| قاعدة البيانات | النوع، الإصدار، الحجم |
| ذاكرة التخزين المؤقت | Redis، معدل ضرب APCu |
| المستخدمون النشطون | آخر 5 دقائق، ساعة واحدة، 24 ساعة، 7 أيام |
latest.ezeo.cooplatest_ezeo_coop<slug>.conf/etc/cron.d/ncstatuscheck-<slug>targets-<slug>.confncstatuscheck-push-<slug>.log…-<slug>.<md5>.lastNextcloud يعمل في Docker (الصورة الرسمية، compose، AIO): مدعوم بالكامل — يتم تثبيت
النص على المضيف (cron الجذر + الوصول إلى خفي Docker)، وليس داخل الحاوية أبداً،
ويتم occ عبر docker exec:
OCC_CMD=docker exec -u www-data <container> php occ (حاوية AIO: nextcloud-aio-nextcloud).
يحتوي مولد نصوص الإدارة على إعداد مسبق لنوع التثبيت يملأ هذا تلقائياً. لا تقم أبداً بإضافة
-t (لا TTY تحت cron); احتفظ بـ -u www-data (الصورة الرسمية ترفض occ كجذر).
النشر / التحديث عبر أسطول الخوادم: نظراً لأن النواة ملف واحد متطابق، فإن تحديث
المنطق عبر العديد من الخوادم = استبدال ذلك الملف الواحد (العلامة ↑ تشير إلى الخوادم
التي تعمل بإصدار أقدم). راجع deploy/ansible/ للحصول على دليل تشغيل جاهز
(أو حلقة scp بسيطة). يظل المراقب سلبيًا — لا يرسل أبداً رمزًا إلى
الأسطول؛ مرسى الثقة هو وصول SSH الخاص بك، وليس المراقب.
الترحيل من تثبيت ما قبل v4 (نص ضخم لكل مثيل): قم بإزالة القديم
/usr/local/bin/ncstatuscheck-push-<slug>.sh و /etc/cron.d/ncstatuscheck-<slug>
قبل تثبيت النواة + التكوين (يتم إعادة استخدام targets-<slug>.conf كما هو)،
وإلا ستدفع مرتين.
request_pushrequest_push_alltargets.conf ينسخ كل دفع بصمت إلى طرف ثالث بخلاف ذلك<>"'& من حقول Docker الحرة (الاسم، الصورة، الإصدار، الحالة) عند الإدخال، بالإضافة إلى التهريب عند وقت العرضtry/catch التقاطه، مما يقتل تشغيل التجميع في منتصف الحلقة ومعه كل إنذار للأسطول بأكمله