تطوير الويب

الاستضافة الذاتية لـ SonarQube Community Build 26.4 على VPS Linux خطوة بخطوة

10 دقائق للقراءة

📍 الدليل الرئيسي: Pipeline SAST DAST SCA في 2026: معمارية، أدوات، وتكامل CI/CD
هذا الدرس يفصّل تثبيت SonarQube Community Build كقاعدة SAST. للحصول على نظرة شاملة على خط أنابيب DevSecOps، اقرأ الدليل الرئيسي أولاً.

لماذا الاستضافة الذاتية لـ SonarQube Community Build في 2026

يبقى SonarQube في 2026 من أكثر أدوات SAST استخداماً في المؤسسات، بحصة مهيمنة في قطاع التحليل الساكن لفرق التطوير الداخلية. إصدار Community Build، الموزع مجاناً تحت رخصة LGPL v3، يغطي أكثر من 30 لغة، ويدمج قاعدة قواعد أمنية مستمدة من OWASP Top 10 و CWE، ويوفر واجهة ناضجة لمتابعة تطور الدين التقني. انتقل تقويم الإصدارات في 2024 إلى وتيرة شهرية: نُشرت النسخة 26.4.0 في أبريل 2026، باعتماد نظام إصدارات YY.M.0 يوضح عُمر كل تنصيب.

الاستضافة الذاتية بدل الاشتراك في SonarCloud توفر ثلاث ميزات حاسمة: الكود المصدري لا يغادر البنية التحتية أبداً، والتكلفة ثابتة أياً كان عدد المُساهمين، ويمكن ربط الخادم بمستودعات داخلية لا يمكن الوصول إليها من الإنترنت. المقابل: يجب إدارة الخدمة، وتطبيق التحديثات الشهرية، والنسخ الاحتياطي لقاعدة PostgreSQL، وضبط حجم JVM بدقة. هذا الدرس يفصّل التثبيت خطوة بخطوة مع Docker Compose و Nginx كوكيل عكسي مع TLS، وهو إعداد يناسب فريقاً من 5 إلى 50 مطوراً.

المتطلبات المسبقة

  • VPS أو خادم مخصص يعمل على Ubuntu 24.04 LTS أو Debian 12 أو Rocky Linux 9 (4 vCPU، 8 جيجا RAM، 50 جيجا SSD كحد أدنى).
  • Docker Engine 20.10+ و Docker Compose v2 مثبّتان ويعملان.
  • اسم نطاق يشير إلى IP العام للخادم (لـ TLS).
  • Java 21 (OpenJDK أو Temurin) على الجهاز الذي سيُشغّل الماسح — JVM المضمّنة في خادم Sonar تديرها صورة Docker، لكن sonar-scanner على جانب CI يحتاج إلى JRE خاصة به.
  • المستوى المتوقع: متوسط في Linux، مرتاح مع Docker Compose وتحرير ملفات الإعدادات.
  • الوقت المقدّر: 90 دقيقة للتثبيت الكامل ومسح أول مُتحقق منه.

الخطوة 1 — تحضير معاملات النواة المطلوبة من Elasticsearch المضمّن

يضمّ SonarQube نسخة من Elasticsearch لفهرسة النتائج وتسريع البحث. يفرض Elasticsearch على نواة Linux حدوداً دقيقة على عدد مناطق الذاكرة التي يمكن للعملية تخصيصها؛ بدون هذه الإعدادات، يبدأ الخادم ثم يتوقف في حلقة مع خطأ bootstrap check failed. هذه الخطوة الأولى تطبّق القيم الموصى بها بشكل دائم.

sudo tee /etc/sysctl.d/99-sonarqube.conf <<EOF
vm.max_map_count=524288
fs.file-max=131072
EOF
sudo sysctl --system

sudo tee /etc/security/limits.d/99-sonarqube.conf <<EOF
sonarqube - nofile 131072
sonarqube - nproc 8192
EOF

الملف الأول يُعلن معاملَين على مستوى النواة، والثاني يرفع الحدود لكل مستخدم. بعد sysctl --system، تحقق من القيمة المطبَّقة بـ sysctl vm.max_map_count الذي يجب أن يعرض 524288. إذا كان الجهاز مشتركاً مع خدمات أخرى، فهذه القيم بلا أثر سلبي: ترفع سقفاً ولا تخفض أرضية. على جهاز مختبر مؤقت، يمكن تجنّب هذه التعديلات بتمرير SONAR_ES_BOOTSTRAP_CHECKS_DISABLE=true في ملف compose، لكن هذا الخيار غير مستحسن صراحة من SonarSource في الإنتاج.

الخطوة 2 — كتابة ملف docker-compose.yml

النمط الموصى به يجمع خدمتين: sonarqube (الصورة الرسمية sonarqube:community) وقاعدة postgres:17-alpine. الفصل بين المسؤوليات يسمح بإعادة تشغيل SonarQube دون فقدان البيانات، وأخذ نسخ احتياطية مستقلة للقاعدة، وربط PostgreSQL مُدار خارجياً يوم تبرّر الحمولة ذلك. أنشئ مجلداً مخصصاً وضع فيه الملف التالي.

services:
  sonarqube:
    image: sonarqube:community
    depends_on:
      - db
    environment:
      SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonarqube
      SONAR_JDBC_USERNAME: sonar
      SONAR_JDBC_PASSWORD: ${SONAR_DB_PASSWORD}
    volumes:
      - sonarqube_data:/opt/sonarqube/data
      - sonarqube_logs:/opt/sonarqube/logs
      - sonarqube_extensions:/opt/sonarqube/extensions
    ports:
      - "127.0.0.1:9000:9000"
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
    restart: unless-stopped

  db:
    image: postgres:17-alpine
    environment:
      POSTGRES_USER: sonar
      POSTGRES_PASSWORD: ${SONAR_DB_PASSWORD}
      POSTGRES_DB: sonarqube
    volumes:
      - postgresql_data:/var/lib/postgresql/data
    restart: unless-stopped

volumes:
  sonarqube_data:
  sonarqube_logs:
  sonarqube_extensions:
  postgresql_data:

ثلاث نقاط تستحق الانتباه. أولاً، المنفذ 9000 مُقيَّد صراحة بـ 127.0.0.1 لا بـ 0.0.0.0: فقط الوكيل العكسي المحلي سيصل إلى الخلفية، أبداً ليس من الإنترنت المفتوح. ثانياً، الـ volumes المسمّاة تعزل البيانات الدائمة عن طبقات الصورة، مما يجعل التحديثات الشهرية بلا ألم (docker compose pull && docker compose up -d يكفي). أخيراً، المتغير SONAR_DB_PASSWORD يُقرأ من ملف .env الذي يجب إنشاؤه فوراً.

الخطوة 3 — توليد كلمة المرور وإطلاق الـ stack

يجب أن تكون كلمة المرور طويلة بما يكفي لمقاومة هجوم القاموس وأن تُخزَّن خارج مستودع Git. openssl يوفر مولّداً موثوقاً.

cat > .env <<EOF
SONAR_DB_PASSWORD=$(openssl rand -base64 32 | tr -d '+/=')
EOF
chmod 600 .env

docker compose up -d
docker compose logs -f sonarqube

الإقلاع الأولي يستغرق دقيقتين إلى ثلاث. يعرض السجل أولاً ترحيل مخطط PostgreSQL، ثم تهيئة Elasticsearch، ثم أخيراً سطر SonarQube is operational. إذا دخل الحاوية في حلقة إعادة تشغيل، تحقق من السجلات بـ docker compose logs sonarqube | grep -i bootstrap؛ أخطاء max virtual memory areas تكشف عن فشل الخطوة 1. أوقف بـ Ctrl+C فور ظهور رسالة operational، الخدمة تستمر في الخلفية.

الخطوة 4 — إعداد Nginx كوكيل عكسي مع TLS

كشف المنفذ 9000 مباشرة على الإنترنت سيكون خطأً: لا TLS، لا WAF، لا حماية من DDoS. Nginx محلي يُنهي TLS، ويعيد التوجيه إلى الخلفية، ويسمح بإضافة rate limiting أو IP whitelisting أو مصادقة HTTP basic حسب الحاجة. ثبّت الحزمة ثم أنشئ vhost.

sudo apt install -y nginx certbot python3-certbot-nginx
sudo certbot --nginx -d sonar.example.com --redirect --agree-tos -m admin@example.com -n

يُنشئ Certbot شهادة Let s Encrypt ويديرها تلقائياً، ثم يُدخل كتلة TLS في إعدادات Nginx. يبقى استكمال vhost للإشارة إلى SonarQube مع headers الوكيل الصحيحة، وإلا فإن الروابط الداخلية التي يولّدها التطبيق ستنكسر ولن يعمل WebSocket للتحديث المباشر.

server {
  listen 443 ssl http2;
  server_name sonar.example.com;
  ssl_certificate /etc/letsencrypt/live/sonar.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/sonar.example.com/privkey.pem;
  client_max_body_size 50M;

  location / {
    proxy_pass http://127.0.0.1:9000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
  }
}

التوجيه client_max_body_size 50M يسمح برفع إضافات plugin كبيرة. اختبر التركيب بـ sudo nginx -t ثم أعد التحميل بـ sudo systemctl reload nginx. طلب curl -I https://sonar.example.com/api/system/status يجب أن يُرجع HTTP/2 200 و JSON {"id":"...","status":"UP"}.

الخطوة 5 — أول اتصال وتغيير كلمة مرور admin

الخادم الجديد يقبل بيانات الاعتماد الافتراضية admin / admin. يفرض الخادم فوراً تغيير كلمة المرور هذه عند أول اتصال، إجراء أُدخل ابتداءً من 8.x لتجنّب الخوادم المكشوفة ببيانات افتراضية. افتح https://sonar.example.com في المتصفح، وسجّل الدخول، واختر كلمة مرور طويلة مخزّنة في مدير كلمات مرور للفريق (Bitwarden، 1Password، Vaultwarden مستضاف ذاتياً).

استثمر الجلسة الأولى لفرض المصادقة في Administration → Configuration → Security، وعطّل إنشاء حسابات مجهولة، وأنشئ مشروعاً تجريبياً. لبيئة متعددة الفرق، اضبط فوراً SSO عبر إضافة OIDC الرسمية أو عبر Authentik إذا كانت المؤسسة تستضيف IdP داخلياً.

الخطوة 6 — تشغيل أول مسح لمشروع

الماسح هو ثنائي Java يُوزَّع منفصلاً عن الخادم. يحلّل المشروع محلياً ويدفع النتائج إلى الخادم عبر API. على محطة التطوير أو runner CI، حمّل آخر إصدار من المستودع الرسمي.

cd /opt
sudo curl -sLO https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-8.1.0.6389-linux-x64.zip
sudo unzip sonar-scanner-cli-8.1.0.6389-linux-x64.zip
sudo ln -s /opt/sonar-scanner-8.1.0.6389-linux-x64/bin/sonar-scanner /usr/local/bin/sonar-scanner
sonar-scanner --version

يجب أن يعرض الخرج SonarScanner 7.0.x.xxxx، ونسخة Java المكتشفة (≥ 21)، ونظام التشغيل. إذا فشل الأمر بـ UnsupportedClassVersionError، فالـ JRE المثبت قديم جداً؛ ثبّت Temurin 21 بـ sudo apt install -y temurin-21-jre بعد إضافة مستودع Eclipse Adoptium. على جانب خادم Sonar، أنشئ بعدها رمزاً (token) للمستخدم في My Account → Security → Generate Tokens وانسخه في متغير بيئة.

cd /path/to/project
cat > sonar-project.properties <<EOF
sonar.projectKey=my-project
sonar.projectName=My Project
sonar.projectVersion=1.0
sonar.sources=src
sonar.sourceEncoding=UTF-8
EOF

export SONAR_TOKEN=sqp_xxxxxxxxxxxx
sonar-scanner -Dsonar.host.url=https://sonar.example.com

يستغرق المسح عشرات الثواني لمشروع صغير، وعدة دقائق لمستودع monorepo بـ 100 ألف سطر. في النهاية، يعرض الماسح رابط Quality Gate؛ انقر للوصول إلى لوحة التحليل، التي تجمع bugs، vulnerabilities، code smells، نقاط ساخنة أمنية، وتكرار. غالباً ما يكشف التمرير الأول عشرات النتائج على مشروع قائم — لا تحاول إصلاح كل شيء دفعة واحدة، أعطِ الأولوية لـ blocker و critical في الأمن أولاً.

الخطوة 7 — تعليق نتائج Pull Requests على GitHub أو GitLab

القيمة التشغيلية لـ SonarQube تظهر عندما يتلقى كل pull request تعليقاً تلقائياً بالنتائج الجديدة التي يُدخلها الـ diff. في Community Build، هذه الميزة تمرّ عبر الإضافة الخارجية mc1arke/sonarqube-community-branch-plugin، غير مُصانة من SonarSource لكن مستخدمة على نطاق واسع. تُحمَّل الإضافة من releases الخاصة بها على GitHub وتُوضع في extensions/plugins للخادم.

SONAR_VOL=$(docker volume inspect sonarqube_extensions -f '{{.Mountpoint}}')
PLUGIN_VER=26.4.0
sudo curl -sL -o "${SONAR_VOL}/plugins/sonarqube-community-branch-plugin.jar" \
  https://github.com/mc1arke/sonarqube-community-branch-plugin/releases/download/${PLUGIN_VER}/sonarqube-community-branch-plugin-${PLUGIN_VER}.jar
docker compose restart sonarqube

بعد إعادة التشغيل، تقترح قائمة Administration → DevOps Platform Integrations إضافة اتصال GitHub App أو رمز GitLab. اضبط الاتصال، اربط المشروع بالمستودع البعيد، ثم أعد إطلاق المسح بتمرير معاملات PR إلى الماسح عبر -Dsonar.pullrequest.key=42 -Dsonar.pullrequest.branch=feat/xyz -Dsonar.pullrequest.base=main. سيظهر التعليق التلقائي خلال ثوانٍ على الـ PR، مع المشكلات الجديدة المكتشفة سطراً بسطر.

الخطوة 8 — النسخ الاحتياطي والتحديث

تعيش خادم مُستضاف ذاتياً أو يموت بحسب استراتيجية نسخه الاحتياطي. PostgreSQL يحتوي كل التحاليل التاريخية والمستخدمين والصلاحيات؛ الـ volumes sonarqube_data و sonarqube_extensions تحتوي فهارس Elasticsearch والإضافات. سكربت cron يومي يكفي.

cat > /usr/local/bin/sonar-backup.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
DATE=$(date +%F)
BACKUP=/var/backups/sonar
mkdir -p "$BACKUP"
docker compose -f /opt/sonar/docker-compose.yml exec -T db \
  pg_dump -U sonar sonarqube | gzip > "$BACKUP/sonarqube-${DATE}.sql.gz"
find "$BACKUP" -mtime +14 -delete
EOF
chmod +x /usr/local/bin/sonar-backup.sh
echo '15 3 * * * root /usr/local/bin/sonar-backup.sh' | sudo tee /etc/cron.d/sonar-backup

السكربت يدوّن القاعدة كل ليلة عند 3:15، يحتفظ بـ 14 يوماً من السجل، ويستخدم set -euo pipefail ليفشل عند أول خطأ. للتحديث الشهري لـ SonarQube، خذ أولاً نسخة احتياطية يدوية، ثم docker compose pull && docker compose up -d. ينطلق ترحيل المخطط تلقائياً عند بدء الحاوية الجديدة؛ إذا فشل، استعد الدامب بـ gunzip -c sonarqube-2026-05-06.sql.gz | docker compose exec -T db psql -U sonar sonarqube.

الأخطاء الشائعة

العَرَض السبب الحل
حاوية في حلقة إعادة تشغيل مع bootstrap checks failed vm.max_map_count لم يُطبَّق تحقق sysctl vm.max_map_count، أعد الخطوة 1 وأعد تشغيل خدمة Docker
الواجهة متاحة لكن بيضاء، JS console مليء بأخطاء mixed content الـ header X-Forwarded-Proto ناقص على جانب Nginx أضف proxy_set_header X-Forwarded-Proto https; وأعد التحميل
الماسح يفشل بـ UnsupportedClassVersionError JRE 8 أو 11 بينما 21 مطلوبة منذ 2024 ثبّت Temurin 21 وصدّر JAVA_HOME
Quality Gate أحمر دائماً على المشاريع القديمة وضع new code غير مضبوط، كل الدين التاريخي يثقل Project Settings → New Code: حدد مرجعاً من فرع أو تاريخ، ركّز على الكود الجديد
تعليق PR لا يُشغَّل قيمة sonar.pullrequest.key خاطئة على جانب CI تحقق من تمرير متغير بيئة PR للماسح بشكل صحيح
بطء متزايد بعد بضعة أشهر فهرس Elasticsearch مشبع Administration → System → Background Tasks: شغّل Project Reindex، زِد SONAR_WEB_JAVAOPTS=-Xmx2g

الأسئلة الشائعة

هل يدعم SonarQube Community Build التحليل التفاضلي على الفروع غير main؟ ليس بشكل أصيل: تحليل الفروع وتعليق pull request ميزتان من إصدار Developer (مدفوع). للحصول عليهما مجاناً، يعتمد النظام على إضافة mc1arke/sonarqube-community-branch-plugin غير المصانة من SonarSource لكن مستخدمة على نطاق واسع. وإلا، فإن وضع main only يبقى وظيفياً لمتابعة الدين الإجمالي.

كم من الذاكرة JVM يجب تخصيصها في الإنتاج؟ الافتراضي -Xmx2g على web server و -Xmx2g على compute engine يكفي حتى 10 مليون سطر كود مُحلَّل. ما وراء ذلك، ارفع إلى 4 جيجا عبر SONAR_WEB_JAVAOPTS و SONAR_CE_JAVAOPTS. راقب الاستهلاك الفعلي في System Info.

هل يمكن استبدال PostgreSQL بـ MySQL أو MariaDB؟ لا، أُزيل دعم MySQL في إصدار 7.9 ولم تُدعم MariaDB رسمياً أبداً. PostgreSQL ≥ 13 إلزامي؛ الإصدار 17 (الصادر في سبتمبر 2024، مدعوم من المجتمع حتى 2029) موصى به للتنصيبات الجديدة.

هل تعمل الإضافات الخارجية في Community Build؟ نعم، شريطة أن تستهدف API خادم متوافقة. تحقق من مصفوفة توافق الإضافة قبل التثبيت. ميزة Marketplace المدمجة تتولى هذا التحقق ذاتياً.

كيف نُصدّر النتائج إلى DefectDojo؟ SonarQube لا يُنتج SARIF بشكل أصيل في خرج التحليل — خيار sonar.sarifReportPaths يعمل بالعكس، أي لاستيراد SARIF إلى Sonar. لدفع نتائج Sonar إلى DefectDojo، استخدم REST API الخاص بـ Sonar (GET /api/issues/search بصيغة JSON) ثم استورد في DefectDojo عبر /api/v2/import-scan/ مع نوع الماسح Sonarqube API Import الذي يُحلّل هذه الصيغة أصلياً.

دروس ذات صلة

  • كتابة قواعد Semgrep مخصصة: تركيب pattern، taint analysis، autofix — مكمّل خفيف لـ SonarQube للقواعد الخاصة جداً بـ stack الخاص بك.
  • دمج SAST + SCA + DAST في خط أنابيب GitLab CI 18 خطوة بخطوة — لربط تعليق PR من SonarQube على GitLab.

🔝 العودة إلى الدليل الرئيسي: Pipeline SAST DAST SCA في 2026: معمارية، أدوات، وتكامل CI/CD

قراءات موصى بها

مقالات ذات صلة

Sponsoriser ce contenu

Cet emplacement est à vous

Position premium en fin d'article — c'est l'instant où les lecteurs sont le plus engagés. Réservez cet espace pour votre marque, votre formation ou votre offre.

Recevoir nos tarifs
Publicité