اذهب إلى المحتوى

البحث في الموقع

المحتوى عن 'nginx'.

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المحتوى


التصنيفات

  • الإدارة والقيادة
  • التخطيط وسير العمل
  • التمويل
  • فريق العمل
  • دراسة حالات
  • التعامل مع العملاء
  • التعهيد الخارجي
  • السلوك التنظيمي في المؤسسات
  • عالم الأعمال
  • التجارة والتجارة الإلكترونية
  • نصائح وإرشادات
  • مقالات ريادة أعمال عامة

التصنيفات

  • مقالات برمجة عامة
  • مقالات برمجة متقدمة
  • PHP
    • Laravel
    • ووردبريس
  • جافاسكربت
    • لغة TypeScript
    • Node.js
    • React
    • Vue.js
    • Angular
    • jQuery
    • Cordova
  • HTML
  • CSS
    • Sass
    • إطار عمل Bootstrap
  • SQL
  • لغة C#‎
    • ‎.NET
    • منصة Xamarin
  • لغة C++‎
  • لغة C
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • لغة Rust
  • برمجة أندرويد
  • لغة R
  • الذكاء الاصطناعي
  • صناعة الألعاب
  • سير العمل
    • Git
  • الأنظمة والأنظمة المدمجة

التصنيفات

  • تصميم تجربة المستخدم UX
  • تصميم واجهة المستخدم UI
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب GIMP
    • كريتا Krita
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • نصائح وإرشادات
  • مقالات تصميم عامة

التصنيفات

  • مقالات DevOps عامة
  • خوادم
    • الويب HTTP
    • البريد الإلكتروني
    • قواعد البيانات
    • DNS
    • Samba
  • الحوسبة السحابية
    • Docker
  • إدارة الإعدادات والنشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
    • ريدهات (Red Hat)
  • خواديم ويندوز
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • شبكات
    • سيسكو (Cisco)

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • استسراع النمو
  • المبيعات
  • تجارب ونصائح
  • مبادئ علم التسويق

التصنيفات

  • مقالات عمل حر عامة
  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • العمل الحر المهني
    • العمل بالترجمة
    • العمل كمساعد افتراضي
    • العمل بكتابة المحتوى

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
    • بريستاشوب
    • أوبن كارت
    • دروبال
  • الترجمة بمساعدة الحاسوب
    • omegaT
    • memoQ
    • Trados
    • Memsource
  • برامج تخطيط موارد المؤسسات ERP
    • تطبيقات أودو odoo
  • أنظمة تشغيل الحواسيب والهواتف
    • ويندوز
    • لينكس
  • مقالات عامة

التصنيفات

  • آخر التحديثات

أسئلة وأجوبة

  • الأقسام
    • أسئلة البرمجة
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات

التصنيفات

  • كتب ريادة الأعمال
  • كتب العمل الحر
  • كتب تسويق ومبيعات
  • كتب برمجة
  • كتب تصميم
  • كتب DevOps

ابحث في

ابحث عن


تاريخ الإنشاء

  • بداية

    نهاية


آخر تحديث

  • بداية

    نهاية


رشح النتائج حسب

تاريخ الانضمام

  • بداية

    نهاية


المجموعة


النبذة الشخصية

  1. كان ختام المقالة السّابقة قولُنا أن بروتوكول HTTP يدير التّفاعل بين عميل وخادوم، وقد شرحنا فكرة ترويسات HTTP. سيكون لدينا الكثير مما يُقال عن هذه الترويسات في أجزاء تالية من هذه السّلسلة، فهذه الترويسات تؤثّر في التّفاعل بين الطّرفين وفي أداء الموقع. أمّا اليوم، فسنطّلع على جانب لا يقلّ أهمّيّة عن التّرويسات، وهو رموز إجابات HTTP. نزهة في الشوارع خرجت ذات صباح قاصدًا مقهى لأقرأ كتابًا، لكنّني وجدت المقهى مُغلقًا حينها، وقد كُتب على لوحة على الباب أنّ احتفالًا يُقام خلال هذا الأسبوع، ولذلك فإنّ المقهى سينتقل مؤقتًا ليُقدّم القهوة في شاحنة الطّعام (التي سمّوها "307") قرب النهر. ذهبت إلى ذلك المكان واستمتعت بشرب القهوة. قرّرت بعدئذٍ التجوّل في مكتبتي المفضّلة في المدينة، فوجدتها مُغلقةً كذلك، إلّا أنّني رأيت لوحة على الباب تقول أن المكتبة ستتوسع ولذلك انتقلت بشكل دائم إلى مبنى جديد في 301 شارع برنرز-لي. لم يُزعجني ذلك، فالمكان قريب. ذهبت إلى هناك فاستقبلني الموظّفون بالتّرحاب: "200 سلامة!". حسنًا، أنا أبالغ قليلًا، لكنّك فهمتني! في طريقي إلى البيت، وجدت متجرًا مهجورًا غطّى الغبار أبوابه في 410 شارع برنرز-لي، وقد أُلصقت ورقةٌ على الباب تقول أنّ صاحب المحلّ تقدّم بطلب إشهار الإفلاس واضطّر إلى إغلاق المتجر، إلى الأبد. وكأنّ العجائب لم تنتهِ اليوم، إذ رأيت في نهاية 500 شارع برنرز-لي مبنى من 4 طوابق وقد انهار بالكامل. ما الذي حدث هنا؟! لم يكن يومي سيئًا بالمجمل، لذا قرّرت أن أكمل يومي بكتابة مقال عن رموز HTTP الّتي تُرسلها الخواديم إلى العملاء الّذين يرسلون الطّلبات. صياغة جواب HTTP وسطر الحالةتطرّقنا في المقال السّابق إلى السّطر الأول من صيغة الطّلبات الّتي يُرسلها العميل (بما في ذلك أفعال HTTP). وسنركّز الآن على السّطر الأول من رسالة الجواب الّتي تصل من الخادوم، ومعاني الرّموز المختلفة الّتي تظهر في هذا السّطر. لاحظ التّشابه بين نوعي الرّسائل (الطّلبات والإجابات). فكما ينصّ توثيق الإصدارة 1.1 من HTTP: إما إن تكون رسالة HTTP طلبًا من العميل إلى الخادوم أو جوابًا من الخادوم للعمل. من حيث الصّياغة، لا يختلف نوعا الرّسائل إلى في السّطر الأوّل، والذي إمّا أن يكون سطر طلب (للطلبات) أو سطر حالة (للإجابات)، وفي خوارزميّة تحديد طول متن الرّسالة (القسم 3.3). يُدعى السّطر الأول في الجواب إذًا سطر الحالة. يبدأ السّطر بإصدارة بروتوكول HTTP ثمّ مسافة ثم رمز من ثلاثة أرقام، ثم مسافة ثمّ جملة تشرح الرّمز، كهذا المثال: HTTP/1.1 200 OKالجملة القصيرة الأخيرة غير إلزامية وعلى العملاء تجاهلها، ولا ينبغي أن يستخدمها برنامج بغرض تفسير الجواب. لنطّلع الآن على بعض أكثر رموز الحالة شيوعًا وما يعنيه كلّ رمز منها. رموز الحالة في HTTP200، كلّ شيء على ما يرام! في كلّ مرّة يريد شخصٌ ما زيارة الصّفحة الرئيسيّة لموقع Opera، يُرسل العميل طلبًا إلى http://www.opera.com/ برسالة مثل هذه: GET / HTTP/1.1 Host: www.opera.com Accept-Language: fr User-Agent: BrowseAndDream/1.0يُحلّل الخادوم الرّسالة الّتي وصلته من العميل ويُرسل جوابًا بناء على ما فهمه من الرابط والترويسات. وكما ذكرنا في المقالتين السّابقتين، يكون الهدف الأهمّ هو إدارة التّواصل بين الطّرفين بما يحقّق أقصى فائدة لكليهما. إن فهم الخادوم الرّسالة، فإنّه يرسل رسالة تبدأ بـ200 OK، أي أنّ كلّ شيء على ما يُرام. تحوي الرسالة بضع ترويسات إجابة ثمّ محتوى الصّفحة، والّذي قد يختلف بناءً على ترويسات الطّلب، فلا إجابة مُطلقة. فكما في كل تفاوض، يجري حوارٌ بين الطّرفين للوصول إلى أفضل تسوية. فيما يلي مثالٌ عن إجابة على الطّلب السّابق: HTTP/1.1 200 OK Date: Fri, 24 Aug 2012, 13:56:44 GMT307، انتقلتُ مؤقّتًا إلى مكان آخر يمكن للخادوم أن يجيب العميل برسالة تبيّن أنّ المحتو قد انتقل مؤقتًا إلى مكان آخر. ويفيد هذا عندما تريد إعادة توجيه العميل إلى صفحة مُعيّنة لفترة قصيرة. افترض مثلًا موقعًا يُعطي توقّعات الطقس لتاييبي، وقد شبّ إعصار هائل مؤخّرًا فيها. سيكون من المفيد إعلام المُستخدمين بوقوع هذا الإعصار حتى هدوئه. قد يكون الطّلب مثل هذا: GET /taiwan/weather/today HTTP/1.1 Host: meteo.example.orgقد يرغب الخادوم بإجابة العميل قائلًا: "سأنقلك إلى صفحة أخرى تُعطيك معلومات مفصّلة عن الأزمة الحاليّة في تاييبي". قد تبدو الإجابة مثل هذه: HTTP/1.1 307 Temporary Redirect Date: Fri, 24 Aug 2012, 13:56:44 GMT Location: http://meteo.example.org/taiwan/weather/crisisيتبع المتصفح عادةً الوجهة الجديدة المذكورة في سطر Location. يمكن أن يطلب الخادوم إعادة التّوجّه إلى نطاق آخر على الويب. وحالما تنتهي الأزمة، يمكن للخادوم إزالة إعادة التّوجيه. ينبغي ألّا يتذكّر العميل إعادة التّوجيه للأبد. فهذا مُهمّ في حالة الإشارات المرجعيّة وسجل التصفّح. من الممكن تصميم برنامج يُدير عمليّات إعادة التّوجيه هذه بطريقة مُفيدة. لا يرى المُستخدم إعادة التّوجيه في معظم المتصفّحات، ولكن من الممكن إرسال متن مع جواب إعادة التّوجيه يعرض على المستخدم رسالة تحوي رابطًا للمكان الجديد يُسمح للمُستخدم بنقره. 301، تغيّر العنوان بشكل دائم عند إدارة المعلومات على موقع ويب، قد نحتاج إلى إعلام العميل (ومستخدميه) أن الصّفحة المطلوبة قد انتقلت بشكل دائم. ففي الشّركات، يُعاد تنظيم الأقسام أحيانًا بعد الاتّحاد مع شركة أخرى أو عند تغيّر الأولويّات. لنفترض مثلًا أن وحدة الآلات الكهربائيّة في شركة تقنية قد ضُمَّت إلى قسم الإلكترونيّات. وعندها يمكن إعادة توجيه عميل يطلب: GET /section/electromech/about HTTP/1.1 Host: inc.example.comإلى: HTTP/1.1 301 Moved Permanently Date: Fri, 24 Aug 2012, 13:56:44 GMT Location: http://inc.example.com/section/electronic/aboutالفرق بين الرمز 307 الّذي شرحناه في الفقرة السّابقة، والرّمز 301، أنّ التّغيّر في العنوان دائم في حالة الرّمز الثّاني، وهي رسالة واضحة من الخادوم للعميل تطلب منه أن يُغيّر الإشارات المرجعيّة المحفوظة لديه إلى العناوين الجديدة. يمكن للمتصفّح تنفيذ ذلك من تلقاء نفسه أو بعد استشارة المستخدم. لإعادة توجيه الروابط القديمة فائدتان مُباشرتان. الأولى هي كسب ثقة المستخدمين بموقعك، بأن تُبدي اهتمامك بالمُحافظة على المعلومات الّتي تستضيفها. والثّانية هي استقرار الموارد، فالمواقع الّتي تُعرف بمحافظتها على الرّوابط تكون أكثر احتمالًا لأن تُشير إليها مواقع أخرى على المدى البعيد، ممّا يزيد ترتيب الموقع في مُحرّكات البحث. 410، وداعًا يا صديقي العزيز! تحتاج بعض المواقع أحيانًا إلى إبلاغ العميل باختفاء المعلومات الّتي كانت موجودة على رابط مُعيّن للأبد. وقد يكون لهذا مُبرّراته. نحن نعلم أن الروابط الجيّدة لا تتعطّل؛ ولكنّ الرّمز 410 Gone هو الوسيلة الوحيدة المناسبة لتعطيلها. لنكن أكثر دقّة: هذا الرّمز هة طريقة لإخبار المستخدمين أن المحتوى الّذي كان موجودًا من قبل على هذا الرابط قد حُذِفَ عمدًا. وهذا معناه أن الخادوم يطلب من العُملاء الّذي يقصدون هذا الرّابط ألّا يتذكّروه. ففي متصفّح يستخدم الإشارات المرجعيّة وسجّلات التّصفّح، يُعتبر هذا الرّمز إبلاغًا للمتصفّح بسلامة حذف هذا الرّابط. افترض شبكة اجتماعيّة يُطلب فيها الوصول إلى صفحة مُستخدم: GET /people/jeanpaulsartres HTTP/1.1 Host: socialnetwork.example.comقرّر المستخدم أن يُغادر شبكتك الاجتماعيّة ويُغلق حسابه، قد تُريد أن تُبلغ غيره من المستخدمين الّذين يطلبون صفحته من سجلّ المتصفّح أو إشاراته المرجعيّة: HTTP/1.1 410 Gone500، يا للمصيبة! قد يتعذّر على الخادوم إجابة الطّلب لسبب مجهول. لا يتدخّل HTTP على الإطلاق في تفاصيل عمل الموقع، مثل طريقة تخزين قواعد البيانات على الخادوم، أو كيف يجلب الخادوم البيانات ويُعالجها. ربّما توقّف الطّلب عند برنامج مُعيّن على الخادوم ولم يصل الجواب، وعندها يُبلغ الخادوم العميل ومستخدمه عن وقوع خطأ ما غير معروف بجواب مثل هذا: HTTP/1.1 500 Internal Server Errorاستخدام سطور الحالة في الإجابات الّتي تُرسلها الخواديمعند تصميم نظام لإدارة المحتوى، يكون من الضّروري فصل الطّبقات بصورة موارد وروابط إلى هذه الموارد، فهذا مُفيد عند إجابة طلبات العملاء بالمعلومات الصّحيحة، وتقديم المحتوى للبرامج أو للبشر هو شيء جوهريّ في صفة الخواديم. ولأنّ المعلومات تتغيّر وتتطوّر،فإنّ تصميم الخواديم بما يراعي هذه النّقطة يُعطيها مرونة أكبر. لا تهدف هذه السّلسلة إلى شرح تفاصيل تطبيق إجابات الخواديم من النّاحية البرمجيّة، ولكنّنا سنستعرض مثالين يُفيدان كنقطتي انطلاق، على الرّغم من أنّهما قد لا يُفيدان في حالة المواقع الضّخمة الّتي تضمّ آلاف الرّوابط. إعادة التّوجيه في Apacheفي حال أردت إعادة توجيه http://inc.example.com/section/electromech/about إلى http://inc.example.com/section/electronic/about، يمكن إضافة ملف .htaccess في جذر الموقع يحوي التّعليمات التّالية: RewriteEngine On RewriteBase / RewriteRule ^/section/electromech/about /section/electronic/about [L,R=301]مُلاحظة: هنالك طرق أخرى لتنفيذ هذا الغرض، كاستخدام httpd.conf أو قواعد البيانات أو من خلال النّصوص البرمجيّة... إلخ. واختيار الطّريقة المناسبة يعتمد على تصميم النّظام. إعادة التّوجيه في nginxخادوم Nginx هو الآخر شائع الاستخدام، وخصوصًا على شبكات توفير المحتوى (CDNs). يمكن إعادة كتابة المثال السّابق لاستخدامه مع nginx: server { listen 80; server_name inc.example.com; rewrite ^/section/electromech/about http://inc.example.com/section/electronic/about permanent; }تصنيف رموز HTTPتعرّفنا على بضع رموز HTTP فيما سبق، ولكنّها أكثر من ذلك، وبعض هذه الرّموز ذائع الصّيت مثل 404 Not Found، وبعضها مغمور لا يُرى كثيرًا. وفي كلا الحالتين يمكن الاستعانة بالرّقم الأوّل للرّمز لأخذ فكرة عن معناه، كون هذا الرقم يُشير إلى العائلة الّتي ينتمي إليها الرّمز: 1xx (بيان): وصل الطّلب، وتجري مُعالجته.2xx (نجاح): وصل الطّلب وفُهم وقُبل.3xx (إعادة توجيه): يُطلب إجراء تالٍ لإكمال الطّلب.4xx (خطأ من جهة العميل): صياغة الطّلب خاطئة أو يتعذّر تحقيقه.5xx (خطأ من جهة الخادوم): فشل الخادوم في تحقيق طلب يبدو سليمًا.الخلاصةإلى هنا نكون قد وصلنا إلى نهاية دراستنا لرموز حالة HTTP. أحثّك على الاطّلاع على كلّ رمز والتّعرّف على فائدته. لبعض هذه الرموز تأثيرات خاصّة على التّخزين المؤقّت وعلى متن رسالة HTTP؛ سنُلقي نظرةً على التّخزين المؤقت لاحقًا. تذكّرتُرسل الخواديم رموز حالة HTTP لتزويد العميل بمعلومات سريعة عن الجواب.تؤثّر رموز HTTP في التّخزين المؤقّت ومُعالجة الرّوابط من جهة العميل.تُصنّف رموز HTTP ضمن عدّة مجموعات.ترجمة (بشيء من التّصرّف) لمقال HTTP: Response Codes لصاحبه Karl Dubosy.
  2. مقدمة Node.js هو بيئة عمل مفتوحة المصدر لجافا سكريبت تعمل وقت التشغيل لبناء تطبيقات الخادم والشبكات بسهولة. تعمل المنصة على لينكس, OS X, FreeBSD وويندوز. يمكن تشغيل تطبيقات Node.js من سطر الأوامر، ولكن سنركز على تشغيلها كخدمة، بحيث سيتم إعادة تشغيلها تلقائيًا في حال حدوث فشل أو في حال إعادة تشغيل الحاسوب، كما يمكن استخدامها بأمان في بيئة الإنتاج. في هذا الدرس، سوف نغطّي موضوع إنشاء بيئة عمل Node.js جاهزة للإنتاج على خادم Debian 8. هذا الخادم سيشغّل تطبيقًا لـ Node.js سيكون مُدارًا بواسطة PM2، ويوفر للمستخدمين وصولًا آمنًا إلى التطبيق عبر Nginx reverse proxy. المتطلبات الأساسية يفترض هذا الدليل أن لديك خادم Debian 8، بصلاحيات مستخدم غير جذري non-root user ومع امتيازات sudo. ونفترض كذلك أن لديك اسم نطاق يشير إلى عنوان IP العام للخادم. دعونا نبدأ بتثبيت بيئة العمل Node.js على خادمك. تثبيت Node.js سوف نقوم بتثبيت أحدث إصدارات Node.js المدعومة على المدى الطويل، وذلك باستخدام أرشيف الحزمة NodeSource. أولًا، تحتاج إلى تثبيت NodeSource PPA لأجل الوصول إلى محتوياته. تأكد من أنك في المجلد الأساسي home directory، وقم باستخدامcurl للحصول على برنامج التثبيت النصي من مستودعات 6.X Node.js: cd ~ curl -sL https://deb.nodesource.com/setup_6.x -o nodesource_setup.sh يمكنك فحص محتويات هذا النص البرمجي بواسطةnano (أو محرر النصوص المفضل لديك): nano nodesource_setup.sh وقم بتشغيل النص البرمجي عقب sudo: sudo bash nodesource_setup.sh سيتم إضافة PPA إلى إعداداتك وسوف يتم تحديث حزمتك المحلية المُخزنة تلقائيًا. بعد تشغيل برنامج التنصيب من nodesource، يمكنك تثبيت حزمة Node.js بنفس الطريقة التي اتبعتها أعلاه: sudo apt-get install nodejs الحزمة nodejs تحتوي رُقامة nodejs (nodejs binary ) إضافة إلى npm، لذلك لا تحتاج إلى تثبيت npm بشكل منفصل. ولكن لكي تعمل بعض حُزم npm (مثل تلك التي تتطلب ترجمة التعليمات البرمجية من المصدر)، فستحتاج إلى تثبيت الحزمة build-essential: sudo apt-get install build-essential لقد تم تثبيت بيئة العمل Node.js، وصارت جاهزة لتشغيل تطبيقاتنا! لذلك دعونا الآن نكتب تطبيقًا بـ Node.js إنشاء تطبيق Node.js سنكتب تطبيق Hello World والذي سيُرجع ببساطة الجملة “Hello World” لكل طلبات HTTP. هذا تطبيق تعليمي بسيط من شأنه أن يساعدك على التعامل مع Node.js، يمكنك بعد ذلك استبداله بتطبيقاتك الخاصة. فقط تذكر أن تعدّل تطبيقك لكي يُصغي إلى منافذ وعناوين IP المناسبة. الشيفرة البرمجية لـ Hello World أولًا، قم بإنشاء وفتح تطبيق Node.js لأجل التحرير. في هذا الدرس، سوف نستخدم nano لتحرير تطبيق تعليمي يُسمّى hello.js: cd ~ nano hello.js أدرج التعليمات البرمجية التالي في الملف. يمكنك استبدال المنفذ 8080، في كلا الموقعين (تأكد من استخدام منفذ غير أساسي non-admin، أي 1024 أو أكبر): hello.js #!/usr/bin/env nodejs var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n'); }).listen(8080, 'localhost'); console.log('Server running at http://localhost:8080/'); الآن احفظ واخرج. هذا التطبيق سيُصغي إلى العنوان المحدد(localhost) والمنفذ (8080)، ويُرجع “Hello World” مع كود النجاح (HTTP success) يساوي200 . وبما أننا نُصغي على localhost، فإن العملاء البعيدين remote clients لن يكونوا قادرين على ربط الاتصال بتطبيقنا. اختبار التطبيق لتتمكن من اختبار التطبيق، اجعل hello.js ملفًّا تنفيذيًا: chmod +x ./hello.js وقم بتشغيله هكذا: ./hello.js Output Server running at http://localhost:8080/ لاختبار التطبيق، قم بفتح جلسة على المطراف terminal على الخادم الخاص بك، ثم اربط االاتصال بـlocalhost بواسطة curl: curl http://localhost:8080 إن رأيت المخرجات التالية، فهذا يعني أن التطبيق يعمل بشكل صحيح ويُصغي للعنوان والمنفذ الصحيحين: Output Hello World إن لم ترى المخرجات المناسبة، تأكد من أن تطبيق Node.js قيد التشغيل، وأنه يٌصغي للعنوان والمنفذ الصحيح. بمجرد أن تتيقن بأنه يعمل، أوقف التطبيق (إذا لم تكن قد فعلت من قبل) عن طريق الضغط على Ctrl + C. تثبيت PM2 سنقوم الآن بتثبيتPM2 ، والذي هو مدير العمليات process manager لتطبيقات Node.js. يوفر PM2 وسيلة سهلة لإدارة وإخفاء daemonize التطبيقات (أي تشغيلها كخدمة في الخلفية.( سوف نستخدم npm، وهي حزمة لإدارة وحدات Nodeالتي تُثبّت مع Node.js، لتثبيت PM2 على الخادم استخدم هذا الأمر: sudo npm install -g pm2 الخيار -g يقول لـnpm أنّ عليه تثبيت الوحدة بشكل كلي globally، بحيث تكون متاحة على نطاق النظام كله. إدارة التطبيق عبر PM2 PM2 بسيط وسهل الاستخدام. سوف نغطي فيما يلي بعض استخداماته الأساسية. بدء التطبيق أول شيء سنفعله هو استخدام التعليمة pm2 start لبدء تشغيل التطبيق hello.js في الخلفية: pm2 start hello.js هذا يضيف أيضًا تطبيقك إلى لائحة عمليات PM2، والتي تُحدَّث في كل مرة تبدأ تشغيل التطبيق: Output [PM2] Spawning PM2 daemon [PM2] PM2 Successfully daemonized [PM2] Starting hello.js in fork_mode (1 instance) [PM2] Done. ┌──────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────────────┬──────────┐ │ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │ ├──────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────────────┼──────────┤ │ hello │ 0 │ fork │ 3524 │ online │ 0 │ 0s │ 21.566 MB │ disabled │ └──────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────────────┴──────────┘ Use `pm2 show <id|name>` to get more details about an app كما ترى، يُعيّن PM2 تلقائيا اسم التطبيق (بناءً على اسم الملف دون الامتداد .js). ورقم تعريفPM2 . كما يحفظ PM2 معلومات أخرى، من قبيل معرّف العمليةPID ، وحالته الراهنة، واستخدام الذاكرة. سيتم إعادة تشغيل التطبيقات التي تعمل تحت PM2 تلقائيا إذا تعطل التطبيق أو أُوقف، لكي نجعل التطبيق يشتغل تلقائيًا عند بدء أو إعادة التشغيل ينبغي اتخاذ خطوة إضافية. ولحسن الحظ، يوفّرPM2 وسيلةً سهلةً للقيام بذلك، وهي التعليمة الفرعية startup. تقوم التعليمة الفرعية startup بإنشاء وإعداد برنامج نصي لإطلاق PM2 والعمليات المُدارة من قبله عند بدء تشغيل الخادم. يجب عليك أيضًا تحديد المنصة الذي تعمل عليها، والتي هي Ubuntu، في حالتنا: pm2 startup system السطر الأخير من المخرجات سوف يتضمّن تعليمة عليك تشغيلها بامتيازات المستخدم الجذري superuser. Output [PM2] You have to run this command as root. Execute the following command: sudo env PATH=$PATH:/usr/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/Sammy قم بتشغيل التعليمة التي تم إنشاؤها (مماثلة للمخرجات الملوّنة أعلاه، ولكن استخدم اسم المستخدم الخاص بك بدلًا من sammy) لجعل PM2 يبدأ مع بداية التشغيل (استخدم التعليمة من المخرجات التي لديك): sudo env PATH=$PATH:/usr/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy هذا سوف يُنشئ systemd unit والتي ستُشغّل PM2 للمستخدم خاصتك عند بدء التشغيل. عينة pm2 هذه ستشغّل بدورهاhello.js . يمكنك التحقق من حالة الوحدة systemd بواسطة systemctl: systemctl status pm2 لمزيد من التفاصيل عن systemd، طالع مقال أساسيات Systemd: العمل مع الخدمات، الوحدات Units، واليوميات Journal استخدامات أخرى لـ PM2 (اختياري) يوفرPM2 العديد من التعليمات الفرعية التي تسمح لك بإدارة أو البحث عن معلومات حول تطبيقاتك. لاحظ أن تشغيل PM2 دون أي معاملات arguments سيؤدي إلى عرض صفحة مساعدة تتضمن أمثلة على الاستخدام والتي تغطي استخدامات PM2 بتفاصيل أكثر مما هو موجود في هذا الدرس. يمكنك إيقاف التطبيق بهذه التعليمة (حدّد App name أو id الخاص بـPM2 ): pm2 stop app_name_or_id يمكنك إعادة تشغيل التطبيق بهذه التعليمة (حدّد App name أو id الخاص بـPM2 ): pm2 restart app_name_or_id ويمكن أيضًا مطالعة قائمة من التطبيقات المُدارة حاليًا من قبل PM2 بالتعليمة الفرعيةlist . pm2 list يمكنك الحصول على مزيد من المعلومات حول تطبيق معين باستخدام التعليمة الفرعية info (حدّد App name أو id الخاص بـPM2 ): pm2 info example يمكن الوصول إلى مراقب عمليات PM2 بالتعليمة الفرعية monit. سيتم عرض حالة التطبيق ووحدة المعالجة المركزية CPU واستخدام الذاكرة: pm2 monit الآن وبعد أن قمنا بتشغيل Node.js وإدارته بواسطة PM2، دعونا نبدأ إعداد الوكيل العكسيreverse proxy . إعداد Nginx ليكون الوكيل العكسي للخادم Reverse Proxy Server الآن وبعد أن بدأ تطبيقك يشتغل ويُصغي إلى المضيف المحلي localhost، تحتاج إلى إعداد وسيلة ليتمكن المستخدمون من الوصول إليه. سوف نقوم بإنشاء خادم Nginx كوكيل عكسي لهذا الغرض. في هذا الدرس ستتعلم كيفية إعداد خادم Nginx من الصفر. إن سبق وقمت بإعداد خادم Nginx، فيمكنك الاكتفاء بنسخ location في server block من اختيارك (تأكد من أن المحل location لا يتداخل مع المحتوى الموجود على الخادم). أولًا، قم بتثبيت Nginx باستخدام apt-get: sudo apt-get install nginx الآن افتح ملف الإعدادات الافتراضي لـ server block لأجل تحريره: sudo nano /etc/nginx/sites-available/default احذف كل ما هو موجود في الملف وقم بإدراج الإعدادات التالية. تأكد من استبدال اسم النطاق خاصتك في الموجّه server_name. بالإضافة إلى ذلك، قم بتغيير المنفذ (8080) إن كان تطبيقك مُعدًّا للإصغاء إلى منفذ آخر: /etc/nginx/sites-available/default server { listen 80; server_name example.com; location / { proxy_pass http://localhost:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } } هذا سيقوم بإعداد الخادم بحيث يرد على الطلبات requests على مستوى الجذر root. إن افترضنا مثلًا أن خادمنا مُتوفر فيexample.com ، فإن الدخول إلى http://example.com/ عبر متصفح الإنترنت سيبعث الطلب إلى hello.js الذي يُصغي إلى المنفذ 8080 في المضيف المحلي. يمكنك إضافة كتل محل location blocks إضافية لنفس كتلة الخادم server block لإتاحة إمكانية الوصول إلى التطبيقات الأخرى على نفس الخادم. على سبيل المثال، إن كنت تُشغّل تطبيقًا آخرًا لـ Node.js على المنفذ 8081، يمكنك إضافة كتلة المحل location block التالية للسماح بالوصول إليها عبر http://example.com/app2 : Nginx Configuration — Additional Locations location /app2 { proxy_pass http://localhost:8081; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; } بمجرد الانتهاء من إضافة كتل المحل لتطبيقاتك، قم بالحفظ واخرج. تأكد من أنك لم ترتكب أي أخطاء نحوية syntax errors أثناء الكتابة: sudo nginx –t بعد ذلك، قم بإعادة تشغيل Nginx: sudo systemctl restart nginx بعد ذلك، قم بترخيص المرور لـ Nginx عبر جدار حماية، إن كان متاحًا. إذا كنت تستخدم ufw ، يمكنك استخدام التعليمة التالية: sudo ufw allow 'Nginx Full' يمكنك بواسطةufw التحقق من الحالة باستخدام التعليمة التالية: sudo ufw status إذا كنت تستخدم IPTables بدلًا من ذلك، يمكنك ترخيص المرور لـ Nginx باستخدام التعليمة التالية: sudo iptables -I INPUT -p tcp -m tcp --dport 80 -j ACCEPT يمكنك دائمًا التحقق من حالة IPTables باستخدام التعليمة التالية: sudo iptables –S على افتراض أن تطبيق Node.js الخاص بك قيد التشغيل، وأن إعدادات Nginx وتطبيقاتك صحيحة، فسيكون بإمكانك الآن الوصول إلى تطبيقك عبر وكيل عكسي لـ Nginx. جرّب ذلك بنفسك عن طريق الدخول إلى عنوان الخادم الخاص بك (الـ IP أو اسم النطاق) الخلاصة تهانينا! لقد نجحت في جعل تطبيق Node.js الخاص بك يعمل في خلفية وكيل عكسي لـ Nginx على خادم Debian 8. إعدادات الوكيل العكسي هاته مرنة بما فيه الكفاية لتمكين المستخدمين من الوصول إلى التطبيقات الأخرى أو محتويات صفحات الأنترنت الثابتة التي تريد مشاركتها. حظًا سعيدًا في عملك على Node.js. ترجمة -وبتصرّف- للمقال How To Set Up a Node.js Application for Production on Debian 8 لصاحبته Lisa Tagliaferri
  3. حاوية لينكس (Linux container) هي تجميع لمجموعة من عمليات تكون منفصلة عن باقي النظام عبر استعمال الخصائص الأمنية لنواة لينكس مثل مجالات الأسماء (Namespaces) ومجموعات المراقبة (Control groups). وهي بنية مُشابهة للأجهزة الوهميّة (Virtual Machines)، إلا أنها أكثر خفّة، بحيث أنك لن تحتاج إلى تشغيل نواة إضافية أو محاكاة العتاد، ما يعني أنه بالإمكان إنشاء حاويات متعددة على نفس الخادوم. ويُمكنك باستعمال حاويات لينكس تشغيل وحدات متعددة لأنظمة تشغيل بأكملها، كلّها محجوزة بنفس الخادوم. أو تحزيم تطبيقاتك الخاصة والملفات التابعة لها في حاوية خاصة دون التأثير على باقي مكونات النظام. على سبيل المثال تخيّل أنك تملك خادوما وتريد تجهيز عدد من الخدمات، بما فيها المواقع اﻹلكترونية لعملائك. في النظام التقليدي، كل موقع إلكتروني سيكون عبارة عن مضيف وهمي (virtual host) من نفس خادوم Nginx أو Apache، لكن مع حاويات لينكس، كل موقع إلكتروني يتم إعداده في حاويته الخاصة مع خادوم ويب خاصّ به. ﻹنشاء وتسيير هذه الحاويات يمكن استعمال LXD الذي يوفر خدمة مراقبة الأجهزة الافتراضية hypervisor لتسيير دورة حياة الحاويات بأكملها. سنقوم في هذا الدرس بتنصيب موقعين إلكترونيين مبنيين على Nginx في نفس الخادوم. كل منهما محجوز في حاويته الخاصة، ثم سنقوم بتنصيب HAProxy ليعمل على شكل وسيط عكسي (reverse proxy) على حاوية ثالثة، ثم سنقوم بتوجيه الزوار إلى حاوية HAProxy لجعل كلا الموقعين قابلين للولوج من خلال شبكة الإنترنت. المتطلّبات لإتمام المطلوب نحتاج إلى ما يلي: خادوم Ubuntu 16.04 معد بإتباع الخطوات المتواجدة في هذا الدّرس ومستخدم إداري بامتيازات sudo غير المستخدم الجذر وجدار ناري. اسما نطاق مؤهلان بالكامل (FQDNs)، مع كل سجل DNS A موجه نحو عنوان IP الخاصّ بالخادوم، لتحقيق ذلك يمكن إتباع هذا الدرس. اختياريا، قم بإضافة 20 GB من تخزين الكتل (Block storage) عن طريق إتباع هذا الدرس الذي يُمكن استعماله لتخزين جميع البيانات المتعلقة بالحاويات. الخطوة الأولى - إضافة المستخدم إلى مجموعة LXD نسجل الدخول إلى الخادوم عن طريق حساب المستخدم غير الجذر الذي سيُستعمل لتأدية جميع مهام تسيير الحاوية، وليُنجِز ذلك يجب إضافة هذا الحساب إلى مجموعة lxd عن طريق الأمر التّالي: sudo usermod --append --groups lxd sammy أبدل sammy باسم المستخدم الخاصّ بك. نقوم بتسجيل الخروج من الخادوم ثم تسجيل الدخول إليه لتحديث جلسة SHH بعضوية المجموعة الجديدة، بعد ذلك، يمكن البدء بإعداد LXD. الخطوة الثانية - إعداد LXD يحتاج LXD إلى إعدادات معينة ليعمل بالشكل المطلوب قبل استعماله، نوع التخزين على مستوى الواجهة الخلفية هو أهم إعداد يجب علينا تحديده، لتخزين الحاويات، التخزين المقترح لـLXD هو استعمال ملف من نوع ZFS مُخزّن إما داخل ملف مخصص مسبقا أو عن طريق استعمال تخزين الكتل. لدعم ملفات ZFS في LXD، سنقوم بتنصيب حزمة zfsutils-linux: sudo apt-get update sudo apt-get install zfsutils-linux بعد ذلك سنكون مستعدين لتهيئة LXD، أثناء التهيئة سيُطلَبُ منك تخصيص تفاصيل تخزين ZFS على مستوى النظام الخلفي. هناك طريقتان لذلك اعتمادا على إذا ما كنا سنستعمل ملفا معدا مسبقا أو تخزين الكتل، بعد تحديد آلية التخزين سنقوم بإعداد اختيارات تواصل الحاويات الخاصة بنا. لكن قبل ذلك، سنتعرّف على خياري تهيئة التّخزين. الخيار الأول - استعمال ملف مخصص مسبقا اتبع الخطوات التالية لإعداد LXD لاستعمال ملف مخصص مسبقا لتخزين الحاويات. أولا نفّذ اﻷمر التالي لبدأ عملية تهيئة LXD: sudo lxd init سيُطلب منا اﻹدلاء بمجموعة من المعلومات كما يظهر في النتائج التالية، سنقوم باختيار الاختيارات الافتراضية بما في ذلك حجم الملف المقترح والمسمى جهاز الحلقة (loop device). المُخرجات: Name of the storage backend to use (dir or zfs) [default=zfs]: zfs Create a new ZFS pool (yes/no) [default=yes]? yes Name of the new ZFS pool [default=lxd]: lxd Would you like to use an existing block device (yes/no) [default=no]? no Size in GB of the new loop device (1GB minimum) [default=15]: 15 Would you like LXD to be available over the network (yes/no) [default=no]? no Do you want to configure the LXD bridge (yes/no) [default=yes]? yes Warning: Stopping lxd.service, but it can still be activated by: lxd.socket LXD has been successfully configured. يتم حساب الحجم المقترح تلقائيا بناء على المساحة المتاحة في الخادوم. بعد إعداد الجهاز، سنقوم بضبط إعدادات التشبيك، لكن قبل ذلك، لنتعرّف على الخيار الثاني. الخيار الثاني - استعمال تخزين الكتل إذا كنت تريد استعمال تخزين الكتل، ستحتاج إلى البحث عن الجهاز الذي يُشير نحو حجم تخزين الكتل (block storage volume) الذي تمّ إنشاؤه لتخصيصه في إعدادات LXD، سنذهب إلى تبويبة Volumes في لوحة التحكم الخاصّة بـDigitalOcean. ثم نقوم بتحديد مكان للمساحة ثم النقر على النافذة المنبثقة More، ثم انقر على Config instructions. نقوم بتحديد مكان الجهاز عن طريق النّظر إلى مُخرج أمر تشكيل الحجم، ابحث بشكل خاص عن المسار المخصّص في أمر sudo mkfs.ext4 -F. تمثل الوثيقة التالية مثالا على هذا الحجم: الذي يهمنا هو الجزء المسطر بالأحمر. في هذه الحالة اسم الحجم هو: /dev/disk/by-id/scsi-0D0_Volume_volume-fra1-01 يمكن لهذا الاسم أن يختلف في حالتك. بعد تعريف الحجم سنعود إلى الطرفية وسننفّذ الأمر التالي لبدء عملية تهيئة LXD: sudo lxd init سوف تُطرَح علينا مجموعة من اﻷسئلة، أجب عليها بالأجوبة المُوضّحة أسفله: Name of the storage backend to use (dir or zfs) [default=zfs]: zfs Create a new ZFS pool (yes/no) [default=yes]? yes Name of the new ZFS pool [default=lxd]: lxd إذا طُلب منك استخدام جهاز كتل جاهز آنفا فاختَر نعم (yes)، مع اﻹدلاء بمساره. Would you like to use an existing block device (yes/no) [default=no]? yes Path to the existing block device: /dev/disk/by-id/scsi-0DO_Volume_volume-fra1-01 ثم اختر القيم الافتراضية لباقي اﻷسئلة. Would you like LXD to be available over the network (yes/no) [default=no]? no Do you want to configure the LXD bridge (yes/no) [default=yes]? yes Warning: Stopping lxd.service, but it can still be activated by: lxd.socket LXD has been successfully configured. بعد انتهاء العملية، سنقوم بإعداد الشبكة. إعداد التشبيك (Networking) ستُظهِر لنا عمليّة التّهيئة مجموعة من شاشات التّعليمات كما هو موضّح في الصورة أسفله، ستمكّننا هذه التّعليمات من إعداد جسر التشبيك للحاويات حتى تتمكن من الحصول على عناوين IP خاصّة بها، وتتمكن من التواصل بينها والاتصال بشبكة الأنترنت. قم باستعمال جميع القيم الافتراضية باستثناء تشبيك IPv6، قم باختيار الخيار No في هذه الحالة. إذ لن نستعمله في هذا الدرس. بعد الانتهاء من إعداد التّشبيك، ستكون جاهزا لإنشاء الحاويات. الخطوة الثّالثة - إنشاء الحاويات قمنا بإعداد LXD بنجاح، إذ قمنا بتخصيص موقع للتخزين على مستوى الواجهة الخلفية وقمنا بإعداد التشبيك الافتراضي ﻷي حاويات منشأة حديثا. ما يعني بأنّنا جاهزون ﻹنشاء وتسيير بعض الحاويات، وذلك باستعمال الأمر lxc. أول أمر سنُجرّبه هو الأمر lxc list، والذي يُعطينا لائحة الحاويات المُنصّبة المتوفرة: lxc list المُخرجات: Generating a client certificate. This may take a minute... If this is your first time using LXD, you should also run: sudo lxd init To start your first container, try: lxc launch ubuntu:16.04 +------+-------+------+------+------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +------+-------+------+------+------+-----------+ ولأنها المرة اﻷولى التي يتواصل فيها أمر lxc مع مراقب الأجهزة الافتراضية (Hypervisor) الخاص بـLXD،فإن المخرج يخبرنا بأن اﻷمر قام بإنشاء شهادة عميل تلقائيا وذلك للتواصل اﻵمن مع LXD. بعد ذلك، يخبرنا بمعلومات حول كيفيّة إطلاق الحاويات، ثمّ يعرِض لائحة فارغة من الحاويات ﻷننا لم ننشئ أيا منها بعد. لنَقُم بإنشاء ثلاثة حاويات، واحدة لكل خادوم ويب والثالثة للوسيط العكسي، دور هذا اﻷخير هو توجيه الاتصالات الواردة من اﻷنترنت نحو الخادوم المناسب داخل الحاوية. نقوم باستعمال أمر lxc launch لإنشاء وتشغيل حاوية (ubuntu:x) Ubuntu 16.04 باسم web1. الحرف x في ubuntu:x هو اختصار لكلمة Xenial الاسم الرمزي لـUbuntu 16.04، أمّا ubuntu: فهو مُعرّف المجلد المضبوط مسبقا الخاص بصور LXD. ملاحظة: يمكنك الوصول إلى اللائحة الكاملة لصور Ubuntu المتاحة عن طريق الأمر lxc image list ubuntu:، ولتوزيعات أخرى استعمل اﻷمر lxc image list images:. نفّذ الأوامر التالية لإنشاء الحاويات: lxc launch ubuntu:x web1 lxc launch ubuntu:x web2 lxc launch ubuntu:x haproxy وبما أنها المرة اﻷولى التي ننشئُ فيها الحاويات، فسيقوم اﻷمر اﻷول بتنزيل صور الحاويات من اﻷنترنت وسيخزنها محليا، ستُنشَئُ الحاويّتان المتبقيّتان بشكل أسرع. لاحظ بيانات المخرج جرّاء إنشاء الحاوية web1: Creating web1 Retrieving image: 100% Starting web1 بعد أن قمنا بإنشاء ثلاثة حاويات فارغة سنقوم باستعمال الأمر lxc list ﻹظهار المعلومات حولها: lxc list يُظهِر المخرج جدولا باسم الحاوية وحالتها الحالية، عنوان IP الخاص بها، نوعها وما إذا تم أخد أية لقطات (snapshots) لها: +---------+---------+-----------------------+------+------------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +---------+---------+-----------------------+------+------------+-----------+ | haproxy | RUNNING | 10.10.10.10 (eth0) | | PERSISTENT | 0 | +---------+---------+-----------------------+------+------------+-----------+ | web1 | RUNNING | 10.10.10.100 (eth0) | | PERSISTENT | 0 | +---------+---------+-----------------------+------+------------+-----------+ | web2 | RUNNING | 10.10.10.200 (eth0) | | PERSISTENT | 0 | +---------+---------+-----------------------+------+------------+-----------+ سَجِّل أسماء الحاويات وعناوين IPv4 الخاصة بها لأننا سنحتاجها لإعداد الخدمات. الخطوة الرابعة - إعداد حاويات Nginx لنقم بالاتصال مع الحاوية web1 وإعداد الخادوم اﻷول، وللقيام بذلك نستعمل الأمر lxc exec الذي يأخذ اسم الحاوية والأوامر التي تريد تنفيذها. استعمل اﻷمر التالي للاتصال بالحاوية: lxc exec web1 -- sudo --login --user ubuntu يَدُلّ المقطع -- على أنّ العوامل التي ستُمرَّرُ للأمر lxc ستنتهي وسيتم تمرير باقي السطر على شكل أوامر للتنفيذ داخل الحاوية، اﻷمر الذي سيُمرَّرُ في هذه الحالة هو sudo --login --user ubuntu والذي يوفر صدفة ولوج (login shell) للحساب ubuntu المعد مسبقا داخل الحاويّة. ملاحظة: إذا كنت تريد الاتصال بالحاوية بصلاحيات حساب الجذر، فقم باستعمال اﻷمر lxc exec web1 -- /bin/bash عوضا عمّا سبق. فور الدخول إلى الحاويّة، سيظهر لنا محثّ الصدفة على الشكل التالي: ubuntu@web1:~$ المُستخدم ubuntu هذا معد مسبقا بصلاحيات sudo داخل الحاوية ويستطيع إصدار أوامر sudo دون الحاجة إلى اﻹدلاء بكلمة المرور. هذه الصدفة محدودة داخل حدود الحاوية. أي أنّ أيّ أمر نُشغله داخل هذه الصدفة يبقى داخل الحاوية ولا يخرج إلى الخادوم المُضيف. لِنحدّث لائحة حزم Ubuntu داخل الحاوية ولنُنصِّب Nginx: sudo apt-get update sudo apt-get install nginx لنعدل صفحة الويب الافتراضية لهذا الموقع ولنُضِف نصّا يوضح أن هذا الموقع مستضاف على الحاوية web1. افتح الملف /var/www/html/index.nginx-debian.html: sudo nano /var/www/html/index.nginx-debian.html قم بالتعديلات التالية للملف: <!DOCTYPE html> <html> <head> <title>Welcome to nginx on LXD container web1!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx on LXD container web1!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> ... قمنا بتعديل الملف في مكانين العنوان <title> والوسم <h1> وذلك بإضافة المقطع on LXD container web1. أغلق المحرر بعد الحفظ. واﻵن، سجّل الخروج من الحاوية لنَعودَ إلى الخادوم المُضيف: logout سنُكرر نفس اﻷمر بالنسبة لحاويّة web2، نسجل الدخول نُنصّب Nginx ثمّ نعدّل الملفّ /var/www/html/index.nginx-debian.html لذِكرِ web2، ثم نخرج من الحاويّة web2. لنستعمل curl للتأكد من أن الخواديم داخل الحاويات تعمل بشكل جيد. نحتاج إلى عناوين IP الخاصّة بالحاويات، والتي حصلنا عليها سابقا. curl http://10.10.10.100/ يجب على المُخرج أن يكون كما يلي: <!DOCTYPE html> <html> <head> <title>Welcome to nginx on LXD container web1!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx on LXD container web1!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> ... تفقّد الحاوية الثانية كذلك باستعمال الأمر curl وعنوان IP الخاصّ بها للتّأكد من أنّها قد ضُبطت بالشكل الصحيح، يمكن المرور إلى ضبط HAProxy بعد ذلك. الخطوة الخامسة - إعداد حاوية HAProxy سنقوم بإعداد حاوية HAProxy لتعمل كوسيط أمام هاتين الحاويتين. ولمزيد من المعلومات حول طريقة عمل HAProxy يمكنك الرجوع إلى هذا الدرس. سنقوم بتوجيه حركة المرور نحو كل حاوية بناءا على اسم النطاق الذي نستعمله، سوف نستعمل اسم النطاق example.com في مثال الإعدادات الموالي، وهو نطاق خاص للتوثيقات التعليمية مثل هذا الدرس، سنقوم بإنشاء أول موقع إلكتروني متاح على اسمي النطاق example.com و www.example.com. الموقع اﻹلكتروني الثاني سيكون على اسم النّطاق www2.example.com. أبدِل أسماء النطاقات الخاصة بك مكان هذه اﻷسماء. سجل الدخول إلى حاوية haproxy: lxc exec haproxy -- sudo --login --user ubuntu حدّث لائحة الحزم ونصِّب HAProxy: sudo apt-get update sudo apt-get install haproxy بعد انتهاء التنصيب سننتقل إلى إعداد HAProxy. ملف إعدادات HAProxy مُتواجد في المسار ‎/etc/haproxy/haproxy.cfg. افتح هذا الملف بواسطة محرر النصوص المُفضّل لديك: sudo nano /etc/haproxy/haproxy.cfg أولا سنقوم ببعض التعديلات في قسم defaults. سنقوم بإضافة خيار forwardfor لكي نحتفظ بعنوان IP المصدري لعميل الويب، وسنضيف الخيار http-server-close، والذي سيقوم بتمكين إعادة استخدام الجلسة (session reuse) وتخفيض زمن الوصول (Latency). global ... defaults log global mode http option httplog option dontlognull option forwardfor option http-server-close timeout connect 5000 timeout client 50000 timeout server 50000 ... سنقوم بعد ذلك بإعداد الواجهة اﻷمامية للإشارة نحو حاويتي الواجهة الخلفية الخاصة بنا. أضف قسم frontend تحت اسم www_frontend كما يلي: frontend www_frontend bind *:80 # Bind to port 80 (www) on the container # It matches if the HTTP Host: field mentions any of the hostnames (after the '-i'). acl host_web1 hdr(host) -i example.com www.example.com acl host_web2 hdr(host) -i web2.example.com # Redirect the connection to the proper server cluster, depending on the match. use_backend web1_cluster if host_web1 use_backend web2_cluster if host_web2 توافق أوامر acl أسماء مُضيفات خواديم الويب ثم تقوم بإعادة توجيه الطلب إلى قسم backend المناسب. ثم نعرف قسمي backend جديدين واحد لكل خادوم ويب، ثم نقوم بتسميتهما web1_cluster وweb2_cluster تباعا. أضف الشفرة التالية للملف لتعريف الواجهات الخلفية: backend web1_cluster balance leastconn # We set the X-Client-IP HTTP header. This is useful if we want the web server to know the real client IP. http-request set-header X-Client-IP %[src] # This backend, named here "web1", directs to container "web1.lxd" (hostname). server web1 web1.lxd:80 check backend web2_cluster balance leastconn http-request set-header X-Client-IP %[src] server web2 web2.lxd:80 check يحدّد خيار balance استراتيجية موازنة الحمل (load-balancing). في هذه الحالة، نُفضّل اقل عدد من الاتصالات. خيار http-request يضبط ترويسة HTTP (HTTP header) مع عنوان IP الخاصّ بعميل الويب الحقيقي، إذا لم نحدد هذه الترويسة فإن خادوم الويب سيسجل عنوان HAProxy IP على انه العنوان المصدري لجميع الاتصالات مما سيصعب تحليل أماكن و أصول حركة المرور. يُخصّص خيار server اسما كيفيا (arbitrary name) للخادوم web1 متبوعا باسم المُضيف ومنفذ الخادوم. يُزوّد LXD الحاويات بخادوم DNS، وذلك لكي يُشير web1.lxd إلى عنوان IP التّابع للحاوية web1. الحاويات اﻷخرى لها أسماء مُضيفات خاصة بها مثل web2.lxd وhaproxy.lxd. يدفع المُعامل check HAProxy إلى أداء فحوصات السلامة (Health checks) على الخادوم للتأكد من توفره. لاختبار صحة اﻹعدادات، نفّذ اﻷمر التالي: /usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -c ينبغي على المخرج أن يكون كما يلي: Configuration file is valid لِنُعد تحميل Haproxy لكي يقرأ اﻹعدادات الجديدة: sudo systemctl reload haproxy والآن سجل الخروج من الحاوية للعودة إلى المُضيف: logout قمنا بتجهيز Haproxy ليتصرف على شكل وسيط عكسي يوجّه أي اتصال يتلقاه عبر المنفذ رقم 80 نحو الخادوم الملائِم داخل كلا الحاويتين. لنتحقق من أن haproxy يستطيع فعلا تحويل الطلبات نحو الحاوية الصحيحة. ولذلك نستعمل اﻷمر التّالي: curl --verbose --header 'Host: web2.example.com' http://10.10.10.10 يُرسل الأمر أعلاه طلبا لـHAProxy ويضبط ترويسة HTTP باسم host والتي سيستعملها HAProxy لتوجيه الاتصال نحو الخادوم الملائم. يجب على المخرج أن يكون كالتالي: ... > GET / HTTP/1.1 > Host: web2.example.com > User-Agent: curl/7.47.0 > Accept: */* > ... < <!DOCTYPE html> <html> <head> <title>Welcome to nginx on LXD container web2!</title> <style> ... تمكن Hproxy من فهم الطلب وتوجيهه نحو الحاوية web2 بنجاح. ومنه فإن الخادوم قدم لنا الصّفحة الرّئيسيّة الافتراضيّة التي قمنا بتعديلها سابقا وأظهر النص on LXD container web2. لنقم الآن بتوجيه الطلبات الخارجية إلى HAProxy حتى يتمكن بقية العالم من الولوج إلى مواقعنا الإلكترونية. الخطوة السادسة - توجيه الاتصالات الواردة نحو حاوية HAProxy القطعة اﻷخيرة من اﻷحجية هي توصيل الوسيط العكسي مع شبكة اﻷنترنت. نحتاج إلي ضبط الخادوم لتوجيه أي اتصال وارد إليه من اﻷنترنت عبر المنفذ 80 نحو حاوية HAProxy. نُصِّبَ HAProxy في حاوية خاصّة به، وبالتالي، فإنه غير قابل للولوج من اﻷنترنت افتراضيا ولحل هذه المشكلة، سنقوم بإنشاء قاعدة iptables لتوجيه الاتصالات. يحتاج اﻷمر iptables إلى عنواني IP، عنوان الخادوم العمومي (your_server_ip) وعنوان IP الخاصّ بالحاويّة haproxy (أي your_haproxy_ip أسفله)، والذي نحصل عليه من خلال اﻷمر lxc list. نفّذ هذا اﻷمر ﻹنشاء القاعدة: sudo iptables -t nat -I PREROUTING -i eth0 -p TCP -d your_server_ip/32 --dport 80 -j DNAT --to-destination your_haproxy_ip:80 وهذا شرح لتفاصيل هذا اﻷمر: المقطع -t nat يعني بأننا نستعمل الجدول nat. المقطع -I PREROUTING يعني أننا نضيف القاعدة إلى سلسلة التوجيه المسبَق (PREROUTING). المقطع -i eth0 يعني أن الواجهة eth0 هي التي ستُستَعمَل، وهي الواجهة العمومية الافتراضية على الخواديم. المقطع -p TCP يعني أننا نستعمل بروتوكول TCP. المقطع -d your_server_ip/32 يحدد عنوان IP الهدف للقاعدة. المقطع --dport 80 يُحدّد رقم المنفذ الهدف. المقطع -j DNAT يعني أننا نريد أن نؤدي قفزة نحو الهدف NAT (DNAT). المقطع --to-destination your_haproxy_ip:80 يدلّ على أننا نريد من الطلب الذهاب إلى عنوان IP الخاصّ بالحاوية من طريق HAProxy. للمزيد من المعلومات حول IPTables، تفقّد الدّرس ما هو الجدار الناري وكيف يعمل؟ والدّرس أساسيات IPTables - قواعد وأوامر شائعة للجدار الناري . أخيرا لحفظ أمر iptables لكي يُعاد تطبيقُه بعد إعادة التشغيل نقوم بتنصيب حزمة iptables-persistent: sudo apt-get install iptables-persistent أثناء تنصيب الحزم سيطلب منك حفظ قواعد iptables الحاليّة. وافق واحفظ جميع قواعد iptables الحاليّة. إذا قمت بإعداد اسمي نطاق FQDN، فسيمكنك أن تتصل بكل من الموقعين باستعمال متصفحك. لذا جرب ذلك. للتحقق من أن الخادومين يمكن الولوج لهما عن طريق اﻷنترنت، ادخل إلى كل منهما باستعمال حاسوبك المحلي عن طريق أمر curl بالشكل التالي: curl --verbose --header 'Host: example.com' 'http://your_server_ip' curl --verbose --header 'Host: web2.example.com' 'http://your_server_ip' هذه اﻷوامر تقوم باتصالات HTTP مع عنوان IP العمومي الخاصّ بالخادوم وتضيف حقل ترويسة HTTP مع خيار --header والذي سيستعمله HAProxy لتنفيذ الطلب كما فعلنا في الخطوة الخامسة. هذا هو المخرج بالنسبة لأمر curl الأول: * Trying your_server_ip... * Connected to your_server_ip (your_server_ip) port 80 (#0) > GET / HTTP/1.1 > Host: example.com > User-Agent: curl/7.47.0 > Accept: */* > < HTTP/1.1 200 OK < Server: nginx/1.10.0 (Ubuntu) ... <!DOCTYPE html> <html> <head> <title>Welcome to nginx on LXD container web1!</title> <style> body { ... وهذا هو مٌخرج الأمر الثّاني: * Trying your_server_ip... * Connected to your_server_ip (your_server_ip) port 80 (#0) > GET / HTTP/1.1 > Host: web2.example.com > User-Agent: curl/7.47.0 > Accept: */* > < HTTP/1.1 200 OK < Server: nginx/1.10.0 (Ubuntu) ... <!DOCTYPE html> <html> <head> <title>Welcome to nginx on LXD container web2!</title> <style> body { ... تم إظهار الموقع الصحيح في كلتا الحالتين. خاتمة قمت الآن بضبط موقعي ويب كل منهما داخل حاويته الخاصة مع HAProxy كموجه للمرور، يمكنك تكرار نفس العملية ﻹعداد مواقع ويب أخرى كل داخل حاويته الخاصة، يمكن كذلك إضافة MySQL في حاوية جديدة وتنصيب نظام إدارة محتوى مثل Wordpress لتسيير كل موقع ويب على حدة. يمكنك كذلك استعمال هذه العملية لدعم نُسخِِ أقدم من برمجية معينة، على سبيل المثال، إن كان نظام إدارة محتوى يتطلب برمجية قديمة مثل PHP5 فبإمكانك تنصيب Ubuntu 14.04 على حاوية (lxc launch ubuntu:t) عوضا عن محاولة تخفيض إصدارات مدير الحزم المتوفرة على Ubuntu 16.04. يوفر LXD القدرة على أخذ لقطات للحالة الكاملة للحاويات، ما يجعل إنشاء النسخ الاحتياطية وإرجاع الحاويات إلى الوراء في وقت لاحق أمرا سهلا. إضافة إلى ما سبق فتنصيب LXD على خادومين مختلفين يمكّن من الربط بينهما وتهجير الحاويات بين الخواديم عبر الإنترنت. ترجمة -بتصرّف- للمقال How to Host Multiple Web Sites with Nginx and HAProxy Using LXD on Ubuntu 16.04 لصاحبه Simos Xenitellis.
  4. نشرح طريقة تثبيت وإعداد خادم Nginx على توزيعة أوبنتو، وسنستعمله لتخديم صفحات HTML الخاصة بنا. لتثبيت خادم أباتشي راجع فيديو تثبيت وضبط خادم Apache في أكاديمية حسوب. قسم خوادم الويب في أكاديمية حسوب غني بالمقالات المفيدة للتعامل معها.
  5. مقدّمة يُعتبر Apache و Nginx اثنين من أشهر خوادم الويب مفتوحة المصدر ويُستخدمان غالباً مع PHP. قد يكون من المفيد تشغيل كل منهما على نفس الجهاز الإفتراضي virtual machine عند استضافة مواقع ويب متعددة ذات متطلباتٍ متنوعة. إنّ الحل العام لتشغيل خوادم الويب على نظام واحد هو استخدام عناوين IP متعددة أو أرقام منافذ مختلفة. بالإمكان ضبط الخوادم التي تملك كلّا من عناوين IPv4 و IPv6 لخدمة مواقع Apache على أحد البروتوكولين ومواقع Nginx على البروتوكول الآخر، ولكن عمليًا هذا غير مُطبّق حاليًا، نظرًا لأن تبنّي مزودي خدمات الإنترنت لـ IPv6 لا يزال غير شائع. حيث يعدّ وجود رقم منفذ مختلف مثل 81 أو 8080 لخادم الويب الثاني حلاً آخر، ولكن مشاركة عناوين URL بأرقام المنافذ (مثل http://example.com:81) ليس منطقيًّا أو مثاليًّا دائمًا. سنتعلّم في هذه الدورة كيفيّة ضبط Nginx كخادم ويب وكذلك كوسيط عكسي Reverse Proxy لـ Apache - كل ذلك على خادم واحد. قد تكون هنالك حاجة اعتمادًا على تطبيق الويب إلى تغييرات في الشفرة ليبقى Apache مُدركًا بالوسيط العكسي، وخاصّة عند ضبط مواقع SSL. سنتجنّب ذلك بتثبيت module وحدة Apache تسمى mod_rpaf والتي تُعيد كتابة متغيرات بيئة معيّنة بحيث يبدو أن Apache يتعامل مباشرة مع الطلبات من عملاء الويب. ستُضاف أربعة أسماء نِطاقات domain names على خادم واحد. وسيُخدَّم اثنين منهما بواسطة Nginx هما:example.com (المُضيف الظاهري الافتراضي) و sample.org. والاثنين المتبقيين، foobar.net و test.io، سيُخدّمان من قبل Apache. سنُعدّ أيضًا Apache لخدمة تطبيقات PHP باستخدام PHP-FPM، والذي يقدّم أداء أفضل عبر mod_php. المتطلبات المُسبقة ستحتاج لإكمال هذه الدورة التعليميّة إلى ما يلي: خادم Ubuntu 18.04 جديد تم إعداده من خلال اتباع خطوات الإعداد الأولي للخادم في Ubuntu 18.4، مع مستخدم sudo عادي (non-root) و جدار ناري. ضبط أربعة أسماء نطاق مؤهلة بالكامل للإشارة لعنوان IP الخاص بخادمك. انظر الخطوة 3 من كيفية إعداد اسم مضيف فيDigitalOcean كمِثال لكيفية القيام بذلك. إذا كنت تستضيف DNS للنطاقات الخاصّة بك في مكان آخر، فعليك إنشاء سجلات A مناسبة هناك بدلاً من ذلك. الخطوة 1 - تثبيت Apache و PHP-FPM لنبدأ بتثبيت Apache و PHP-FPM. سنثبّت أيضًا بالإضافة إلى تثبيت Apache و PHP-FPM، وحدة PHP FastCGI Apache وهيlibapache2-mod-fastcgi، لدعم تطبيقات ويب FastCGI. أولاً، يجب تحديث قائمة الحزم package الخاصّة بك للتأكد من حصولك على أحدث الحزم. $ sudo apt update يجب بعد ذلك تثبيت حزم Apache و PHP-FPM: $ sudo apt install apache2 php-fpm يجب تنزيل وحدة FastCGI Apache من kernel.org وتثبيتها باستخدام الأمر dpkg لأنّها غير متوفرة في مستودع Ubuntu: $ Wget https://mirrors.edge.kernel.org/ubuntu/pool/multiverse/liba/ libapache-mod-fastcgi/libapache2-mod-fastcgi_2.4.7~0910052141-1.2_amd64.deb $ sudo dpkg -i libapache2-mod-fastcgi_2.4.7~0910052141-1.2_amd64.deb علينا بعد ذلك تغيير الضبط الافتراضي لخادم Apache من أجل استخدام PHP-FPM. الخطوة 2 - ضبط Apache و PHP-FPM سنغيّر في هذه الخطوة رقم منفذ Apache إلى 8080 وضبطه للعمل مع PHP-FPM باستخدام الوحدة mod_fastcgi. أعد تسمية ملف ضبط ports.conf لمخدم Apache: $ sudo mv /etc/apache2/ports.conf /etc/apache2/ports.conf.default أنشئ ملف ports.conf جديد مع تعيين المنفذ إلى 8080: $ echo "Listen 8080" | sudo tee /etc/apache2/ports.conf ملاحظة: تُضبط خوادم الويب بشكل عام للتنصت على المنفذ 127.0.0.1:8080 عند ضبط الوكيل العكسي، ولكن القيام بذلك سيؤدي إلى ضبط قيمة متغير بيئة (PHP (SERVER_ADDR إلى عنوان IP الاسترجاع بدلاً من عنوان الـ IP العام للخادم. هدفنا هو إعداد Apache بطريقة لا ترى مواقعه على الويب الوكيل العكسي أمامها. لذلك، سنضبطه للتنصت على المنفذ 8080 لجميع عناوين IP. سننشئ بعد ذلك ملف مضيف افتراضي لـ Apache. سيعدّ التوجيه في هذا الملف ليخدّم المواقع فقط على المنفذ 8080. عطّل المضيف الظاهري الافتراضي: $ sudo a2dissite 000-default ثم أنشئ ملف مضيف افتراضي جديد، باستخدام الموقع الافتراضي الموجود: $ sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/001-default.conf افتح الآن ملف الضبط الجديد: $ sudo nano /etc/apache2/sites-available/001-default.conf غيّرمنفذ التنصت إلى 8080: /etc/apache2/sites-available/000-default.conf ServerAdmin webmaster@localhost DocumentRoot /var/www/html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined احفظ الملف وقم بتنشيط ملف الضبط الجديد: $ sudo a2ensite 001-default ثم أعد تحميل Apache: $ sudo systemctl reload apache2 تحقّق من أن Apache يتنصت الآن على 8080: $ sudo netstat -tlpn يجب أن يبدو الخرج output كالمثال التالي، حيث يتنصّت apache2 على المنفذ 8080: output Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1086/sshd tcp6 0 0 :::8080 :::* LISTEN 4678/apache2 tcp6 0 0 :::22 :::* LISTEN 1086/sshd يمكنك إعداد دعم PHP و FastCGI بمجرّد التحقق من أن Apache يتنصت على المنفذ الصحيح. الخطوة 3 - ضبط Apache لاستخدام mod_fastcgi يخدّم Apache صفحات PHP باستخدام mod_php افتراضيًا، ولكنه يتطلب إعدادًا إضافيًّا للعمل مع PHP-FPM. ملاحظة: إذا كنت تجرّب هذا الدرس على نسخة موجودة مسبقًا من LAMP مع mod_php، عطّله أولاً باستخدام sudo a2dismod php7.2. سنضيف كتلة ضبط لوحدة mod_fastcgi التي تعتمد على mod_action. يُعطّل mod_action بشكل افتراضي، لذلك نحتاج أولاً إلى تفعيله: $ sudo a2enmod action أعد تسمية ملف ضبط FastCGI الموجود: $ sudo mv /etc/apache2/mods-enabled/fastcgi.conf/etc/apache2/mods -enabled/fastcgi.conf.default أنشئ ملف ضبط جديد: $ sudo nano /etc/apache2/mods-enabled/fastcgi.conf أضف التوجيهات التالية إلى الملف لتمرير طلبات ملفات php. إلى مقبس PHP-FPM UNIX: /etc/apache2/mods-enabled/fastcgi.conf AddHandler fastcgi-script .fcgi FastCgiIpcDir /var/lib/apache2/fastcgi AddType application/x-httpd-fastphp .php Action application/x-httpd-fastphp /php-fcgi Alias /php-fcgi /usr/lib/cgi-bin/php-fcgi FastCgiExternalServer /usr/lib/cgi-bin/php-fcgi -socket /run/php/php7.2-fpm.sock -pass-header Authorization Require all granted احفظ التغييرات واختبر الضبط: $ sudo apachectl -t إذا ظهرت عبارة Syntax OK، أعد تحميل Apache: $ sudo systemctl reload apache2 إذا رأيت رسالة التحذير التالية، يمكنك تجاهلها الآن بشكل آمن. سنَضبط أسماء الخادم في وقت لاحق: Could not reliably determine the server's fully qualified domain name, using 127.0.1.1. Set the 'ServerName' directive globally to suppress this message. دعنا نتأكد الآن من أنّه بإمكاننا تخديم PHP من Apache. الخطوة 4 - التحقق من عمل PHP سَنتأكّد من أن PHP يعمل، وذلك من خلال إنشاء ملف ()phpinfo والوصول إليه من متصفح الويب. أنشئ الملف var/www/html/info.php/ والذي يحتوي على استدعاء للدّالة phpinfo: $ echo "" | sudo tee /var/www/html/info.php انتقل في المتصفح إلى http: // your_server_ip: 8080 / info.php لاستعراض هذا الملف. ستظهر لك قائمة إعدادات الضبط التي يستخدمها PHP. كما في الشكل التالي: تحقّق من أن الخيار Server API يأخذ القيمة FPM/FastCGI وذلك في أعلى الصفحة كما في الصورة السابقة. سترى كذلك في أسفل الصفحة تقريبًا في القسم PHP Variables بأنّ قيمة SERVER_SOFTWARE هي Apache على Ubuntu. وهذا يؤكّد أنّ الوحدة mod_fastcgi مُفعّلة وأنّ Apache يستخدم PHP-FPM لمعالجة ملفات PHP. الخطوة 5 - إنشاء مضيفات افتراضيّة لـ Apache دعونا ننشئ ملفات المضيف الافتراضي لـ Apache للنطاقين foobar.net و test.io. سنقوم لعمل ذلك أولاً بإنشاء الأدلّة الجذر للمستند في كِلا الموقعين ووضع بعض الملفات الافتراضيّة في هذه الأدلة حتى نتمكن من اختبار الضبط لدينا بسهولة. أولاً، أنشئ الأدلّة الجذر للمستند: $ sudo mkdir -v /var/www/foobar.net /var/www/test.io أنشئ بعد ذلك ملف index لكل موقع: $ echo "<h1 style='color: green;'>Foo Bar</h1>" | sudo tee /var/www/foobar.net/index.html $ echo "<h1 style='color: red;'>Test IO</h1>" | sudo tee /var/www/test.io/index.html " | sudo tee /var/www/test.io/index.html ثم أنشئ ملف ()phpinfo لكل موقع حتى نتمكن من اختبار فيما إذا ضُبط PHP بشكل صحيح. $ echo "" | sudo tee /var/www/foobar.net/info.php $ echo "" | sudo tee /var/www/test.io/info.php الآن أنشئ ملف المضيف الافتراضي للنطاق foobar.net: $ sudo nano /etc/apache2/sites-available/foobar.net.conf أضف الشفرة التالية إلى الملف لتعريف المضيف: /etc/apache2/sites-available/foobar.net.conf ServerName foobar.net ServerAlias www.foobar.net DocumentRoot /var/www/foobar.net AllowOverride All يتيح السطر AllowOverride All تفعيل دعم htaccess. احفظ وأغلق الملف. ثم أنشئ ملف ضبط مماثل لـ test.io. أولاً أنشئ الملف: $ sudo nano /etc/apache2/sites-available/test.io.conf ثم أضف الضبط إلى الملف: /etc/apache2/sites-available/test.io.conf ServerName test.io ServerAlias www.test.io DocumentRoot /var/www/test.io AllowOverride All احفظ الملف وإغلاق المحرّر. والآن بعد إعداد كل من مضيفي Apache الافتراضيين، فعّل المواقع باستخدام الأمر a2ensite. والذي يُنشئ رابط رمزي لمَلف المضيف الافتراضي في الدليل sites-enabled: $ sudo a2ensite foobar.net $ sudo a2ensite test.io تحقّق من Apache للتأكّد من وجود أخطاء في الضبط مرّة أخرى: $ sudo apachectl –t سترى عبارة Syntax OK إذا لم يكن هناك أخطاء. إذا رأيت أي شيء آخر، فتحقّق من الضبط وحاول مرّة أخرى. قم بإعادة تحميل Apache لتطبيق التغييرات بمجرّد أن يكون الضبط الخاص بك خاليًا من الأخطاء: $ sudo systemctl reload apache2 افتح http://foobar.net:8080 و http://test.io:8080 في متصفحك للتأكّد من عمل المواقع والتحقّق من أنّ كل موقع يعرض ملف index.html الخاص به. سترى النتائج التالية: تأكّد أيضًا من أن PHP تعمل وذلك عن طريق الوصول إلى ملفات info.php لكل موقع. افتح http://foobar.net:8080/info.php و http://test.io:8080/info.php في متصفحك. سترى قائمة مواصفات ضبط PHP نفسها على كل موقع كما رأيت في الخطوة 4. لدينا الآن موقعين مُستضافين على Apache على المنفذ 8080. فلنَضبط بعد ذلك Nginx. الخطوة 6 - تثبيت وضبط Nginx سنقوم في هذه الخطوة بتثبيت Nginx وإعداد ضبط النطاقات example.com و sample.org كمضيفين افتراضيين لـ Nginx. ثبّت Nginx باستخدام مدير الحزم: $ sudo apt install nginx أزل الرابط الرمزي الافتراضي للمضيف الافتراضي حيث أننا لن نستخدمه بعد الآن: $ sudo rm /etc/nginx/sites-enabled/default سنُنشئ الموقع الافتراضي الخاص بنا فيما بعد (example.com). سنُنشئ الآن مضيفين افتراضيين لـ Nginx باستخدام نفس الإجرائيّة التي استخدمناها من أجل Apache. أنشئ أولاً الأدلّة للمستند الجذر لكل من موقعي الويب: $ sudo mkdir -v /usr/share/nginx/example.com /usr/share/nginx/sample.org سنحتفظ بمواقع الويب الخاصّة بـ Nginx في /usr/share/nginx، وهو المسار الافتراضي الذي سيختاره Nginx. يمكنك وضع هذه المواقع في /var/www/html مع مواقع Apache، لكن هذا الفصل بينها قد يساعدك على ربط المواقع بـ Nginx. كما فعلت مع مضيفي Apache الافتراضيين، أنشئ ملفات index و ()phpinfo من أجل الاختبار بعد اكتمال الإعداد: $ echo "<h1 style='color: green;'>Example.com</h1>" | sudo tee /usr/share/nginx/example.com/index.html $ echo "<h1 style='color: red;'>Sample.org</h1>" | sudo tee /usr/share/nginx/sample.org/index.html $ echo "<?php phpinfo(); ?>" | sudo tee /usr/share/nginx/example.com/info.php $ echo "<?php phpinfo(); ?>" | sudo tee /usr/share/nginx/sample.org/info.php الآن أنشئ ملف مضيف افتراضي للنطاق example.com: $ sudo nano /etc/nginx/sites-available/example.com يستدعي Nginx كتل server {. . .} من ملف الضبط server blocks. أنشئ كتلة خادم من أجل المضيف الافتراضي الأساسي example.com. تجعل ضبط التوجيه default_server هذا المضيف كمضيف افتراضي افتراضي لمعالجة طلبات HTTP التي لا تتطابق مع أي مضيف افتراضي آخر. /etc/nginx/sites-available/example.com server { listen 80 default_server; root /usr/share/nginx/example.com; index index.php index.html index.htm; server_name example.com www.example.com; location / { try_files $uri $uri/ /index.php; } location ~ \.php$ { fastcgi_pass unix:/run/php/php7.2-fpm.sock; include snippets/fastcgi-php.conf; } } احفظ وأغلق الملف. أنشئ الآن ملف مضيف Nginx افتراضي للنطاق الثاني، sample.org: $ sudo nano etc/nginx/sites-available/sample.org أضف ما يلي إلى الملف: /etc/nginx/sites-available/sample.org server { root /usr/share/nginx/sample.org; index index.php index.html index.htm; server_name sample.org www.sample.org; location / { try_files $uri $uri/ /index.php; } location ~ \.php$ { fastcgi_pass unix:/run/php/php7.2-fpm.sock; include snippets/fastcgi-php.conf; } } احفظ وأغلق الملف. ثم فعّل كِلا الموقعين من خلال إنشاء روابط رمزيّة للدّليل sites-enabled: $ sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com $ sudo ln -s /etc/nginx/sites-available/sample.org /etc/nginx/sites-enabled/sample.org اختبر بعد ذلك ضبط Nginx لضمان عدم وجود أخطاء في الضبط: $ sudo nginx -t ثم أعد تحميل Nginx إذا لم يكن هناك أخطاء: $ sudo systemctl reload nginx الآن قم بالوصول إلى ملف ()phpinfo الخاص بمُضيفي Nginx الافتراضيين من متصفح الويب من خلال زيارة http://sample.org/info.php و http://example.com/info.php. انظر مجدّدًا إلى الصورة في الأسفل إلى قسم المتغيرات PHP Variables. يجب أن يحوي["SERVER_SOFTWARE"] على القيمة Nginx، مشيرًا إلى أنّ الملفات خُدّمت بشكل مباشر بواسطة Nginx. يجب أن يشير["DOCUMENT_ROOT"] إلى الدليل الذي أنشأته مُسبقًا في هذه الخطوة لكل موقع من مواقع Nginx. ثبّتنا في هذه المرحلة Nginx وأنشأنا مضيفين افتراضيين.سنقوم بعد ذلك بضبط Nginx على طلبات الوكيل المخصّصة للنطاقات المستضافة على Apache. الخطوة 7 - ضبط Nginx لمضيفي Apache الافتراضيين لنُنشئ مضيف Nginx افتراضي إضافي مع أسماء نطاقات متعددة في توجيهات server_name. سيتم توكيل طلبات هذه النطاقات إلى Apache. أنشئ ملف مضيف Nginx افتراضي جديد لإعادة توجيه الطلبات إلى Apache: $ sudo nano /etc/nginx/sites-available/apache أضف كتلة الشفرة التالية التي تحدد أسماء نطاقات كلاً من مضيفي Apache الاتراضيين وتوكل طلباتها إلى Apache. تذكّر استخدام عنوان IP العام في proxy_pass: /etc/nginx/sites-available/apache server { listen 80; server_name foobar.net www.foobar.net test.io www.test.io; location / { proxy_pass http://your_server_ip:8080; 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 $scheme; } } قم بحفظ الملف وتفعيل هذا المضيف الافتراضي الجديد عن طريق إنشاء رابط رمزي: $ sudo ln -s /etc/nginx/sites-available/apache /etc/nginx/sites-enabled/apache اختبر الضبط للتأكد من عدم وجود أخطاء: $ sudo nginx -t إذا لم يكن هنالك أخطاء، أعد تحميل Nginx: $ sudo systemctl reload nginx افتح متصفحك وقم بالوصول إلى العنوان http://foobar.net/info.php. انتقل لأسفل إلى قسم PHP Variables وتحقق من القيم المعروضة كما في الصورة. يؤكّد المتغيران ERVER_SOFTWARE و DOCUMENT_ROOT أنّ هذا الطلب عُولج بواسطة Apache. وأضيفت المتغيرات HTTP_X_REAL_IP و HTTP_X_FORWARDED_FOR بواسطة Nginx ويجب أن تُظهر عنوان IP العام للحاسب الذي تستخدمه للوصول إلى عنوان URL. لقد أعددنا Nginx بنجاح ليوكل بطلبات نطاقات محدّدة إلى Apache. بعد ذلك، لنقم بضبط Apache لضبط المتغير REMOTE_ADDR كما لو أنه يتعامل مع هذه الطلبات مباشرة. الخطوة 8 - تثبيت وضبط mod_rpaf سنُثبّت في هذه الخطوة وحدة Apache تسمى mod\_rpaf والتي تعيد كتابة قيم REMOTE_ADDR، HTTPS و HTTP_PORT استنادًا إلى القيم المقدّمة من قبل وسيط عكسي. وبدون هذه الوحدة، تتطلب بعض تطبيقات PHP تغييرات في الشفرة للعمل بسلاسة من خلفْ الخادم الوكيل. هذه الوحدة موجودة في مستودع Ubuntu باسم libapache2-mod-rpaf ولكنها قديمة ولا تدعم توجيهات ضبط معينة. سنقوم بدلاً من ذلك بتثبيتها من المصدر. تثبيت الحزم اللازمة لبناء الوحدة: $ sudo apt install unzip build-essential apache2-dev نزّل أحدث إصدار مستقر من GitHub: $ wget https://github.com/gnif/mod_rpaf/archive/stable.zip استخراج الملف الذي نزل: $ unzip stable.zip انتقل إلى المجلد الجديد الذي يحتوي على الملفات: $ cd mod_rpaf-stable ترجم Compile الوحدة ثم ثبّتها: $ make $ sudo make install أنشئ بعد ذلك ملف في المجلد mods-available والذي سيُحمّل وحدة rpaf: $ sudo nano /etc/apache2/mods-available/rpaf.load أضف الشفرة التالية إلى الملف لتحميل الوحدة: /etc/apache2/mods-available/rpaf.load LoadModule rpaf_module /usr/lib/apache2/modules/mod_rpaf.so احفظ الملف وأغلق المحرر. أنشئ ملف آخر في نفس الدليل وسمّه rpaf.conf والذي سوف يحتوي على توجيهات الضبط للوحدة mod_rpaf: $ sudo nano /etc/apache2/mods-available/rpaf.conf أضف كتلة الشفرة التالية لضبط mod_rpaf، مع التأكّد من تحديد عنوان IP الخاص بخادمك: /etc/apache2/mods-available/rpaf.conf RPAF_Enable On RPAF_Header X-Real-Ip RPAF_ProxyIPs your_server_ip RPAF_SetHostName On RPAF_SetHTTPS On RPAF_SetPort On فيما يلي وصف موجز لكل توجيه. لمزيد من المعلومات، راجع ملف mod_rpaf README. RPAF_Header - الترويسة المراد استخدامها لعنوان IP الحقيقي للعميل. RPAF_ProxyIPs - عنوان IP للوكيل لضبط طلبات HTTP من أجله. RPAF_SetHostName - يقوم بتحديث اسم المضيف الافتراضي بحيث يعمل كل من ServerName و ServerAlias. RPAF_SetHTTPS - يضبط متغير بيئة HTTPS استنادًا إلى القيمة الموجودة في X-Forwarded-Proto. RPAF_SetPort - يضبط متغير بيئة SERVER_PORT. يكون مفيد عندما يكون Apache يعمل خلف وكيل SSL. احفظ الملف rpaf.conf وقم بتفعيل الوحدة: $ sudo a2enmod rpaf يؤدي هذا إلى إنشاء روابط رمزيّة من الملفات rpaf.load و rpaf.conf في الدليل mods-enabled. الآن قم بإجراء اختبار الضبط: $ sudo apachectl -t أعد تحميل Apache إذا لم يكن هنالك أخطاء: $ sudo systemctl reload apache2 قم بالوصول إلى الملف ()phpinfo في الصفحات http://foobar.net/info.php و http://test.io/info.php من متصفحك وتحقق من قسم PHP Variables. الآن سيكون المتغير REMOTE_ADDR هو أيضًا عنوان IP العام للحاسب المحلي لديك. الآن دعنا نعد تشفير TLS / SSL لكل موقع. الخطوة 9 - إعداد مواقع HTTPS باستخدام Let's Encrypt (اختياري) سنضبط في هذه الخطوة شهادات TLS / SSL لكل من النطاقات المُستضافة على Apache. سوف نحصل على الشهادات بواسطة [Let's Encrypt](https://letsencrypt.org]. يدعم Nginx إنهاء SSL، لذا من الممكن إعداد SSL بدون تعديل ملفات ضبط Apache. تَضمنْ الوحدة mod_rpaf أن يتم تعيين متغيرات البيئة المطلوبة على Apache لجعل التطبيقات تعمل بسلاسة خلفْ وكيل عكسي لـ SSL. أولاً سنفصل كتل الخادم {...}server من كِلا النطاقين بحيث يمكن أن يكون لكلٍ منهما شهادات SSL خاصّة به. افتح الملف etc/nginx/sites-available/apache/ في المحرّر الخاص بك: $ sudo nano /etc/nginx/sites-available/apache عدّل الملف بحيث يبدو مثل هذا، مع foobar.net و test.io في كتل الخادم الخاصّة بهم: /etc/nginx/sites-available/apache server { listen 80; server_name foobar.net www.foobar.net; location / { proxy_pass http://your_server_ip:8080; 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 $scheme; } } server { listen 80; server_name test.io www.test.io; location / { proxy_pass http://your_server_ip:8080; 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 $scheme; } } سنستخدم Certbot لإنشاء شهادات TLS/SSL الخاصّة بنا. ستتولى إضافة Nginx plugin" Nginx" مُهمة إعادة ضبط Nginx وإعادة تحميل الضبط عند الضرورة. أولاً، أضف مستودع Certbot المرخّص: $ sudo add-apt-repository ppa:certbot/certbot اضغط على ENTER عند مطالبتك بتأكيد رغبتك في إضافة المستودع الجديد. ثم قم بتحديث قائمة الحزم للحصول على معلومات حزمة المستودع الجديدة: $ sudo apt update ثم ثبّت حزمة Nginx الخاصّة بـ Certbot باستخدام apt: $ sudo apt install python-certbot-nginx وبمجرّد تثبيته، استخدم أمر certbot لإنشاء الشهادات لـ foobar.net و www.foobar.net: $ sudo certbot --nginx -d foobar.net -d www.foobar.net يخبر هذا الأمر Certbot ليستخدم ملحق nginx، وباستخدم –d لتحديد الأسماء التي نودّ أن تكون الشهادة صالحة لها. إذا كانت هذه هي المرة الأولى التي تُشغّل فيها certbot، فسَتتم مطالبتك بإدخال عنوان بريد إلكتروني والموافقة على شروط الخدمة. سيتصل بعد القيام بذلك certbot بخادم Let's Encrypt، ثم يشغّل ردّا للتحقق من أنّك تتحكم في النطاق الذي تطلب الحصول على شهادة له. سَيسألك Certbot بعد ذلك عن الطريقة التي ترغب في ضبط إعدادات HTTPS الخاصّة بك: Output Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access. ------------------------------------------------------------------------------- 1: No redirect - Make no further changes to the webserver configuration. 2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for new sites, or if you're confident your site works on HTTPS. You can undo this change by editing your web server's configuration. ------------------------------------------------------------------------------- Select the appropriate number [1-2] then [enter] (press 'c' to cancel): حدّد خيارك، ثم اضغط على ENTER. سيتم تحديث الضبط، وإعادة تحميل Nginx لتفعيل الإعدادات الجديدة. الآن، نفّذ الأمر للنطاق الثاني: $ sudo certbot --nginx -d test.io -d www.test.io انظر في قسم PHP Variables. تم تعيين المتغير SERVER_PORT على القيمة 443 وضبط HTTPS على القيمة on، كما لو أنّه تم الوصول إلى Apache مباشرةً عبر HTTPS. مع ضبط هذه المتغيرات، لن تحتاج تطبيقات PHP إلى إعداد خاص للعمل خلف وسيط عكسي. سنقوم الآن بتعطيل الوصول المباشر إلى Apache. الخطوة 10 - حظر الوصول المباشر إلى Apache (اختياري) بما أن Apache يستمع على المنفذ 8080 على عنوان IP العام، فإنّه بإمكان الجميع الوصول إليه. ويمكن حظره من خلال عمل الأمر IPtables التالي في مجموعة قواعد الجدار الناري. $ sudo iptables -I INPUT -p tcp --dport 8080 ! -s your_server_ip -j REJECT --reject-with tcp-reset تأكّد من استخدام عنوان IP لخَادمك مكان اللون الأحمر في المثال السابق. بمجرد حظر المنفذ 8080 في الجدار الناري، اختبر عدم إمكانية الوصول إلى Apache. افتح متصفح الويب الخاص بك وحاول الوصول إلى أحد أسماء نطاقات Apache على المنفذ 8080. على سبيل المثال: http://example.com:8080 يجب أن يعرض المتصفح رسالة خطأ "غير قادر على الاتصال" أو "صفحة الويب غير متوفرة". وبضبط خيار IPtables tcp-reset، لن يرى أحد أي اختلاف بين المنفذ 8080 والمنفذ الذي لا يحتوي أيّ خدمةٍ عليه. ملاحظة: عند إعادة تشغيل النظام وبشكل افتراضي لن تبقى قواعد IPtables كما حدّدناها. هناك طرق متعددة للحفاظ على قواعد IPtables، ولكن أسهلها هو استخدام iptables-persistent في مستودع Ubuntu. استكشف هذه المقالة لمعرفة المزيد حول كيفيّة ضبط IPTables. لنضبط الآن Nginx لخدمة ملفات ثابتة لمواقع Apache. الخطوة 11 - تخديم الملفات الثابتة باستخدام Nginx (اختياري) عندما يقدم وسيط Nginx طلبات لنطاقات Apache، فإنّه يرسل كل ملف طلب لهذا النطاق إلى Apache. Nginx أسرع من Apache في خدمة الملفات الثابتة مثل الصور، وجافا سكريبت وأوراق الأنماط. لذلك دعونا نضبط ملف مضيف apache افتراضي خاص بـ Nginx لتخديم الملفات الثابتة مباشرة ولكن مع إرسال طلبات PHP إلى Apache. افتح الملف etc/nginx/sites-available/apache/ في محرّرك الخاص: $ sudo nano /etc/nginx/sites-available/apache ستحتاج إلى إضافة موضعين location إضافيين لكل كتلة خادم، بالإضافة إلى تعديل أقسام location الموجودة. بالإضافة إلى ذلك، ستحتاج إلى إخبار Nginx بمكان تواجد الملفات الثابتة لكل موقع. إذا قرّرت عدم استخدام شهادات SSL و TLS، فعدّل ملفك بحيث يبدو كالتالي: /etc/nginx/sites-available/apache server { listen 80; server_name test.io www.test.io; root /var/www/test.io; index index.php index.htm index.html; location / { try_files $uri $uri/ /index.php; } location ~ \.php$ { proxy_pass http://your_server_ip:8080; 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 $scheme; } location ~ /\.ht { deny all; } } server { listen 80; server_name foobar.net www.foobar.net; root /var/www/foobar.net; index index.php index.htm index.html; location / { try_files $uri $uri/ /index.php; } location ~ \.php$ { proxy_pass http://your_ip_address:8080; 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 $scheme; } location ~ /\.ht { deny all; { { إذا كنت تريد بأن يكون HTTPS متوفرًا أيضًا، فاستخدم الضبط التالي بدلاً من ذلك: server { listen 80; server_name test.io www.test.io; root /var/www/test.io; index index.php index.htm index.html; location / { try_files $uri $uri/ /index.php; } location ~ \.php$ { proxy_pass http://your_server_ip:8080; 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 $scheme; } location ~ /\.ht { deny all; } listen 443 ssl; ssl_certificate /etc/letsencrypt/live/test.io/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/test.io/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; } server { listen 80; server_name foobar.net www.foobar.net; root /var/www/foobar.net; index index.php index.htm index.html; location / { try_files $uri $uri/ /index.php; } location ~ \.php$ { proxy_pass http://your_ip_address:8080; 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 $scheme; } location ~ /\.ht { deny all; } listen 443 ssl; ssl_certificate /etc/letsencrypt/live/foobar.net/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/foobar.net/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; { إنّ التوجيه try_files يجعل Nginx يبحث عن الملفات في المستند الجذر ويقدّمها مباشرةً. إذا كان الملف له امتداد php.، سيتم تمرير الطلب إلى Apache. حتى إذا لم يُعثر على الملف في المستند الجذر، يُمرّر الطلب إلى Apache لتعمل ميزات التطبيق مثل permalinks بدون أخطاء. تحذير: إنّ التوجيه location ~ /\.ht مهم جداً؛ حيث يمنع Nginx من عرض محتويات ملفات الضبط Apache مثل htaccess. و htpasswd. التي تحتوي على معلومات حساسة. احفظ الملف وقم بإجراء اختبار الضبط: $ sudo nginx -t أعد تحميل Nginx إذا نجح الاختبار: $ sudo service nginx reload يمكنك للتحقّق من أن العمل تم بشكل صحيح فحص ملفات سجل Apache في var/log/apache2/ ومشاهدة طلبات GET لملفات info.php من test.io و foobar.net. استخدم الأمر tail لمشاهدة الأسطر القليلة الأخيرة من الملف، واستخدم رمز التبديل f- لمشاهدة الملف من أجل التغييرات: $ sudo tail -f /var/log/apache2/other_vhosts_access.log قم الآن بزيارة http://test.io/info.php في مستعرض الويب الخاص بك ثم انظر إلى خرج السجل. سترى أن Apache يجيب بالفعل: Output test.io:80 your_server_ip - - [01/Jul/2016:18:18:34 -0400] "GET /info.php HTTP/1.0" 200 20414 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36" ثم قم بزيارة صفحة index.html لكل موقع ولن ترى أي إدخالات للسجّل من قبل Apache. لأن Nginx هو من يخدّمهم. عند الانتهاء من معاينة ملف السجل، اضغط على CTRL + C لإيقاف تعقبّه. باستخدام هذا الإعداد، لن يكون Apache قادرًا على تقييد الوصول إلى الملفّات الثابتة. وللتَحكم في الوصول إلى الملفّات الثابتة تحتاج إلى ضبط في ملف المضيف apache الافتراضي الخاص بـ Nginx، ولكن هذا خارج نطاق هذه الدورة التعليميّة. الخلاصة لديك الآن خادم Ubuntu مع Nginx يُخدّم example.com و sample.org، جنبًا إلى جنب مع Apache والذي يُخدّم foobar.net و test.io. على الرغم من أن Nginx يعمل كوكيل عكسي لـ Apache، إلا أن خدمة الوكيل في Nginx تتسم بالشفافية وتُظهر اتصالها بنطاقات Apache كما لو أنها مخدّمة مباشرةً من Apache. يمكنك استخدام هذه الطريقة لتخديم مواقع آمنة وثابتة. ترجمة بتصرف للمقال How To Configure Nginx as a Web Server and Reverse Proxy for Apache on One Ubuntu 18.04 Server لصاحبه Jesin A.
  6. يشرح هذا الدّرس كيفيّة نشر Nginx في حاوية Docker container. نقلّل باحتواء Nginx من نفقات إدارة النظام، فلن نعود في حاجة إلى إدارة Nginx عبر مُدير الحِزَم أو بنائِه من المصدر، تسمح لنا حاوية Docker ببساطة أن نستبدل كامل الحاوية عند إطلاق إصدار جديد من Nginx، نحتاج فقط إلى الحفاظ على ملفّات إعدادات Nginx ومحتوانا. يصف Nginx نفسه كما يلي: يُستَخدَم Nginx من قبل العديد من مديري النُظُم sysadmins في الممارسة العمليّة لتخديم محتوى الويب، ابتداءً من مواقع الملفّات الثابتة flat-file وحتى upstream APIs في NodeJS، سنقوم في هذا الدّرس بتخديم صفحة ويب أساسيّة حتى نستطيع التركيز على إعداد Nginx مع حاوية Docker. إنّ حاويات Docker هي شكل شائع من ممارسات عمليّة قديمة نسبيًّا وهي الاحتواء containerization. يختلف الاحتواء عن الآلات الافتراضية (virtualization) في أنّ الإيهام يقوم بعزل العتاد hardware بعيدًا، بينما يقوم الاحتواء بعزل نظام التشغيل الأساسي بعيدًا أيضًا، يعني هذا من النّاحية العمليّة أنّه يمكننا أخذ تطبيق (أو مجموعة تطبيقات) ووضعها في حاوية (أو حاويات) لجعلها من النمط التركيبي modular، محمولة portable، قابلة للتركيب composable، وخفيفة الوزن lightweight. تعني قابليّة النقل portability أنّنا نستطيع تثبيت مُحرِّك Docker Engine (تتم الإشارة له أيضًا بلُب Docker Core، أو حتى Docker فقط) على مجموعة واسعة من أنظمة التّشغيل، وأي حاوية وظيفيّة مكتوبة من قبل أي شخص ستعمل عليه. إن أردت تعلّم المزيد حول Docker بإمكانك الاطلاع على درس Docker التّمهيدي. سنقوم بتثبيت مُحرِّك Docker على Ubuntu لأغراض هذا الدّرس. سنثبّت إصدار Docker المستقر الحالي لـ Ubuntu وهو 1.8.1. هذا الدّرس مُخصَّص لمستخدمي Nginx الجديدين على Docker، إن كنت تريد الأوامر المجرّدة لإعداد حاوية Nginx لديك تستطيع تطبيق الخطوة الأولى ومن ثمّ الانتقال إلى الخطوة الخامسة. إن كنت ترغب ببناء حاويتك خطوة بخطوة والتعلّم عن تعيين المنافذ port mapping والوضع المنفصل detached mode فقم باتّباع كامل الدّرس. المتطلبات الأساسيةمن أجل احتواء Nginx يجب علينا إتمام ما يلي: إعداد خادوم Ubuntu ويُفضَّل أن يكون مع مفاتيح SSH Keys من أجل الأمان.إعداد مستخدم بصلاحيات الجذر sudo.التحقّق من إصدار النّواة Kernel لدينا.يعتمد Docker 1.8.1 إلى حدٍّ ما على بعض الميّزات الأخيرة للنواة، لذا تأكّد من أن يكون إصدار النّواة 3.10 أو أعلى، تمتلك أنظمة تشغيل لينِكس الحديثة نواة جديدة نسبيًّا، ولكن إن كنت تريد التحقّق قم بتنفيذ الأمر uname –r: uname -rلقد قمنا بتضمين الخَرْج output من نسخة Ubuntu 14.04، والتي تحتوي إصدار نواة أعلى من 3.10، لذا لا يجب أن تقلق ما لم تقم بتنفيذ هذا الأمر على نسخة أقدم: 3.13.0-57-genericالخطوة الأولى – تثبيت Dockerيستضيف Docker على موقعه script بدء للحصول على Docker وتشغيله على جهازنا، نستطيع ببساطة تنفيذ الأمر: sudo curl -sSL https://get.docker.com/ | shلا ينبغي بشكل عام تمرير scripts عشوائيّة من الإنترنت إلى الصّدفة Shell عن طريق الأنبوب (Pipe (| sh، لأنّها قد تقوم بفعل أي شيء، ألقِ نظرة على get.docker.com إن كنت تريد معرفة ما أنت مُقبِلٌ عليه. بعد أن ينتهي تنفيذ الأمر السّابق سنرى الإصدار المُثبَّت كما يلي (قد تكون الأرقام لديك أحدث ولا مشكلة في هذا) وبعض التعليمات حول التشغيل كمستخدم غير جذري non-root\بدون sudo، نقوم في هذا الدّرس بالتشغيل كمستخدم sudo لذا لا داعي للقلق حول هذا الأمر: Client: Version: 1.8.3 API version: 1.20 Go version: go1.4.2 Git commit: f4bf5c7 Built: Mon Oct 12 05:37:18 UTC 2015 OS/Arch: linux/amd64 Server: Version: 1.8.3 API version: 1.20 Go version: go1.4.2 Git commit: f4bf5c7 Built: Mon Oct 12 05:37:18 UTC 2015 OS/Arch: linux/amd64اختياري: قم بتشغيل الحاوية hello-world للتحقّق من أنّ كل شيء يعمل كما هو متوقَّع: sudo docker run hello-worldيجب أن ترى خَرْجًا مشابهًا للتالي: $ docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 535020c3e8ad: Pull complete af340544ed62: Already exists library/hello-world:latest: The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security. Digest: sha256:d5fbd996e6562438f7ea5389d7da867fe58e04d581810e230df4cc073271ea52 Status: Downloaded newer image for hello-world:latest Hello from Docker. This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker Hub account: https://hub.docker.com For more examples and ideas, visit: https://docs.docker.com/userguide/نستطيع بعد الانتهاء ممّا سبق الخوض في أساسيّات Docker. الخطوة الثانية (اختيارية) – مراجعة أساسيات الحاوية: التشغيل Run، السرد List، الإزالة Removeيشرح هذا القسم كيفيّة تشغيل حاوية أساسيّة ومن ثمّ إزالتها، إن كنت تعرف مُسبقًا كيفيّة استخدام Docker بشكل عام وتريد التخطّي إلى القسم المتعلّق بـ Nginx فاذهب إلى الخطوة الخامسة. لقد ثبّتنا عميل Docker Client كجزء من تثبيت Docker لدينا، لذا نمتلك أداة سطر الأوامر التي تسمح لنا بالتفاعل مع حاوياتنا. إن قمنا بتنفيذ الأمر التالي: sudo docker ps -aينبغي أن نحصل على خَرْج مُشابِه لما يلي: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a3b149c3ddea hello-world "/hello" 3 minutes ago Exited (0) 3 minutes ago nostalgic_hopperنستطيع مشاهدة بعض المعلومات الأساسيّة حول حاويتنا. سنلاحظ أنّها تملك اسمًا لا معنى له مثل nostalgic_hopper، يتم توليد هذه الأسماء تلقائيًّا إن لم نُحدِّد اسمًا عند إنشاء الحاوية. نرى أيضًا في هذا المثال أنّه تم تشغيل الحاوية منذ 3 دقائق وتم إنشاؤها منذ 3 دقائق. إن قمنا بتشغيل الحاوية مرّة أخرى باستخدام هذا الأمر (مع وضع اسم حاويتنا بدلًا من nostalgic_hopper): sudo docker start nostalgic_hopperومن ثمّ نفّذنا الأمر التالي لعرض الحاويات: sudo docker ps -aيجب أن نشاهد أنّه تم تشغيل الحاوية مؤخّرًا: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a3b149c3ddea hello-world "/hello" 4 minutes ago Exited (0) 9 seconds ago nostalgic_hopperتقوم حاويات Docker افتراضيًّا بتنفيذ الأوامر المسندة إليها ومن ثمّ الخروج. تكون بعض الحاويات مُعدّة لتنفيذ بعض المهام ومن ثمّ الانتهاء من ذلك، بينما يبقى بعضها يعمل بدون وقت مُحدّد. الآن وقد مررنا على بعض أساسيّات Docker فلنقم بإزالة الصّورة image التي تُدعى hello-world، حيث أنّنا لن نحتاجها مرّة أخرى (تذكّر أن تضع اسم حاويتك بدلًا من nostalgic_hopper أو استخدم مُعرِّف ID الحاوية). سنبدأ بعد ذلك باستخدام Nginx. الخطوة الثالثة (اختيارية) – تعلم كيفية عرض expose المنفذ portسنقوم في هذا القسم بتنزيل صورة Nginx Docker image ونرى كيفيّة تشغيل الحاوية بحيث تكون مُتاحة للعوام كخادوم ويب. تكون الحاويات افتراضيًّا غير مُتاحة للوصول من قبل الإنترنت، لذا نحتاج إلى تعيين منفذ الحاوية الدّاخلي إلى منفذ Droplet لدينا، هذا ما سنتعلّمه في هذا القسم. سنحصل في البداية على صورة Nginx. تحتوي الخطوة الخامسة على الأوامر النهائيّة لنشر الحاوية كاملة، لذا إن لم تكن مهتمًّا بتفاصيل التنفيذ تستطيع التخطّي والانتقال إلى هناك. نقوم بتنفيذ الأمر التالي للحصول على صورة Nginx Docker: sudo docker pull nginxيقوم هذا بتنزيل جميع العناصر الضّروريّة للحاوية، يُخبِّئ Docker كل هذا في ذاكرة مؤقتة cache حتى لا نحتاج إلى تنزيل صورة الحاوية في كل مرّة نريد فيها تشغيل الحاوية. تحتفظ Docker بموقع يُدعى Dockerhub وهو مستودع عام لملفّات Docker (يتضمّن كل من الصّور الرسميّة والمُقدَّمة من قبل المستخدمين)، الصّورة التي قمنا بتنزيلها هي صورة Nginx الرسميّة، والتي توفّر علينا عناء بناء الصّورة الخاصّة بنا. فلنقم بتشغيل حاوية Nginx Docker باستخدام هذا الأمر: sudo docker run --name docker-nginx -p 80:80 nginxrun هو أمر إنشاء حاوية جديدة يُحدِّد العَلَم name-- اسم الحاوية (إن تركناه فارغًا سيتم تعيينه تلقائيًّا لنا، مثل nostalgic_hopper في الخطوة الثّانية)يُحدِّد p- المنفذ الذي نقوم بعرضه على هيئة p local-machine-port:internal-container-port-، في هذه الحالة نقوم بتعيين المنفذ 80 في الحاوية إلى المنفذ 80 على الخادومnginx هو عبارة عن اسم الصورة على dockerhub (قمنا بتنزيلها من قبل باستخدام الأمر pull، ولكن يقوم Docker بهذا تلقائيًّا إن كانت الصورة مفقودة)هذا هو كل ما نحتاجه للحصول على Nginx وتشغيله، نقوم الآن بكتابة عنوان IP لـ Droplet لدينا في متصفّح الويب وهنا يجب أن نرى صفحة "Welcome to nginx". سنلاحظ أيضًا في جلسة الصّدفة shell لدينا أنّه يتم تحديث سِجِل Nginx عندما نقوم بطلبات إلى خادومنا، لأنّنا نشغّل الحاويات لدينا بشكل تفاعلي. فلنضغط على الاختصار CTRL+C للعودة إلى جلسة الصّدفة shell لدينا. إن حاولنا الآن تحميل الصفحة سنتلقّى الصّفحة "تم رفض الاتصال" "connection refused"، وقد حدث هذا لأنّنا قمنا بإيقاف تشغيل حاويتنا، بإمكاننا التحقّق من ذلك باستخدام هذا الأمر: sudo docker ps -aيجب أن نرى شيئًا مشابهًا للخَرْج التّالي: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 05012ab02ca1 nginx "nginx -g 'daemon off" 57 seconds ago Exited (0) 47 seconds ago docker-nginxنستطيع أن نرى أنّه تمّ الخروج من حاوية Docker لدينا. لن يكون Nginx مفيدًا جدًّا إن كان يجب علينا أن نكون متصلين attached إلى صورة الحاوية من أجل أن يعمل، لذا سنشرح في الخطوة التالية كيفية فصل detach الحاوية للسماح لها بالعمل بشكل مستقل. نقوم بإزالة الحاوية docker-nginx الحالية عن طريق هذا الأمر: sudo docker rm docker-nginxسنشرح في الخطوة التالية كيفيّة تشغيلها في الوضع المنفصل detached mode. الخطوة الرابعة (اختيارية) – تعلم كيفية التشغيل في الوضع المنفصلنُنشِئ حاوية Nginx جديدة منفصلة باستخدام هذا الأمر: sudo docker run --name docker-nginx -p 80:80 -d nginxأضفنا العَلَم d- لتشغيل هذه الحاوية في الخلفيّة. يجب أن يكون الخَرْج ببساطة مُعرِّف ID الحاوية الجديدة. إن قُمنا بتشغيل أمر السّرد list: sudo docker psسنرى في الخَرْج العديد من الأشياء التي لم نشاهدها من قبل: CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b91f3ce26553 nginx "nginx -g 'daemon off" About a minute ago Up About a minute 0.0.0.0:80->80/tcp, 443/tcp docker-nginxبإمكاننا أن نرى أنّه بدلًا من Exited (0) X minutes ago نمتلك الآن Up About a minute، ونرى أيضًا تعيين المنفذ port mapping. إن ذهبنا إلى عنوان IP خادومنا باستخدام المتصفّح فسنشاهد الصفحة "!Welcome to nginx" مرّة أخرى، ولكن في هذه المرّة تعمل الحاوية في الخلفيّة لأنّنا حدّدنا العَلَم d- والذي يُخبِر Docker أن يُشغِّل هذه الحاوية في الوضع المنفصل. نمتلك الآن نسخة من Nginx تعمل في الوضع المنفصل. وبالرغم من ذلك فهي ليست مفيدة بما فيه الكفاية حتى الآن، لأنّنا لا نستطيع تحرير edit ملف الإعدادات ولا تمتلك الحاوية نفاذًا إلى أي من ملفّات مواقع الويب لدينا. نوقف الحاوية بتنفيذ الأمر التّالي: sudo docker stop docker-nginxوالآن وقد توقفت الحاوية عن العمل (نستطيع التحقّق باستخدام الأمر sudo docker ps –a إن أردنا أن نكون متأكدين من ذلك) فبإمكاننا إزالتها بتنفيذ الأمر التّالي: sudo docker rm docker-nginxسنصل الآن إلى الإصدار النّهائي لحاويتنا مع وقفة سريعة لإنشاء ملف مُخصَّص لموقع الإنترنت. الخطوة الخامسة – بناء صفحة ويب ليتم تخديمها على Nginxسنُنشِئ في هذه الخطوة صفحة فهرس index مُخصَّصة لموقعنا، يسمح لنا هذا الإعداد بأن نملك محتوى للموقع بشكل دائم تتم استضافته خارج الحاوية (العابرة transient). فلنقم بإنشاء دليل جديد من أجل محتوى موقعنا بداخل الدّليل الرئيسي home directory والانتقال إليه بتنفيذ الأوامر التالية: mkdir -p ~/docker-nginx/html cd ~/docker-nginx/htmlنُنشِئ الآن ملف HTML (طبّقنا الأوامر من أجل مُحرِّر النّصوص Vim ولكن تستطيع استخدام أي مُحرِّر نصوص آخر). vim index.htmlننتقل إلى وضع الإدخال insert mode عن طريق الضغط على i، ونلصق المحتوى التّالي بداخل الملف السّابق (أو بإمكانك إضافة محتوى HTML الخاص بك): <html> <head> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" integrity="sha256-MfvZlkHCEqatNoGiOXveE8FIwMzZg4W85qfrfIFBfYc= sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous"> <title>Docker nginx Tutorial</title> </head> <body> <div class="container"> <h1>Hello Digital Ocean</h1> <p>This nginx page is brought to you by Docker and Digital Ocean</p> </div> </body> </html>إن كنت على معرفة بـ HTML سترى أنّها صفحة ويب بسيطة، قمنا بتضمين وسم <link> يُشير إلى شبكة توزيع محتوى CDN من أجل Bootstrap (وهو إطار عمل CSS يُعطي لصفحتنا مجموعة من التنسيقات المتجاوبة responsive)، تستطيع قراءة المزيد عن Bootstrap. نحفظ هذا الملف الآن عن طريق الضغط على ESC ومن ثمّ wq: و ENTER: تُخبِر (write (w أن يقوم Vim بكتابة التغييرات إلى الملف.تُخبِر (quit (q أن يقوم Vim بالخروج.نمتلك الآن صفحة فهرس index بسيطة بدلًا من صفحة هبوط Nginx الافتراضيّة. الخطوة السادسة – ربط الحاوية إلى نظام الملفات المحليفي هذا القسم سنضع كل ما سبق معًا، سنقوم بتشغيل حاوية Nginx لدينا بحيث تكون قابلة للنفاذ على الإنترنت عبر المنفذ 80، وسنقوم بتوصيلها إلى محتوى موقع الويب لدينا على الخادوم. معلومات أساسية حول مسارات التخزين (volumes) والتي هي الرّبط إلى محتوى خادوم بشكل دائم من قبل الحاوية الخاصة بنايسمح لنا Docker بربط الأدلّة directories من نظام الملفّات المحلّي للجهاز الافتراضي Virtual Machine لدينا إلى حاوياتنا. وفي حالتنا بما أنّنا نريد تخديم صفحات ويب نحتاج إلى إعطاء حاويتنا الملفّات التي نريد تقديمها. كان باستطاعتنا نسخ الملفّات إلى الحاوية كجزء من ملفّات Docker، أو نسخها إلى الحاوية بعد إسقاطها أو توقيفها، ولكن هاتين الطريقتين تبقيان موقعنا في حالة ثابتة بداخل حاويتنا، أمّا باستخدام ميزة حجوم volumes البيانات بإمكاننا إنشاء ارتباط رمزي بين نظام ملفّات Droplet ونظام ملفّات الحاوية، يسمح لنا هذا بتحرير ملفّات صفحات الويب الموجودة حاليًّا وإضافة ملفّات جديدة إلى الدّليل وستكون الحاوية قادرة على النفاذ لها بشكل تلقائي، إن كنت ترغب بقراءة المزيد حول Docker ومسارات التخزين volumes تحقّق من وثائق حجوم البيانات data volumes. تكون حاوية Nginx مُعدَّة افتراضيًّا لتبحث عن صفحة فهرس index في المسار usr/share/nginx/html/، لذا نحتاج في حاوية Docker الجديدة الخاصّة بنا أن نقوم بإعطائها نفاذًا إلى ملفّاتنا في ذلك الموقع. إنشاء الربطلإنشاء الربط نستخدم العَلَم v- لتعيين مُجلَّد من جهازنا المحلّي (docker-nginx/html/~) إلى مسار نسبي في الحاوية (usr/share/nginx/html/). نستطيع إتمام هذا بتنفيذ الأمر التالي: sudo docker run --name docker-nginx -p 80:80 -d -v ~/docker-nginx/html:/usr/share/nginx/html nginxنرى أنّ الإضافة الجديدة إلى الأمر v ~/docker-nginx/html:/usr/share/nginx/html- هي رابط مسار تخزين volume لدينا. تُحدِّد v- أنّنا نقوم بربط مسار تخزين volume.الجزء الذي على يسار ":" هو موقع ملفّنا/دليلنا على الجهاز الافتراضي (docker-nginx/html/~).الجزء الذي على يمين ":" هو الموقع الذي نقوم بالرّبط إليه في حاويتنا (usr/share/nginx/html/).إن قمنا بعد تنفيذ هذا الأمر بالتوجّه باستخدام المتصفّح إلى عنوان IP الخاص بـ DigitalOcean Droplet مثلا (إن كنت على DigitalOcean) لدينا فيجب أن نرى الترويسة الأولى من Hello Digital Ocean (أو أي صفحة ويب أنشأتها في الخطوة الخامسة). إن كنت سعيدًا بإعدادات Nginx الافتراضيّة الأخرى فأنت الآن جاهز. تستطيع رفع المزيد من المحتوى إلى الدّليل docker-nginx/html/~ وستتم إضافته إلى موقعك بشكل مباشر. إن قمنا على سبيل المثال بتعديل ملف الفهرس لدينا وأعدنا تحميل نافذة متصفحنا، سنرى أنّ التحديث يحدث آنيًّا، نستطيع بناء موقع كامل من ملفّات HTML ثابتة بهذه الطريقة، على سبيل المثال إن أضفنا صفحة about.html فبإمكاننا النفاذ إليها على الرّابط http://your_server_ip/about.html بدون الحاجة للتعامل مع حاويتنا. الخطوة السابعة (اختيارية) – استخدام ملف إعدادات Nginx الخاص بناهذ القسم مُخصَّص للمستخدمين المتقدّمين الذين يرغبون باستخدام ملف إعدادات Nginx الخاص بهم مع حاوية Nginx لديهم، قم بتجاوز هذه الخطوة إن كنت لا تملك ملف إعدادات مُخصَّص تريد استخدامه. فلنقم بالعودة دليلًا إلى الوراء كيلا نكتب إلى دليل HTML المتاح للعوام لدينا: cd ~/docker-nginxإن كنّا نرغب بإلقاء نظرة على ملف الإعدادات الافتراضي نقوم فقط بنسخه باستخدام أمر Docker للنسخ: sudo docker cp docker-nginx:/etc/nginx/conf.d/default.conf default.confوبما أنّنا سنقوم باستخدام ملف conf. مُخصَّص من أجل Nginx سنحتاج إلى إعادة بناء الحاوية. نقوم في البداية بإيقاف الحاوية: sudo docker stop docker-nginxنزيل الحاوية باستخدام الأمر: sudo docker rm docker-nginxنستطيع الآن تحرير الملف الافتراضي محليًّا (لتخديم دليل جديد أو استخدام proxy_pass لتمرير حركة مرور البيانات traffic إلى تطبيق أو حاوية أخرى كما كنّا نفعل مع تثبيت Nginx الاعتيادي)، تستطيع القراءة حول ملف إعدادات Nginx في دليل ملف إعدادات Nginx. بعد أن نقوم بحفظ ملف إعداداتنا المُخصَّص يحين الوقت لصنع حاوية Nginx، نضيف ببساطة علم v- آخر مع المسار المناسب لإعطاء حاوية Nginx الجديدة الروابط المناسبة لتعمل من خلال ملف إعداداتنا: sudo docker run --name docker-nginx -p 80:80 -v ~/docker-nginx/html:/usr/share/nginx/html -v ~/docker-nginx/default.conf:/etc/nginx/conf.d/default.conf -d nginxلا يزال هذا الأمر يربط صفحات الموقع المُخصَّصة إلى الحاوية أيضًا. نلاحظ أنّنا سنحتاج إلى إعادة تشغيل الحاوية باستخدام الأمر docker restart بعد أي تغيير لملف الإعدادات أثناء تشغيل الحاوية، لأنّ Nginx لا يقوم بإعادة تحميل فوري إن تمّ تغيير ملف إعداداته: sudo docker restart docker-nginxالخاتمة نمتلك الآن حاوية Nginx قيد التشغيل وتُخدِّم صفحة ويب مُخصَّصة. نوصي من هذه النقطة القراءة حول ربط حاوية Docker إن كنت تريد التعلّم حول ربط الحاويات ببعضها لأغراض استخدام Nginx كوسيط عكسي reverse proxy لتخديم تطبيقات الويب الأخرى المعتمدة على الحاوية. إن كنت تريد إدارة مجموعة من الحاويات مثل حاوية تطبيق، حاوية قاعدة بيانات، وحاوية Nginx، فألقِ نظرة على تركيب Docker Compose. ترجمة -وبتصرّف- لـ How To Run Nginx in a Docker Container on Ubuntu 14.04 لصاحبه Thomas Taege.
  7. ما هي Let’s Encrypt هي هيئة شهادات مجانية تابعة لمجموعة أبحاث أمن الإنترنت-Internet Security Research Group (ISRG)، وتقدم هذه الهيئة طريقة سهلة ومؤتمتة للحصول على شهادات SSL/TLS مجانية لجعل الزيارات على خادم الويب مشفرة وعبر بروتوكول HTTPS. ومعظم خطوات الحصول على الشهادة وتثبيتها يمكن جعلها تتم تلقائيًا باستخدام أداة Certbot. وهذه الأداة يمكن استخدامها حين يتسنى الاتصال بالخادم عبر SSH، أي حين يوجد دخول من الصدفة “Shell” على الخادم. وسنرى في هذا المقال كيف نستخدم Certbot للحصول على شهادة SSL مجانية ومن ثم استخدامها مع NGINX على خادم أوبنتو 16.04 تثبيت Certbot سنضيف مستودع Certbot أولًا، لماذا؟ لأن مطوريه يقومون على صيانة وتحديث هذا المستودع بآخر إصدار من Certbot أولًا بأول، بشكل أسرع مما تفعله أوبنتو بالبرنامج في مستودعاتها، فأوبنتو تحتاج وقتًا لمراجعة كل برنامج يدخل مستودعاتها، خاصة إن كان في إصدار LTS مثل 16.04، وبالتالي فمن الطبيعي أن يتأخر كل برنامج قليلًا حتى يدخل تلك المستودعات. والآن، لإضافة مستودع Certbot: # add-apt-repository ppa:certbot/certbot ثم نحدّث قائمة APT # apt-get update ونثبّت البرنامج # apt-get install certbot الحصول على الشهادة هناك العديد من إضافات Certbot التي يمكن الحصول على شهادة SSL من خلالها، ويقوم مدير الخادم بتثبيتها وتهيئة الخادم بعد ذلك بنفسه. وسنستخدم إضافة Webroot في هذا المقال، وهي إضافة تصلح للحالات التي يمكن فيها تعديل المحتوى، ولسنا في حاجة لإيقاف الخادم أثناء عملية تصدير الشهادة. تهيئة NGINX تنشئ Webroot ملفًا مؤقتًا لكل نطاق في مجلد مخفي اسمه well-known، موجود في المجلد الجذر لـweb، وفي حالتنا فإن مجلد web موجود في var/www/html/. تأكد أن Let’s Encrypt لديها صلاحية الوصول لهذا المجلد، من خلال تعديل تهيئة NGINX. ولفعل ذلك، نفذ هذا الأمر لفتح الملف الذي سنعدّل فيه (استبدل $EDITOR بمحرر نصي من تفضيلك): # $EDITOR /etc/nginx/sites-available/default ضع هذه الأسطر في قسم server داخل الملف: location ~ /.well-known { allow all; } احفظ الملف واخرج، ثم تفقد تهيئة NGINX عبر الأمر التالي: # nginx -t ويجب أن ترى هذين السطرين -بفرض نجاح الأمر-: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful والآن أعد تشغيل NGINX: # systemctl restart nginx الحصول على الشهادة باستخدام Certbot الخطوة التالية هي الحصول على شهادة جديدة باستخدام Certbot مع إضافة Webroot. وسنؤمّن في هذا الشرح (كمثال) نطاق www.example.com عبر الأمر التالي: (لا تنسى أنك يجب أن تحدد كل نطاق تريد تأمينه بهذه الشهادة). # certbot certonly --webroot --webroot-path=/var/www/html -d www.example.com سيسألك Certbot خلال العملية عن بريد إلكتروني صالح من أجل الإشعارات، وسيطلب منك مشاركته مع EFF، غير أن ذلك غير ضروري، وسيكون لديك الشهادةبعد الموافقة على شروط الخدمة. وبعد انتهاء العملية، سيحتوى مجلد etc/letsencrypt/archive/ على الملفات التالية: chain.pem: شهادة السلسلة-Chain Certificate الخاصة بـLet’s Encrypt. cert.pem: شهادة النطاق. fullchain.pem: دمج للشهادتين السابقتين. privkey.pem: المفتاح الخاص للشهادة. كما سينشئ Certbot روابط رمزية لآخر ملفات الشهادة في etc/letsencrypt/live/domain_name/، وهو المسار الذي سنستخدمه في تهيئة الخادم. تهيئة SSL/TLS على NGINX الخطوة التالية هي تهيئة الخادم، أنشئ قصاصة-snippet جديدة في etc/nginx/snippets، تلك القصاصة هي جزء من ملف تهيئة يمكن إدراجه في ملفات تهيئة المضيف الوهمي-virtual host. أنشئ ملف جديد (استخدم محررك النصي بدلًا من $EDITOR) # $EDITOR /etc/nginx/snippets/secure-example.conf محتويات هذا الملف ستكون الموجّهات التي تحدد مواقع الشهادة والمفتاح، الصق المحتوى التالي في الملف: ssl_certificate /etc/letsencrypt/live/domain_name/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/domain_name/privkey.pem; في مثالنا الذي نشرحه، سيكون domain_name هو example.com. تعديل تهيئة NGINX افتح الملف الافتراضي للمضيف الوهمي: # $EDITOR /etc/nginx/sites-available/default عدل محتواه كما يلي: server { listen 80 default_server; listen [::]:80 default_server; server_name www.example.com return 301 https://$server_name$request_uri; # SSL configuration # listen 443 ssl default_server; listen [::]:443 ssl default_server; include snippets/secure-example.conf # # Note: You should disable gzip for SSL traffic. # See: https://bugs.debian.org/773332 … كان هذا الكود من أجل تفعيل التشفير في NGINX، احفظ الملف واخرج ثم تأكد من ملف تهيئة NGINX: # nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful أعد تشغيل NGINX: # systemctl restart nginx خاتمة إن اتبعت الخطوات السابقة فيجب أن يكون لديك الآن خادم آمن مبني على NGINX، مع تشفير من Certbot وLet’s Encrypt. وهذه إعدادات أساسية قطعًا، فيمكنك استخدام معاملات-parameters كثيرة في NGINX لتعديل تهيئته وتخصيصه، حسب حاجة خادم الويب. ترجمة -بتصرف- لمقال Encryption: How To Secure an NGINX web server on Ubuntu 16.04 لصاحبه Giuseppe Molica
  8. حاوية لينكس هي مجموعة من العمليات المعزولة عن بقية النظام من خلال استخدام ميزات أمان نواة لينكس، مثل مساحات الأسماء ومجموعات التحكم. إنها بناء مماثل للآلة الافتراضية، و لكنه أكثر خفة منها، فإن لم يكن لديك النفقات الكافية لتشغيل أنوية إضافية أو آلات افتراضية فلا تقلق من ذلك، لأنه يمكنك بسهولة إنشاء حاويات متعددة على نفس الخادوم. على سبيل المثال، تخيل أن لديك خادوم يقوم بتشغيل مواقع ويب متعددة لعملائك. في حال التثبيت التقليدي سيكون كل موقع على شبكة الانترنت مضيفًا افتراضيًا من نفس حالة خادوم apache أو Nginx. ولكن مع حاويات لينكس يمكن لكل موقع على شبكة الإنترنت أن يثبت في حاوية خاصة به مع خادوم الويب الخاص بها. باستخدام حاويات لينكس يمكنك تجميع التطبيق الخاص بك واعتمادياته في حاوية دون التأثير على بقية النظام. يتيح لك LXD إنشاء هذه الحاويات وإدارتها. يوفر LXD خدمة مراقب الأجهزة الافتراضية لإدارة دورة الحياة الكاملة للحاويات. في هذا الدرس سوف نقوم بإعداد LXD واستخدامه لتشغيل Nginx في حاوية. وستقوم بعد ذلك بتوجيه حركة المرور إلى الحاوية من أجل جعل موقع الويب ممكن الوصول إليه من الإنترنت. المتطلبات الأساسية لإكمال هذا الدرس ستحتاج إلى ما يلي: خادوم أوبونتو 16.04 مُعَد مسبقا ، يمكنك الرجوع إلى هذه المقال لتعرف كيف تفعل ذلك: الإعداد الابتدائي لخادوم أوبنتو 14.04 مستخدم غير جذر يملك صلاحيات الجذر وجدار الحماية. اختياريًا أضف 20 جيغا أو أكثر من مساحة التخزين ، يمكنك استخدام ذلك لتخزين كافة البيانات المتعلقة بالحاويات. الخطوة 1 : إعداد LXD تم تثبيت LXD بالفعل على أوبونتو، ولكن يجب أن يتم إعداده بشكل مناسب قبل أن تتمكن من استخدامه على الخادوم. يجب عليك إعداد حساب المستخدم لإدارة الحاويات، ثم إعداد نوع قاعدة التخزين لتخزين الحاويات وإعداد الشبكة. قم بتسجيل الدخول إلى الخادوم باستخدام حساب المستخدم غير الجذر. ثم أضف المستخدم إلى مجموعة LXD بحيث يمكنك استخدامه لأداء جميع مهام إدارة الحاويات: sudo usermod --append --groups lxd Sammy قم بتسجيل الخروج من الخادوم وتسجيل الدخول مرة أخرى لكي يتم تحديث جلسة SSH الجديدة الخاصة بك مع عضوية المجموعة الجديدة. بعد تسجيل الدخول يمكنك البدء في تهيئة LXD. الآن قم بإعداد قاعدة التخزين. قاعدة التخزين الموصى بها ل LXD هو نظام ملفات ZFS، المخزنة إما في ملف مخصص مسبقًا أو باستخدام كتلة التخزين . لاستفادة من دعم ZFS في LXD حدّث قائمة الحزم الخاصة بك ثم ثبت الحزمة zfsutils-linux : sudo apt-get update sudo apt-get install zfsutils-linux يمكنك الآن إعداد LXD. ابدأ بعملية تهيئة LXD مع الأمر LXD init : sudo lxd init ستتم مطالبتك بتعيين تفاصيل قاعدة التخزين. بعد الانتهاء من هذا الإعداد يتوجب عليك إعداد الشبكة من أجل الحاويات. أولاً سوف يُقترح عليك أن تختار بشأن قاعدة التخزين، وستُخَير بين أمرين: dir أو zfs . الخيار dir يخبر LXD بتخزين الحاويات في مجلدات تابعة لنظام ملفات الخادوم. وأما الخيار zfs فيستخدم نظام الملفات zfs ونظام إدارة القرص الصلب LVM. اختر zfs. باستخدام zfs نحصل على كلٍّ من كفاءة التخزين وتحسين الاستجابة. على سبيل المثال إذا أنشأنا عشرة حاويات من نفس صورة الحاوية الأولية، فإنها جميعا تستخدم من القرص مساحةَ حاوية واحدة فقط. وبعد ذلك سيتم فقط تخزين التغييرات على صورة الحاوية الأولى في قاعدة التخزين. Name of the storage backend to use (dir or zfs) [default=zfs]: zfs بعد اختيار zfs سيُطلَب منك إنشاء تجمع (pool) zfs جديد واسم لهذا التجمع. اختر نعم لإنشاء التجمع، وسمه ب lxd : Create a new ZFS pool (yes/no) [default=yes]? yes Name of the new ZFS pool [default=lxd]: lxd ثم ستُسأل إذا كنت ترغب في استخدام عتاد التخزين الموجود: Would you like to use an existing block device (yes/no) [default=no] إذا أجبت بنعم فعليك أن تخبر LXD أين يجد هذا العتاد. إذا أجبت بلا فسوف يقوم LXD باستخدام ملف مخصص مسبقًا. مع هذا الخيار سوف تستخدم المساحة الفارغة على الخادوم نفسه. هناك حالتان يتبعان ذلك اعتمادًا على ما إذا كنت تريد استخدام ملف مخصص مسبقًا أو عتاد التخزين. اتبع الخطوة المناسبة لحالتك. بعد تحديد آلية التخزين ستعمل على تهيئة خيارات الشبكة من أجل حاوياتك. الخيار 1 : استخدام التخصيص المسبق يمكنك استخدام ملف مخصص مسبقًا إذا لم تتمكن من الوصول إلى عتاد التخزين من أجل تخزين الحاويات. اتبع هذه الخطوات لإعداد LXD لكي يستخدم ملف مخصص مسبقًا لتخزين الحاويات. أولًا، عندما يطلب منك استخدام عتاد التخزين الموجود أجب بلا : Would you like to use an existing block device (yes/no) [default=no]? no بعد ذلك، سيطلب منك تحديد حجم loop device ، الذي يستدعيه الملف المخصص مسبقًا من LXD. استخدام الحجم الافتراضي المقترح للملف المخصص مسبقًا : Size in GB of the new loop device (1GB minimum) [default=15]: 15 وكقاعدة عامة 15 جيغا هو أصغر حجم يجب عليك إنشاؤه. فأنت تريد تخصيص مساحة كافية لكي يكون لديك 10 غيغابايت على الأقل من المساحة المتبقية بعد إنشاء الحاويات الخاصة بك. بعد تهيئة الجهاز سيطلب منك إعداد الشبكة. انتقل إلى الخطوة 2 لمتابعة الإعداد. الخيار 2 : استخدام عتاد التخزين إذا كنت تريد استخدام عتاد التخزين قاعدةً للتخزين فستحتاج إلى العثور على العتاد الذي يتوافق مع حجم كتلة التخزين التي قمت بإنشائها في تهيئة LXD. انتقل إلى تبويب المجلدات في لوحة التحكم الخاصة ب DigitalOcean، ثم حدد موقع وحدة التخزين الخاصة بك، انقر فوق المزيد من القائمة المنبثقة، ثم انقر فوق تعليمات الإعداد. حدد موقع العتاد بتطبيق أمر تهيئة وحدة التخزين. بعبارة أدق ابحث عن المسار المحدد بتنفيذ الأمر sudo mkfs.ext4 -F . لا تقم بتشغيل أيٍّ من الأوامر الظاهرة في تلك الصفحة، نحن لا نريد سوى العثور على اسم الجهاز الصحيح لإعطاءه لـ LXD. يوضح الشكل التالي مثالا عن اسم الجهاز الخاص بوحدة التخزين. تحتاج فقط إلى الجزء المسطر عليه بالأحمر: يمكنك أيضا تحديد اسم الجهاز بالأمر التالي: ls -l /dev/disk/by-id/ total 0 lrwxrwxrwx 1 root root 9 Sep 16 20:30 scsi-0DO_Volume_volume-fra1-01 -> ../../sda في هذه الحالة اسم الجهاز لوحدة التخزين هو /dev/disk/by-id/scsi-0D0_Volume_volume-fra1-01 وقد يختلف الأمر لديك. بعد تحديد اسم عتاد وحدة التخزين تابع مع تثبيت LXD . عندما تُسأل هل تود أن تستخدم عتاد التخزين الموجود، اختر نعم وقدّم المسار الذي وجدته سابقا: Would you like to use an existing block device (yes/no) [default=no]? yes Path to the existing block device: /dev/disk/by-id/scsi-0DO_Volume_volume-fra1-01 بعد تحديد القرص الصلب سيطلب منك إعداد خيارات الشبكة. الخطوة 2 : إعدادات الشبكة بعد تهيئة وحدة التخزين ستتم مطالبتك بتهيئة الشبكة وإعدادها. أولاً سيسألك LXD عما إذا كنت تريد جعله متاحًا عبر الشبكة. اختيار “نعم” سوف يمكّنك من إدارة LXD من جهاز الكمبيوتر المحلي الخاص بك، دون الحاجة إلى جلسة SSH للوصول إلى هذا الخادوم. اقبل القيمة الافتراضية “لا” : Output of the "lxd init" command — LXD over the network Would you like LXD to be available over the network (yes/no) [default=no]? no ثم سيطلب منك إنشاء جسر الشبكة من أجل حاويات LXD. وهذا يتيح لك الميزات التالية: كل حاوية تحصل تلقائيًا على عنوان IP خاص. يمكن للحاويات التواصل مع بعضها البعض عبر الشبكة الخاصة. يمكن لكل حاوية انشاء اتصال بالإنترنت. تبقى الحاويات التي تقوم بإنشائها غير قابلة للوصول إليها من الإنترنت. لا يمكنك إجراء اتصال من الإنترنت والوصول إلى حاوية إلا إذا قمت بتمكينه صراحة. سوف تتعلم كيفية السماح بالوصول إلى حاوية معينة في الخطوة التالية. عندما يطلب منك تكوين جسر LXD، اختر نعم : Output of the "lxd init" command — Networking for the containers Do you want to configure the LXD bridge (yes/no) [default=yes]? Yes سيتم عرض الرسالة التالية: أكّد أنك تريد إعداد جسر الشبكة. سيطلب منك تسمية الجسر. اقبل القيمة الافتراضية. سيطلب منك إجراء تهيئة الشبكة لكلٍّ من IPv4 و IPv6. في هذا الدرس سنعمل فقط مع IPv4. عندما يطلب منك إعداد شبكة فرعية IPv4 اختر نعم . سوف يتم إعلامك بأنه تم إنشاء شبكة فرعية عشوائية بالنسبة لك. اختر موافق للمتابعة. عند المطالبة بعنوان IPv4 صحيح قم بقبول القيمة الافتراضية. عندما يطلب منك قناع CIDR صحيح، اقبل القيمة الافتراضية. عند المطالبة بعنوان DHCP الأول اقبل القيمة الافتراضية. افعل الشيء نفسه مع عنوان DHCP الأخير وذلك حسب الحد الأقصى لعدد عملاء DHCP. اختر نعم عندما يطلب إلى NAT حركة مرور IPv4. عندما يطلب منك إعداد شبكة فرعية لـ IPv6 اختر “لا” . ستشاهد المخرجات التالية بعد اكتمال إعداد الشبكات: Warning: Stopping lxd.service, but it can still be activated by: lxd.socket LXD has been successfully configured. أنت مستعد الآن لإعداد حاوياتك. الخطوة 3 : إنشاء حاوية Nginx لقد نجحت في تهيئة LXD وأصبحت الآن جاهزا لإنشاء الحاوية الأولى وإدارتها. يمكنك إدارة الحاويات مع الأمر lxc. استخدم lxc list لعرض الحاويات المثبتة المتاحة: lxc list سترى الإخراج التالي: Generating a client certificate. This may take a minute... If this is your first time using LXD, you should also run: sudo lxd init To start your first container, try: lxc launch ubuntu:16.04 +------+-------+------+------+------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +------+-------+------+------+------+-----------+ وبما أن هذه هي المرة الأولى التي يتواصل فيها الأمر lxc مع مراقب الأجهزة الافتراضية لـ LXD تتيح لك مخرجاته معرفة أنه قام تلقائيًا بإنشاء شهادة للعميل من أجل الاتصال الآمن مع LXD، وبعض المعلومات حول كيفية تشغيل حاوية، وقائمة فارغة من الحاويات، وهو أمر متوقع لأننا لم ننشئ أي واحدة حتى الآن. دعنا ننشئ حاوية تقوم بتشغيل Nginx. للقيام بذلك سوف نستخدم الأمر lxc launch لإنشاء وبدء حاوية أوبونتو 16.04 اسمها webserver. لإنشاء الحاوية webserver ننفذ الأمر: lxc launch ubuntu:x webserver x في ubuntu:x هو اختصار للحرف الأول من Xenial ، الاسم الرمزي لأوبونتو 16.04. ubuntu: هو معرف للمستودع الذي تم تكوينه مسبقا لصور LXD . يمكنك أيضا استخدام ubuntu:16.04 لاسم الصورة. ملاحظة : يمكنك العثور على القائمة الكاملة لجميع صور ubuntu المتاحة عن طريق تشغيل الأمر: lxc image list Ubuntu: وفي التوزيعات الأخرى عن طريق تشغيل الأمر: lxc image list images: نظرًا لأن هذه هي المرة الأولى التي تقوم فيها بإنشاء حاوية ينزّل هذا الأمرُ صورةَ الحاوية من الإنترنت ويخزنها محليًا بحيث إذا أنشأت حاوية جديدة فسيتم إنشاؤها بسرعة أكبر. سترى هذه المخرجات عند إنشاء الحاوية الجديدة: Generating a client certificate. This may take a minute... If this is your first time using LXD, you should also run: sudo lxd init To start your first container, try: lxc launch ubuntu:16.04 Creating webserver Retrieving image: 100% Starting webserver الآن ..بعد تشغيل الحاوية استخدم الأمر lxc list لعرض معلومات حولها: lxc list تظهر المخرجات جدولًا يحمل اسم كل حاوية وحالتها الحالية وعنوان IP خاص بها ونوعها وما إذا كانت هناك لقطات مأخوذة. Output +-----------+---------+-----------------------+------+------------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +-----------+---------+-----------------------+------+------------+-----------+ | webserver | RUNNING | 10.10.10.100 (eth0) | | PERSISTENT | 0 | +-----------+---------+-----------------------+------+------------+-----------+ ملاحظة: إذا قمت بتمكين IPv6 في LXD فقد يكون مخرج أمر lxc list كبيرًا جدًا عن أن تسعه الشاشة. يمكنك أن تستخدم بدلا عن ذلك الأمر lxc list –columns ns4tS الذي يظهر فقط الاسم والحالة و IPv4 والنوع وما إذا كانت هناك لقطات متاحة. لاحظ عنوان IPv4 للحاوية. ستحتاج إلى تهيئة الجدار الناري للسماح بالزيارات الواردة من العالم الخارجي. سنتابع في الدرس القادم كيفية تكوين وتوجيه وإزالة حاوية Nginx. ترجمة -وبتصرّف- للمقال How to Set Up and Use LXD on Ubuntu 16.04 لصاحبه Simos Xenitellis
  9. تعلمنا في الدرس السابق كيفية إعداد LXD وإعداد الشبكة بالإضافة إلى إنشاء حاوية Nginx والآن لنقم بإعداد Nginx داخل الحاوية: الخطوة 4 : تكوين حاوية Nginx لِنتصلْ بالحاوية webserver ولنقم بإعداد خادوم الويب. اتصل بالحاوية بالأمر lxc exec الذي يأخذ اسم الحاوية وأوامر التنفيذ كمدخلات: lxc exec webserver -- sudo --login --user ubuntu يشير المحرف “–” الأول إلى أن مدخلات الأمر lxc يجب أن تتوقف عندها وسيتم تمرير بقية السطر كأمر يتم تنفيذه داخل الحاوية. الأمر هو sudo --login –user Ubuntu وهو الذي سوف يوفر صدفة تسجيل الدخول للحساب ubuntu السابق الإعداد داخل الحاوية. ملاحظة: إذا كنت بحاجة إلى الاتصال بالحاوية باعتبارك جذرًا استخدم الأمر lxc exec webserver -- /bin/bash بدلًا من ذلك. بعدما تدخل إلى الحاوية ستبدو الصدفة الآن كما يلي. ubuntu@webserver:~$ المستخدم ubuntu في الحاوية لديه صلاحيات sudo مُعَدَّة مسبقًا ويمكنه تنفيذ أوامر بصلاحيات الجذر دون المطالبة بإدخال كلمة السر. تقتصر هذه الصدفة على حدود الحاوية. أيُّ شيء تقوم بتشغيله في هذه الصدفة سيبقى في الحاوية ولا يمكن الذهاب به إلى الخادوم المضيف. لنقم بإعداد Nginx في هذه الحاوية. حدّث قائمة حزم ubuntu داخل الحاوية وثبت Nginx: sudo apt-get update sudo apt-get install nginx ثم قم بتحرير صفحة الويب الافتراضية لهذا الموقع وأضف بعض الجمل التي تجعل من الواضح أن هذا الموقع يتم استضافته في الحاوية webserver . افتح الملف : sudo nano /var/www/html/index.nginx-debian.html أدخل التغيير التالي على الملف: <!DOCTYPE html> <html> <head> <title>Welcome to nginx on LXD container webserver!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx on LXD container webserver!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> لقد قمنا بتحرير الملف في مكانين، وعلى وجه التحديد أضفنا العبارة ” on LXD container webserver”. احفظ الملف وأغلق المحرر. الآن سجل الخروج من الحاوية وعُد إلى الخادوم المضيف: Logout استخدم الأمر curl لاختبار أن خادوم الويب في الحاوية يعمل. ستحتاج إلى عناوين IP لحاويات الويب التي يمكنك أن تجدها بتنفيذ الأمر lxd list. curl http://10.10.10.100/ يجب أن تكون المخرجات: <!DOCTYPE html> <html> <head> <title>Welcome to nginx on LXD container webserver!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx on LXD container webserver!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> خادوم الويب يعمل، ولكن لا يمكننا الوصول إليه إلا من خلال الـ IP الخاص. لِنوجِّهْ الطلبات الخارجية إلى هذه الحاوية حتى يتمكن العالم من الدخول إلى موقعنا على الويب. الخطوة 5 : إعادة توجيه الاتصالات الواردة إلى حاوية Nginx الجزء الأخير من اللغز هو ربط حاوية خادوم الويب بالإنترنت. Nginx مثبت في حاوية، وبشكل افتراضي لا يمكن الوصول إليه من الإنترنت. نحتاج إلى إعداد الخادوم المضيف لإعادة توجيه أيّ اتصالات قد يتلقاها من الإنترنت على المنفذ 80 إلى الحاوية webserver . للقيام بذلك سننشئ قاعدة iptables لإعادة توجيه الاتصالات. يتطلب الأمر iptables اثنين من عناوين IP: عنوان IP العام للخادوم (your_server_ip) وعنوان IP الخاص بحاوية nginx (your_webserver_container_ip) ، والذي يمكنك الحصول عليه باستخدام الأمر lxc list . نفذ هذا الأمر لإنشاء القاعدة: PORT=80 PUBLIC_IP=your_server_ip CONTAINER_IP=your_container_ip \ sudo -E bash -c 'iptables -t nat -I PREROUTING -i eth0 -p TCP -d $PUBLIC_IP --dport $PORT -j DNAT --to-destination $CONTAINER_IP:$PORT -m comment --comment "forward to the Nginx container"' وإليك شرح هذا الأمر: -t nat يعني أننا نستخدم جدول nat لترجمة العنوان. -I PREROUTING يعني أننا نقوم بإضافة القاعدة إلى سلسلة PREROUTING. -i eth0 يعني الواجهة eth0، وهي الواجهة العامة الافتراضية في Droplets. -p TCP يعني أننا نستخدم البروتوكول TCP. -d $PUBLIC_IP يحدد عنوان IP الوجهة . --dport $PORT : يحدد منفذ الوجهة (مثل 80 ). -j DNAT تعني أننا نريد إجراء قفزة إلى الوجهة NAT (DNAT). --to-destination $CONTAINER_IP:$PORT تعني أننا نريد الذهاب إلى عنوان IP الخاص بالحاوية المذكورة ومنفذ الوجهة. ملاحظة: يمكنك إعادة استخدام هذا الأمر لإعداد قواعد إعادة التوجيه ببساطة عن طريق تعيين متغيرات PORT و PUBLIC_IP و CONTAINER_IP في بداية السطر. فقط قم بتغيير القيم الملونة بالأحمر. يمكنك الاطلاع على قواعد IPTables عن طريق تشغيل هذا الأمر: sudo iptables -t nat -L PREROUTING سترى مخرجًا مماثلًا لهذا: Chain PREROUTING (policy ACCEPT) target prot opt source destination DNAT tcp -- anywhere your_server_ip tcp dpt:http /* forward to this container */ to:your_container_ip:80 ... اختبر الآن إمكانية الوصول إلى خادوم الويب، وذلك بالدخول إليه من جهاز الكمبيوتر المحلي باستخدام الأمر curl مثل هذا: curl --verbose 'http://your_server_ip' سترى رأس صفحة الويب التي أنشأتها في الحاوية متبوعًا بمحتوياتها: * Trying your_server_ip... * Connected to your_server_ip (your_server_ip) port 80 (#0) > GET / HTTP/1.1 > User-Agent: curl/7.47.0 > Accept: */* > < HTTP/1.1 200 OK < Server: nginx/1.10.0 (Ubuntu) ... <!DOCTYPE html> <html> <head> <title>Welcome to nginx on LXD container webserver!</title> <style> body { ... هذا يؤكد أن الطلبات ستذهب إلى الحاوية. وأخيرًا .. لحفظ قاعدة جدار الحماية ثبت الحزمة iptables-persistent الحماية لكي يتم إعادة تطبيقها بعد إعادة التشغيل sudo apt-get install iptables-persistent عند تثبيت الحزمة ستتم مطالبتك بحفظ قواعد جدار الحماية الحالية. اقبل واحفظ جميع القواعد الحالية. عند إعادة تشغيل جهازك ستكون قاعدة جدار الحماية موجودة. بالإضافة إلى ذلك سيتم إعادة تشغيل خدمة Nginx في الحاوية الخاصة بك تلقائيا. الآن بعد أن قمنا بإعداد كل شيء لننظر في كيفية إزالته. الخطوة 6 : إيقاف وإزالة الحاوية ربما تقرر إزالة الحاوية واستبدالها. لنعرف كيف نقوم بذلك: لإيقاف الحاوية استخدم lxc stop : lxc stop webserver استخدم الأمر lxc list للتحقق من الحالة، ستكون المخرجات: +-----------+---------+------+------+------------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +-----------+---------+------+------+------------+-----------+ | webserver | STOPPED | | | PERSISTENT | 0 | +-----------+---------+------+------+------------+-----------+ لإزالة الحاوية استخدم lxc delete : lxc delete webserver نفذ الأمر lxc list مرة أخرى ليظهر لك أنه لا يوجد حاوية قيد التشغيل: +------+-------+------+------+------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +------+-------+------+------+------+-----------+ استخدم الأمر lxc help للاطلاع على خيارات إضافية. لإزالة قاعدة الجدار الناري التي توجه حركة المرور إلى الحاوية حدد أولا القاعدة في قائمة القواعد بهذا الأمر والذي يربط رقم سطر مع كل قاعدة: sudo iptables -t nat -L PREROUTING --line-numbers سترى القاعدة، مسبوقة برقم سطر، كما يلي: Chain PREROUTING (policy ACCEPT) num target prot opt source destination 1 DNAT tcp -- anywhere your_server_ip tcp dpt:http /* forward to the Nginx container */ to:your_container_ip استخدم رقم السطر هذا لإزالة القاعدة: sudo iptables -t nat -D PREROUTING 1 تأكد من إلغاء القاعدة من خلال مشاهدة القواعد مرة أخرى بالأمر: `sudo iptables -t nat -L PREROUTING --line-numbers` سترى أنه تمت إزالة القاعدة: Chain PREROUTING (policy ACCEPT) num target prot opt source destination احفظ التغييرات الآن حتى لا يتم العمل بالقاعدة بعد إعادة تشغيل الخادوم: sudo netfilter-persistent save يمكنك الآن إنشاء حاوية أخرى مع الإعدادات الخاصة بك وإضافة قاعدة جدار حماية جديدة لإعادة توجيه حركة المرور إليها. خلاصة لقد قمت بإعداد موقع ويب باستخدام Nginx في حاوية LXD. يمكنك من هنا إعداد المزيد من مواقع الويب حيث يقتصر كل واحد منها على حاويته الخاصة به، ويمكنك ايضا استخدام بروكسي عكسي لتوجيه حركة المرور إلى الحاوية المناسبة. سيعلمك كيف تفعل ذلك هذا المقال: كيف تستضيف مجموعة مواقع بشكل آمن باستخدام Nginx و Php-fpm على أوبنتو 14.04 يتيح لك LXD أيضا التقاط لقطات من الحالة الكاملة للحاويات، مما يجعل من السهل إنشاء نسخ احتياطية من أجل الرجوع إليها لاحقا. وإذا قمت بتثبيت LXD على خادومين مختلفين فمن الممكن توصيل الحاويات بعضها ببعض وترحيلها بين الخوادم عبر الإنترنت. لمعرفة المزيد عن LXD اقرأ هذه التدوينات عن LXD التي كتبها مطورو LXD يمكنك أيضا تجربة LXD على الانترنت واتباع البرنامج التعليمي على شبكة الإنترنت للحصول على مزيد من الممارسة. ترجمة -وبتصرّف- للمقال How to Set Up and Use LXD on Ubuntu 16.04 لصاحبه Simos Xenitellis
  10. يُعتبر خادوما الويب Apache و Nginx الأكثر شهرةً من بين الخواديم المفتوحة المصدر في عالم الشبكة العنكبوتيّة، على اعتبار أنّهما مسؤولان عن خدمة وتأمين نصف تدفّق البيانات على الإنترنت، وعلى مَقدرة على تولّي مُختلف حجوم الأحمال، والعمل مع برمجيات أخرى في سبيل توفير حزمة من خدمات الويب الشاملة والكاملة لتلبية مُختلف الاحتياجات. بينما يَتشارك الخادومان Apache و Ngnix العديد من الميّزات والخاصيّات، فلا يُمكن اعتبارهما مُتشابهان، أو التفكير بأن أحدهما هو بديل عن الآخر، فكل منهما يتفّوق عن الآخر بشيءٍ ما، وعلى مُدير النظام فهم وإدراك لماذا يجب اختيار أحدهما دون الآخر، فهذا الدليل يَهدف إلى مُناقشة كيف أنّ كُل خادوم يَتميّز ويَبرز في شيء ويُخفق في آخر. مقدّمة عامّةسيتمّ أخذ نظرة سريعة عن تاريخ وبداية المشروعين وخواصّهم العامّة قبل التعمّق في الاختلاف بينهما. تاريخ خادوم الويب Apacheأَنْشَأَ “روبت ماك كول” (Robert McCool) “خادم الـ HTTP أباتشي” (Apache HTTP Server) في عام 1995، وتمّ مُتابعة تطويره تحت مظلّة “مُنشأةُ برمجيات أباتشي” (Apache Software Foundation) مُنذ العام 1999، وكان هذا الخادم هو المشروع الأساسي للمُنشأة والأكثر شهرةً عن باقي البرمجيات، فأصبح ببساطة يُشار إليه بالاسم “Apache”. يُعتبر خادم الويب أباتشي الخادم الأكثر استخدامًا على الإنترنت منذ العام 1996، وبسبب هذه الشهرة، استفاد أباتشي من توثيق ودعم باقي مشاريع البرمجيات الأُخرى. يَختار مُدراء الأنظمة الخادم أباتشي غالبًا بسبب مرونته، وقُدرته على التحمّل، وتوفّر دعمه العالي والمُنتشر، كما يُحسب له قابليته على التوسّع عبر نظام الوحدات (modules) الديناميكيّة، واستطاعته على مُعالجة عدد كبير من اللغات المُفسّرة (interpreted languages) من دون الحاجة إلى برمجيّة مٌستقلّة وسيطة. تاريخ خادوم الويب Nginxبَدأ “ايجور سيسيوﭫ” في عام 2002 العمل Nginx للإجابة وحلّ المُشكلة المعروفة بالاسم C10K، والّتي كانت تُشكّل تحدّيًا كبيرًا لخوادم الويب لتُصبح قادرة على تولّي عشرة آلاف اتصال مُتزامن (concurrent) وذلك في تلبية حاجة الويب الحديث، وأُنتجت الإصدارة الأوليّة والمُتاحة للعُموم في عام 2004 مُقدمةً حلًا لهذه المُشكلة، وذلك بالاعتماد على معماريّة مدفوعة بالحالة (event-driven) ولا مُتزامنة. انتشر Nginx كالنار في الهشيم مُنذ إصداره، بمُقتضى خفته واستخدامه الخفيف للمَوارد، وقدرته على التوسّع وتحمّل الضغط العالي وبأقل عتاد مُمكن، وتفوّق Nginx بتأمين المُحتوى الثّابت (static content) بسرعة، وبتصميمه لتمرير الطلبات الديناميكيّة (المُتغيّرة) إلى برمجيات أُخرى قادرة على مُعالجة هذا النوع من المُحتوى. يختار مُدراء الأنظمة الخادم Nginx غالبًا بسبب استهلاكه الأمثل للمَوارد، واستجابته العالية مع الضغط المتزايد. معماريّة مُعالجة الاتصال (Connection Handling Architecture)يَكمن الاختلاف الواضح بين أباتشي و Nginx في طريقة كلٍ منهما في مُعالجة الاتصالات وتدفّق البيانات (traffic)، وربّما هذا السبب وراء الاختلاف في طريقة كل من الخادمين في الاستجابة إلى حالة تدفّق البيانات المُختلفة. وحدات أباتشي (Apache Modules)يقدّم أباتشي تشكيلةً من وحدات المُعالجة المُتعدّدة (multi-processing)، والّتي يُطلق عليها بـ MPMs، والغرض منها تحديد آليّة مُعالجة طلبات العميل، ويَسمح ذلك مُدراء الأنظمة عامّةً بالتبديل بين معماريّة مُعالجة الاتصال بسهولة، والوحدات هي: mpm_prefork: تَستنسخ وتُوالد هذه الوحدة الخاصّة بالمُعالجة عمليّات (processes) باستخدام سلسلة وحيدة (single thread)، على أنّ تكون كل عمليّة لمُعالجة طلب، ويستطيع كل ابن مُعالجة اتصال واحد في نفس الوقت، وطالما أنّ عدد الطلبات أقل من عدد العمليّات، فستكون هذه الوحدة سريعةً جدًا، ولكن يَنخفض الأداء بسرعة بعد تخطّي الطلبات عدد العمليّات، ولذلك لا يُعتبر هذا النمط بالخيار الجيّد للعديد من السيناريوهات، فكل عمليّة لها تأثير بليغ على استهلاك الذاكرة (RAM)، ولهذا السبب تُصعّب هذه الوحدة من عمليّة التوسّع بطريقة مُلائمة، ومع هذا تبقى هذه الوحدة خيارًا جيّدًا إن تمّ استخدامها مقترنةً مع مُقوّمات (components) أُخرى لم تُبنى بالأساس آخذةً بعين الاعتبار السلاسل (threads)، فلغة PHP ليست سلسلة آمنة (thread-safe)، ولذلك يُنصح بهذه الوحدة باعتبارها الطريقة الوحيدة الآمنة للعمل مع mod_php والّتي هي وحدة من وحدات أباتشي لمُعالجة هذا النوع من الملفّات. mpm_worker: تستنسخ وتُوالد هذه الوحدة عمليّات (processes) كل منها ذات قُدرة على إدارة سلاسل مُتعدّدة (multiple threads)، تستطيع كل واحدة من هذه السلاسل مُعالجة اتصال وحيد، تُعتبر هذه السلاسل أكثر كفاءة من العمليّات، بسبب أنّ هذه الوحدة تتوسّع (scales)، وتتحمّل المزيد من الضغط أفضل من الوحدة prefork MPM، وباعتبار أنّه يوجد سلاسل أكثر من العمليّات، فهذا يعني أيضًا أنّ الاتصالات الجديدة تستطيع مُباشرةً استهلاك واستخدام سلسلةبدلًا من اضطرارها إلى الانتظار لتوفّر عمليّة مُتاحة. mpm_event: تَعمل هذه الوحدة بشكل مُشابه إلى الوحدة worker، ولكنها مُحسّنة لتتولّى اتصالات keep-alive، فعند استخدام الوحدة worker فإن الاتصال سيَحتفظ بالسلسلة (thread) بصرف النظر فيما إذا كان الطلب نشطًا فيما صُنع من أجله ما دام الاتصال محفوظًا نشطًا، فالوحدة mpm_event تتولّى الاتصالات keep-alive بالاحتفاظ جانبًا بسلاسل مكرّسة لمُعالجتها، وبتمرير الطلبات النشطة إلى سلاسل أُخرى، وهذا من شأنه أنّ يُبعد الوحدة من الغوص بطلبات keep-alive، الأمر الّذي يُجيز بتنفيذ الطلبات (execution) بشكل أسرع، وهذا الأسلوب أصبح يعمل بشكل مُستقر مع الإصدار Apache 2.4. أصبح الأمر أكثر وضوحًا، حيث تقدّم خوادم أباتشي بنية معماريّة مرنة للاختيار بين مُختلف الاتصالات وخوارزمية مُعيّنة في مُعالجة الطلبات، وبُنيت هذه الخيارات في الدرجة الأولى من تطوّر الخادم والحاجة المُتزايدة للاتصالات المُتزامنة لتواكب طبيعة الإنترنت بعد تغيرها وتطوّرها. آليّة مُعالجة الاتصال في خادوم Nginxقَدِم Nginx إلى عالم خوادم الويب بعد قدوم أباتشي، مَبنيًّا ومُعدًّا لمشاكل الاتصالات المُتزامنة (concurrency) الّتي تواجه المواقع عند التوسّع، مُحمّلًا بهذه المعرفة، صُمّمَ Nginx من جذوره ليستخدم خوارزميّة في مُعالجة اتصالات مدفوعة بالحالة (event-driven)، غير مُستوقفة (non-blocking)، ولا مُتزامِنة. يستنسخ ويُوالد Nginx من العمليّات العاملة (worker processes)، ويستطيع كلٍ مِنها مُعالجة آلاف الاتصالات، وتُنجذ العمليّات العاملة ذلك عن طريق تطبيق/تنفيذ آلية حلقيّة سريعة، والّتي تفحص بشكل مُستمر حالات العمليّات (processes events)، وإن فصل المُهمّة الفعليّة عن الاتصالات يسمح لكلعامل بالاهتمام بنفسه باتصال فقط عند بدء حالة جديدة. يتموضع كل اتصال مُعالج من قبل العامل ضمن حلقة الحالة (event loop) في مكان تواجد بقية الاتصالات، وتُعالج الأحداث بشكل لا مُتزامن ضمن الحلقة، ليتمّ إنجاز المُهمّة بطريقة غير مُستوقفة (non-blocking)، وعندما يُغلق الاتصال سيتمّ نزعه من الحلقة. يَسمح هذا الأسلوب من مُعالجة الاتصال Nginx بتحمّل الضغط العالي بشكل لا يُصدّق وبأقل المَوارد المُتاحة، وباعتبار أنّ الخادم ذو سلسلة وحيدة (single-threaded) ولا تتوالد العمليّات لتُعالج كل اتصال جديد، فإن استهلاك المُعالج (CPU)، والذّاكرة يبقى ثابتًا نسبيّا، حتّى في أوقات الذروة. كيف يُعالج أباتشي و Nginx المُحتوى الثّابت والمحتوى الديناميكي (المُتغيّر)إن أبرز ما يتمّ النظر إليه عند المُقارنة بين الخادمين هي طريقة كلٍ منهما في التعامل مع طلبات المُحتوى الثّابت (static)، والمُحتوى المُتغيّر (dynamic). كيف يتعامل أباتشي مع المُحتوى الثّابت والمُتغيّرتستطيع خوادم أباتشي التعامل مع المُحتوى الثّابت باستخدام الطريقة التقليديّة المُعتمدة على الملفّات، ويعود أداء هذه الإجراءات (operations) في الدرجة الأولى على دور ووظيفة أساليب الوحدات (MPM) المشروحة سابقًا. يستطيع أباتشي أيضًا مُعالجة المُحتوى الديناميكي (المُتغيّر) بدمج مُعالج اللغة المُراد مُعالجتها داخل كل من نماذجه العاملة (worker instances)، وهذا يَسمح له بتنفيذ المُحتوى الديناميكي داخل خادم الويب نفسه بدون الحاجة إلى الاعتماد على مُقوّمات خارجيّة، ومن المُمكن تفعيل هذه المُعالجات الديناميكيّة (المُتغيّرة) من خلال استخدام وحدات قابلة للتحميل بشكل ديناميكي. إن قدرة أباتشي على مُعالجة المُحتوى الديناميكي بشكل داخلي تعني أنّ الإعداد يُصبح أسهل لمُعالجة هذا النوع من المُحتوى، فليس من الضروري تنسيق عمليّة الربط مع برمجيات إضافيّة، وتستطيع الوحدات وبسهولة أنّ تقوم بالتبديل عندما تتغيّر مُتطلّبات المُحتوى. كيف يتعامل Nginx مع المُحتوى الثّابت والمُتغيّرلا يَملك Nginx بطبيعته أي قدرة على مُعالجة المُحتوى الديناميكي، ولمُعالجة شيفرة PHP وطلبات المُحتوى الديناميكي، فإن على Nginx تمرير الطلبات إلى مُعالج خارجي من أجل التنفيذ (execution) والانتظار ريثما يتم الانتهاء من مُعالجة هذا المُحتوى ليتمّ إعادة إعادته، ومن ثم عرض النتائج على العميل. يَنبغي على مُدراء الأنظمة الانتباه إلى أنّ الأسلوب الّذي ينتهجه Nginx يستوجب إعدادًا بينه وبين المُعالج وباستخدام واحدًا من البرتوكولات الّتي يفهمها Nginx أمثال: HTTP, FastCGI, SCGI,uWSGI, memcache، وهذا من شأنه أنّ يُعقّد الأمور بعض الشيء، خصوصًا عند مُحاولة توقّع عدد الاتصالات اللازم السماح بها، حيثُ أنّه سيتمّ استخدام اتصالًا إضافيًا لكل مُعالج يتمّ استدعاؤه. من ناحية أخرى، إن هذا الأسلوب يقدّم بعضًا من الأفضليّة، عندما نعلم أنّ مُفسّر المُحتوى الديناميكي غير مُدمج في عمليّة العامل، وتكلفة هذه الطريقة ستُدفع للمُحتوى الديناميكي فقط، وعلى أنّ يُقدّم المُحتوى الثّابت بطريقة مُباشرة، ولا يتمّ الاتصال بالمُفسر إلا عند الحاجة، والجدير بالذكر أنّ أباتشي يستطيع العمل بهذا الأسلوب، ولكن بعمله ذلك سيتخلّى عندها عن بعض ميزاته. الاختلاف بين الإعداد الموزّع (Distributed) والإعداد المركزي (Centralized)يَعتبر مُدراء الأنظمة الاختلاف الأكبر والبارز بين هذين الخادمين هو فيما إذا كان الإعداد والتخصيص على مُستوى المسار مسموحًا أو لا ضمن مسارات (directories)المُحتوى. فلسفة Apache في الإعداديُضمّن أباتشي خيارًا للسماح بالإعداد لكل مسار عن طريق تَفحُّص (inspecting) وتفسير (interpreting) التعليمات أو التوجيهات الموجودة في الملفات المخفيّة داخل مسارات المُحتوى نفسها، وهذه الملفّات معروفة بملفات .htaccess. باعتبار أنّ هذه الملفّات تَقطن داخل مسارات المُحتوى نفسها، فعند مُعالجة طلبٍ ما، فإن أباتشي يَفحص كل جزء من مسار الملفّ المطلوب باحثًا عن ملفّ .htaccess ليُطبّق التوجيهات الّتي بداخله، وهذا من شأنه أنّ يسمح للإعداد اللامركزي لخادم الويب، والذي غالبًا ما يُستخدم لإنجاز: إعادة كتابة عنوان الموقع (URL rewrites)تقييد الوصول (access restrictions)التفويض والمُصادقة (authorization and authentication)سياسات التخبئة (caching policies)بالطبع يُمكن للأمثلة السابقة إعدادها عن طريق ملفّ إعدادات أباتشي الرئيسي، ولكن استخدام ملفات.htaccess يَملك بعض الميزات: أوّلًا، باعتبار أنّها تُفسّر في كل مرّة توجد بها مع المسار المطلوب، فهي تُنفّذ مُباشرةً بدون إعادة تحميل الخادم.ثانيًا، تجعل من المُمكن السماح للمُستخدِمين غير المصرّح لهم بالتحكم بجانب معيّن من المُحتوى الخاصّة بهم بدون إعطائهم تحكم كامل لملفّ الإعدادات.يُقدّم هذا النمط من الإعداد طريقة سهلة ونموذجيّة، وخاصّة لبعض برمجيات الويب، مثل أنظمة إدارة المُحتوى (CMS)، لغرض إعداد بيئتها بدون مَنح إذن وصول إلى ملفّ إعدادات مركزيّ، وكما هو معروف يُستخدم هذا الأسلوب مع مزودات الاستضافة المُشتركة (shared hosting providers) لصون والحفاظ على الإعدادات الرئيسية مع إمكانيّة منح العُملاء أفضليّة التحكّم بمسارات مُعيّنة. فلسفة Nginx في الإعدادلا يُفسّر Nginx ملفّات .htaccess، ولا يُقدّم أي آليّة للتعامل مع كل مسار من دون استخدام ملفّ إعدادات رئيسي، قد يبدو هذا الأسلوب أقل مرونةً من أسلوب أباتشي، ولكن من ناحية أُخرى فلهذا الأسلوب أفضليته. إن عدم الاعتماد على نظام ملفّات .htaccess الخاصّ بالإعداد على مستوى المسارات يُقدّم سرعةً في الأداءً، فخادم أباتشي عليه القيام بتفحّص المسار الجذر لكل طلب يصله، وعند وجود ملفّ أو أكثر خلال عمليّة البحث، يتم قراءة محتوياته وتفسيرها، ولكن Nginx لا يفعل ذلك، فهو يخدم الطلبات بسرعة أكبر بالاعتماد على مكان وحيد للبحث عنه. أفضليّة أُخرى مُتعلّقة بالحماية، فإن توزيع ملفّات الإعدادات على مستوى المسارات يوزّع مسؤوليّة الحماية على كل المُستخدِمين، الّذين قد يكونوا في معظم الأحوال غير موثوقون لتولّي هذه المُهمّة بالشكل الأمثل، فعندما يقوم مُدير النظام بتولّي مُهمة التحكم بالخادم ككل، يمنع ذلك من حدوث أخطاء، والتي قد تحدث في حال منح صلاحيات وصول لأطراف أُخرى. يجدر الذكر أنّه من المُمكن تعطيل تفسير ملفّات .htaccess’ فيأباتشي`، في حال أنها تُشكل نوعًا من القلق لمُدير النّظام. الاختلاف بين تفسير الملفّات وتفسير URIلا يقتصر الاختلاف بين الخادومين على ما سبق فقط، فيظهر الاختلاف الآخر في كيفيّة تفسير كلٍ منهما للطلبات (requests) وربطها مع المَوارد المُتواجدة على النّظام. كيف يُفسر Apache الطلباتيقدّم أباتشي القدرة على تفسير الطلب إما كمَورد فيزيائي (حقيقي) على نظام الملفّات (filesystem) أو عنوان URI الّذي قد يحتاج أسلوب أكثر تجرّد، ويستخدم أباتشي بشكلٍ عام للأسلوب الأول كتل (blocks) وهي إما <Directory> أو <Files>، بينما يستخدم كتل <Location>للمَوارد الأكثر تجرّدًا. صُمّم أباتشي من الأساس كخادم ويب، لذلك في مُعظم الأحيان فإن السلوك الافتراضيّ هو تفسير الطلبات كمَوارد نظام ملفّات (filesystem)، حيثُ يبدأ بتتبّع جذر المُستند وإلحاقه بجزئية الطلب متبوعًا باسم المُضيف (host) ورقم المنفذ في مُحاولة لإيجاد الملفّ المطلوب، بمعنى آخر وببساطة، تتمثّل هرميّة نظام الملفّات على الويب كشجرة مُستند. يُقدّم أباتشي عددًا من البدائل عندما لا يتوافق الطلب مع نظام الملفّات المقصود، فمثلًا من المُمكن استخدام الموجّه Alias لربط عنوان البديل، مع العلم أنّ استخدام الكتل <Location> هو طريقة للتعامل مع URI نفسها بدلًا من نظام الملفّات، كما يُمكن استخدام التعابير النمطيّة (regular expression)، والّتي من المُمكن استخدامها لتطبيق الإعداد بسهولة أكبر في كامل نظام الملفّات. يُعوّل أباتشي على نظام الملفّات بشكل كبير، يظهر ذلك جليًا في اعتماده على ملفّات .htaccessلإعداد كل مسار، حتّى أنّ التوثيق الرسميّ الخاصّ به يحذر من استخدام كتل مُعتمدة على URI في تقييد الوصول عندما يكون الطلب يَعتمد بشكل أو بآخر على نظام الملفّات. كيف يُفسّر Nginx الطلباتأُنشِأ Nginx ليكون خادمًا للويب وخادمًا وكيلًا/وسيطًا (proxy server)، ونظرًا إلى المعماريّة المطلوبة للعمل بهذه الأدوار، فإنه يعمل بشكل رئيسي مع URIs، والتحويل إلى نظام الملفّات عند الضرورة. يُمكن رؤية ذلك في بعض جوانب بناء وتفسير ملفّات إعدادات Nginx، فلا يوفّر Nginx آليّة لتحديد إعدادًا لمسار نظام الملفّات، بل يَستعيض عنها بتحليل URI نفسه. يُمكن توضيح ذلك بالمثال، كتل الإعداد الأوليّ لـ Nginx هي: server و location، الكتلة serverتُفسّر المُضيف الجاري طلبه، بينما الكتل مسؤولة عن مُطابقة أجزاء من URI التي تأتي بعد المُضيف والمنفذ، في هذه المرحلة يتمّ تفسير الطلب كـ URI، وليس كعنوان على نظام الملفّات. يتوجّب في نهاية المطاف على جميع الطلبات أنّ تُربط مع عنوان على نظام الملفّات وذلك للملفّات الثّابتة، فأولًا، سيَختار Nginx كتل server و location الّتي سوف تتولّى الطلب، ومن ثم ضم جزر المُستند مع الـ URI. إن تحليل ومُعالجة الطلب قبل كل شيء على شكل URIs بدلًا من عناوين نظام الملفّات يَسمح لـ Nginxالعمل بسهولة وعلى حدٍّ سواء كخادم وسيط (بروكسي)، وكخادم بريد، وخادم ويب، فقد تمّ إعداده ليُلائم كيف له أنّ يستجيب لأنماط الطلبات المُختلفة، ولا يفحص Nginx نظام الملفّات حتّى يكون جاهزًا ليَخدم الطلب، وهذا يُفسّر لماذا هو لا يُطبّق نمط ملفّات .htaccess. الوحداتيتوسع كلا الخادومان عن طريق نظام الوحدات، ولكن طريقة عملهما تختلف عن الآخر بشكل كبير. كيف يستخدم أباتشي نظام الوحدات (Modules)؟يَسمح نظام وحدات أباتشي بطريقة آليّة وديناميكيّة بتركيب ونزع الوحدات ليتناسب مع مُتطلّبات مُدير النظام خلال عمليّة تشغيل الخادم، وتتواجد نواة أباتشي دائمًا بكل جاهزية، بينما يُمكن تشغيل أو تعطيل الوحدات، أو حتّى حذفها أو إضافة ما يلزم إلى الخادم. يستخدم أباتشي الوحدات في العديد من المهام، ونظرًا للباع الطويل لمنصة أباتشي، فيتوفّر عدد هائل من مكتبات الوحدات، والّتي من المُمكن استخدامها في تعديل بعض الوظائف الداخليّة في بنية خادم أباتشي، فمثلًا الوحدة mod_php تقوم بدمج مُفسّر PHP داخل كل عامل (worker). لا تنحصر الوحدات لمُعالجة المُحتوى الديناميكي (المُتغيّر) فقط، فيُمكن استخدامها في العديد من الوظائف، فيُمكن استخدامها في: rewriting URLs: إعادة كتابة العناوينauthenticating: المُصادقةlogging: التّتبّعcaching: التخبئةcompression: الضغطproxying: الوساطةencrypting: التشفيركيف يتعامل Nginx مع نظام الوحدات (Modules)يُطبّق ويتعامل Nginx مع نظام الوحدات، ولكن يختلف الأمر عما هو في نظام أباتشي، فلا تُحمّل الوحدات بشكل ديناميكي في نظام Nginx، لذلك يجب على هذه الوحدات أنّ تُختار وتُترجم (compiled) إلى النواة. قد يبدو الأمر صعبًا للعديد من المُستخدمين وخاصّة لهؤلاء الذين لا يُحبذون صيانة برمجياتهم المُترجمة (compiled) بدون الاستعانة بنظام حزم تقليدي، وعلى الرغم من أنّ حزم الموزّع تتضمّن الوحدات الأكثر استخدامًا، ولكن عند الحاجة إلى وحدة غير شائعة، سيتوجب على مُدير النظام بناء الخادم من المصدر بنفسه. تَبقى وحدات Nginx مع ذلك ذات فائدة، وتسمح لمُدير النّظام بتحديد ماذا يجب على الخادم أنّ يحتوي من وظائف، أيضًا بعض المُدراء ينظر إلى الأمر من منظور الحماية، حيثُ أنّ المُكوّنات الاعتباطيّة لا يُمكن أن تُدرج داخل الخادم. تُقدّم وحدات Nginx مقدرات مُماثلة للوحدات الّتي المُقدّمة من أباتشي، على سبيل المثال، توفّر وحدات Nginx: proxying support: الوساطةcompression: الضغطlogging: التّتبّعrewriting: إعادة كتابة العنوانauthentication: المُصادقةencryption: التشفيرالدعم والتوافُقيّة والتوثيقيجب دائمًا التأكد من آليّة بناء الخادم ومُتطلباتها، وما الّذي على مُدير النّظام عمله لبناء خادم يعمل بأبسط الإمكانيات، وما هو حجم الدعم والمُساعدة المتوفّر لهذه البرمجية. الدعم في أباتشييُعرف الخادم أباتشي بباعه الطويل في هذا المجال، ولذلك فإن الدعم الخاصّ به متواجد وبقوّة، حيثُ يتوفّر توثيق مُمتاز لمكتباته الخاصّة به ومكتبات الطرف الثالث (الخارجيّة)، وعلى كافّة المُستويات، سواء كان لنواة الخادم أو للجزئيات المُرتبطة ببرمجيات أُخرى. يتوفّر بجانب التوثيق، العديد من الأدوات ومشاريع الويب لتسريع بدء العمل مع بيئة الخادم، وهي موجودة ضمن المشاريع نفسها أو مُتوفّرة ضمن برمجيات الحزم المعروفة. يَملك أباتشي بشكلٍ عام دعمًا قويًا من قِبل مشاريع الطرف الثالث، وذلك بسبب حصته السوقيّة، وقِدَمه، كما يَملك مُعظم مُدراء الأنظمة بشكل أو بآخر معرفة جيّدة بخادم أباتشي، ليس فقط بسبب انتشاره، ولكن أيضًا بسبب أنّ معظمهم بشكل أو بآخر يستخدم الاستضافة المُشتركة (shared-hosting)، والّتي تعتمد على خادم أباتشي بشكل حصري، لمقدرته الإدارية الموزّعة باستخدام ملفّ .htaccess. الدعم في Nginxيكسب Nginx المزيد من الدعم مع ازدياد المُستخدِمين بسبب أدائه العالي، ولكن يبقى عليه التطوير من نفسه في بعض الجزئيات. قد كان من الصعب إيجاد توثيق مفهوم وواضح بالغة الإنكليزية للخادم Nginx في البداية، نظرًا إلى أنّ تطويره وتوثيقه تمّ بالغة الروسية، ومع ازدياد الاهتمام بالمشروع، أصبح هناك وفرة من المصادر على الموقع الرسميّ وغيره من الدعم الخارجي. أصبح الدعم متوفّرًا أكثر من ذي قبل فيما يخص تطبيقات الطرف الثالث، وبدأت بعض الحزم بتقدم خيارات الإعداد التلقائي سواءً لـ أباتشي أو Nginx، وعند عدم توفّر الدعم، فإن إعداد Nginx مع البرمجيات البديلة عادةً ما يكون واضحًا ومُيسرًا طالما أنّ برمجية الطرف الثالث تملك توثيقًا جيّدًا لمُتطلّباتها. استخدام Apache و Nginx معًاتمّ عرض فوائد وقصور كلا الخادومين، ويجب على مُدير النّظام في هذه المرحلة أنّ يُحدّد أيًا منهما يُناسب احتياجاته، ولكن يجد العديد من المُستخدِمين أنّه من المُمكن تقوية خادوم الويب عند استخدام كلٍ من أباتشي و Nginx جنبًا إلى جنب. إن إتمام هذه الشراكة يتمّ عن طريق تَمَوْضُع Nginx أمام أباتشي كوكيل/وسيط عكسي (reverse proxy)، وهذه يسمح لـ Nginx بمُعالجة جميع الطلبات من العُملاء، الأمر الّذي يَسمح بالاستفادة من سرعة Nginx وقدرته على تولّي عدد كبير من الاتصال في وقتٍ واحد. إن خدمة الملفّات الثّابتة بسرعة كبيرة ومباشرةً إلى العُملاء، هو الأمر الّذي يتفوّق به Nginx، ولكن وللمُحتوى الديناميكي، ملفات PHP مثلًا، سيُوكل Nginx الطلبات إلى أباتشي لمُعالجتها والعودة بصفحة بالنتيجة النهائيّة، ليستطيع Nginx عندها تمرير المُحتوى إلى العميل. يعمل هذا الإعداد بشكل جيّد للعديد من مُدراء الأنظمة، وذلك بسبب أنّه يسمح لـ Nginx ليعمل كآلة فرز وتصنيف، بمعنى أنّه سيتولّى مُعالجة جميع الطلبات طالما أنّه يستطيع ذلك، وتمرير ما لا يستطيع التعامل معه، وبتخفيض الطلبات المطلوب من خادم أباتشي تولّيها، سيُخفف بعضًا من الاستيقاف (blocking) الّذي قد يحدث عندما يستهلك أباتشي المزيد من المُعالج. يَسمح هذا الإعداد أيضًا لمُدراء الأنظمة بالتوسّع عن طريق إضافة خادم خلفي (backend) على حسب الحاجة والضرورة، ومن المُمكن إعداد Nginx لتمرير الطلبات إلى تجمّع (pool) من الخوادم بسهولة، الأمر الّذي يزيد من الأداء والفعاليّة. الختاميُقدّم كلًا من أباتشي و Nginx مُرونة في الاستخدام، وقوّةً في الأداء، والتفضيل بينهما هو لأمرٌ يَعتمد على تقدير مُتطلبات ووظائف الخادم، وعلى مُدير النّظام أنّ لا يسأل: هو أفضل خادم ويب؟، بل السؤال الّذي يجب سؤاله هو، ما هو أفضل خادم ويب لمشروعي الّذي يتطلّب كذا وكذا؟ يوجد بالفعل اختلافات بين المشروعين، هذه الاختلافات من شأنها أن تأثر على الأداء، والقدرات، والوقت المُستغرق في إتمام أي منهما للعمل بالجاهزيّة الكاملة، ولكي يتمّ اختيار الأفضل يُنصح بعمل تسوية أو مقايضة بين المحاسن والمساوئ، ففي نهاية المطاف لا يوجد خادم يُلبي كافة الاحتياجات، ويَكمن الحلّ في ترتيب الأولويات. ترجمة –وبتصرّف– للمقال Apache vs Nginx: Practical Considerations لصاحبه Justin Ellingwood.
  11. تمهيد كلما كانت صفحات الموقع أسرع تحميلًا كلما ازداد احتمال بقاء الزائر متصفحًا للموقع، وعندما تمتلئ صفحات مواقع الويب بالصور والمحتوى التفاعلي الظاهر عبر سكربتات تُحمَّل في الخلفية، فلن تكون عملية فتح «صفحة» ويب أمرًا هينًا، إذ تتضمن طلب ملفاتٍ عدِّة من خادوم الويب ملفًا ملفًا، وعملية تقليل تلك الطلبيات هي إحدى سُبُل تسريع موقعك. يمكن فعل ذلك بطرائق عدِّة، لكن إحدى أهم الخطوات التي يجب إجراؤها هي ضبط التخزين المؤقت في المتصفح (browser caching)؛ وهذا يعني إخبار المتصفح بإمكانية استخدام نسخ محلية من الملفات التي حُمِّلَت في إحدى المرات بدلًا من طلبها من الخادوم مرارًا وتكرارًا؛ ولفعل ذلك يجب إضافة ترويسات لرد HTTP ‏(HTTP response headers) تخبر المتصفح بما عليك فعله. هذا هو دور وحدة header (‏header module) في خادوم Nginx، التي يمكن استعمالها لإضافة الترويسات إلى رد HTTP، لكن دورها الأساسي يمكن في ضبط الترويسات المسؤولة عن التخزين المؤقت. سننظر في هذا الدرس إلى كيفية استخدام وحدة header لتطبيق الفكرة السابقة. المتطلبات المسبقة ستحتاج قبل إكمال قراءة هذا الدرس إلى ما يلي: خادوم أوبنتو 16.04 (أو 14.04) مضبوطٌ كما في درس «الإعداد الابتدائي لخادوم أوبنتو 14.04»، بما في ذلك إعداد حساب مستخدم عادي لكنه يملك امتيازات الجذر (root) عبر الأداة sudo. خدمة Nginx مثبّتة على خادومك باتباعك لهذا الدرس «تنصيب، إعداد واستخدام nginx كخادوم ويب». سنحتاج بالإضافة إلى وحدة header إلى وحدة map التابعة لخادوم Nginx؛ لمزيدٍ من المعلومات حول وحدة map، فاقرأ درس كيفية استخدام وحدة map على خادوم أوبنتو 16.04. الخطوة الأولى: إنشاء ملفات للتجربة سنُنشِئ في هذه الخطوة عدِّة ملفات في مجلد Nginx، إذ سنستخدم هذه الملفات لاحقًا للتحقق من سلوك خادوم Nginx الافتراضي لاختبار أنَّ التخزين المؤقت في المتصفح يعمل عملًا صحيحًا. لتقرير ما هو نوع الملفات المُخدَّمة عبر الشبكة، فلن يُحلِّل Nginx محتويات الملف لأن ذلك يستهلك وقتًا كثيرًا؛ وإنما سينظر إلى لاحقة (أو امتداد) الملف لتحديد ما هو نوع MIME التابع له، والذي سيُصرِّح عن الهدف أو الغاية من الملف. ونتيجةً لهذا السلوك، فلن يكون لمحتوى الملفات الاختبارية أيّة أهمية؛ إذ سنستطيع خداع خادوم Nginx بتسمية الملفات تسميةً صحيحةً، فقد يظن خادوم Nginx أنَّ ملفًا فارغًا يُمثِّل صورةً وآخر يُمثِّل سكربت JavaScript. لنُنشِئ ملفًا باسم test.html في مجلد Nginx الافتراضي عبر الأداة truncate (يمكنك استخدام أيّة أداة أو أمر آخر وليكن touch مثلًا). لاحقة الملف تُشير إلى أنَّه مستند HTML: sudo truncate -s 1k /var/www/html/test.html لنُنشِئ المزيد من الملفات الاختبارية بنفس الطريقة السابقة: صورة jpg وملف css وسكربت js: sudo truncate -s 1k /var/www/html/test.jpg sudo truncate -s 1k /var/www/html/test.css sudo truncate -s 1k /var/www/html/test.js الخطوة التالية هي التحقق من سلوك خادوم Nginx فيما يتعلق بإرسال ترويسات للتحكم بالتخزين المؤقت للمتصفح وذلك بتخديم الملفات التي أنشأناها أخيرًا مع الضبط الافتراضي له. الخطوة الثانية: التحقق من السلوك الافتراضي لخادوم Nginx يكون لجميع الملفات نفس سلوك التخزين المؤقت افتراضيًا. ولرؤية ذلك سنستخدم ملف HTML الذي أنشأناه في الخطوة الأولى، إلا أنَّك تستطيع إجراء هذا الاختبار على أيّ ملف من الملفات التي أنشأناها سابقًا. لنتحقق من أنَّ الملف test.html يُخدَّم ومعه المعلومات التي لها علاقة بالمدة الواجب تخزين المتصفح للملف فيها مؤقتًا. سيؤدي الأمر الآتي إلى طلب الملف من خادوم Nginx المحلي ويُظهِر ترويسات رد HTTP: curl -I http://localhost/test.html يجب أن ترى عدِّة ترويسات HTTP: HTTP/1.1 200 OK Server: nginx/1.10.0 (Ubuntu) Date: Sat, 10 Sep 2016 13:12:26 GMT Content-Type: text/html Content-Length: 1024 Last-Modified: Sat, 10 Sep 2016 13:11:33 GMT Connection: keep-alive ETag: "57d40685-400" Accept-Ranges: bytes يمكنك أن تلاحظ السطر قبل الأخير الذي يبدأ بالكلمة ETag الذي يتضمن مُعرِّفًا فريدًا للنسخة الحالية من الملف المطلوب. فإذا حاولت تنفيذ أمر curl السابق أكثر من مرة فستجد نفس قيمة ETag. أما عند استخدام متصفح ويب، فستُخزَّن قيمة ETag ثم تُرسَل إلى الخادوم عبر ترويسة If-None-Match عندما يريد المتصفح أن يطلب نفس الملف مرةً أخرى (عند تحديث الصفحة على سبيل المثال). يمكنك محاكاة ذلك في سطر الأوامر بالأمر الآتي. احرص على تغيير قيمة الترويسة If-None-Match في الأمر لتُطابِق قيمة ETag في ناتج الأمر السابق: curl -I -H 'If-None-Match: "57d40685-400"' http://localhost/test.html ستجد أنَّ الرد أصبح مختلفًا الآن: HTTP/1.1 304 Not Modified Server: nginx/1.10.0 (Ubuntu) Date: Sat, 10 Sep 2016 13:20:31 GMT Last-Modified: Sat, 10 Sep 2016 13:11:33 GMT Connection: keep-alive ETag: "57d40685-400" ردّ خادوم Nginx بحالة «‎304 Not Modified»، ولن يُرسِل الملف عبر الشبكة مجددًا، وإنما يخبر المتصفح أنَّه يستطيع إعادة استخدام الملف المُخزَّن محليًا والذي نزَّله سابقًا. ما سبق مفيدٌ لأنه يُقلِّل من التراسل الشبكي، لكنه ليس مثاليًا لتحقيق أداءٍ عالٍ نتيجةٍ للتخزين المؤقت. المشكلة مع ترويسة ETag أنَّ المتصفح سيرسل الطلبية إلى الخادوم دائمًا ويسأله إن كان بإمكانه استخدام الملف المُخزَّن مؤقتًا، وحتى لو ردّ الخادوم على المتصفح بالإيجاب بحالة 304 بدلًا من إعادة إرسال الملف مجددًا، إلا أنَّ إرسال الطلبية واستلام الرد سيستهلك وقتًا. سنستخدم في الخطوة التالية وحدة headers لإضافة معلومات للتحكم بالتخزين المؤقت. وهذا سيجعل المتصفح يُخزِّن الملفات محليًا دون أخذ إذن الخادوم أولًا. الخطوة الثالثة: ضبط ترويستَي Cache-Control و Expires إضافةً إلى ترويسة التحقق من تغيّر الملف (ETag)، هنالك ترويستان للتحكم بالتخزين المؤقت هما Cache-Control و Expires. ترويسة Cache-Control هي نسخةٌ أحدث، وفيها خياراتٌ أكثر مقارنةً بترويسة Expires وهي أفيد إن شئت التحكم بسلوك التخزين المؤقت تحكمًا دقيقًا. إذا ضُبِطَت تلك الترويسات، فهي تخبر المتصفح أنَّ الملف المطلوب يمكن أن يُخزَّن محليًا لفترةٍ زمنيةٍ معيّنة (تستطيع أن تجعل صلاحيته «للأبد»!) دون طلبه مرةً أخرى. أما إن لم تُضبَط تلك الترويسات، فسيطلب المتصفحُ الملفَ دومًا من الخادوم، متوقعًا أن يحصل على الحالة «‎200 OK» أو «‎304 Not Modified». يمكننا استخدام وحدة header لإرسال ترويسات HTTP آنفة الذكر. وحدة header هي وحدةٌ من أساس خادوم Nginx لذا لن تحتاج إلى تثبيت أيّ شيءٍ لاستخدامها. لإضافة وحدة header، افتح ملف ضبط Nginx في محرر nano أو أيّ محررٍ نصيٍ تشاء: sudo nano /etc/nginx/sites-available/default اعثر على القسم المُعَنوَنَ server، والذي يبدو كما يلي: . . . # Default server configuration # server { listen 80 default_server; listen [::]:80 default_server; . . . أضف القسمَين الآتيين: أولهما قبل قسم server لتعريف المدة الزمنية لتخزين مختلف أنواع الملفات مؤقتًا، وثانيهما داخل كتلة server الذي يضبط ترويسات التخزين المؤقت ضبطًا سليمًا: . . . # Default server configuration # # Expires map map $sent_http_content_type $expires { default off; text/html epoch; text/css max; application/javascript max; ~image/ max; } server { listen 80 default_server; listen [::]:80 default_server; expires $expires; . . . القسم الموجود قبل قسم server هو قسم map الذي يربط بين أنواع الملفات ومدة التخزين المؤقت لهذا النوع من الملفات. استعملنا عدِّة خيارات ضبط فيه: القيمة الافتراضية هي off، والتي لن تُضيف أيّة ترويسات للتحكم بالتخزين المؤقت، وهذا خيارٌ جيدٌ للمحتوى الذي لا يتطلب تخزينًا مؤقتًا. لنوع text/html سنضبط القيمة إلى epoch وهي قيمةٌ خاصةٌ التي تعني عدم التخزين المؤقت نهائيًا، مما يجبر المتصفح على السؤال إن كانت الصفحة مُحدَّثة. لنوع text/css و application/javascript -والتي هي ملفات الأنماط CSS وسكربتات JavaScript- سنضبط القيمة إلى max وهذا يعني أنَّ المتصفح سيُخزِّن هذه الملفات مؤقتًا أطول مدة يستطيعها، مما يُقلِّل عدد الطلبيات لوجود عدد كبير من هذه الملفات التي ترتبط بصفحة HTML. آخر خيار لنوع ‎~image/‎ وهو تعبيرٌ نمطيٌ (regular expression) الذي يُطابِق جميع الملفات ذات النوع الذي يحتوي على العبارة image/‎ فيه (مثل image/jpg و image/png). وكما في ملفات CSS و JS، تتواجد عادةً صورٌ كثير في مواقع الويب، ومن الجيد تخزينها محليًا، لذا ضبطنا القيمة إلى max أيضًا. التعليمة expires داخل قسم server (التي هي جزءٌ من وحدة headers) تضبط ترويسات التحكم بالتخزين المؤقت؛ حيث تستخدم القيمة المأخوذة من المتغير ‎$expires الذي يربط بين أنواع الملفات ومدة صلاحيتها. وبهذه الطريقة ستختلف الترويسات المُرسَلة اعتمادًا على نوع الملف. احفظ الملف واخرج من المُحرِّر النصي، وأعد تشغيل خادوم Nginx لتفعيل الضبط الجديد: sudo systemctl restart nginx سنتحقق في الخطوة التالية من أنَّ الضبط الجديد يعمل عملًا سليمًا. الخطوة الرابعة: اختبار التخزين المؤقت في المتصفح لنُنفِّذ نفس الأمر الذي طلبنا فيه ملف HTML في القسم السابق: curl -I http://localhost/test.html سيكون الرد مختلفًا هذه المرة، إذ يجب أن ترى ترويستين جديدتين: HTTP/1.1 200 OK Server: nginx/1.10.0 (Ubuntu) Date: Sat, 10 Sep 2016 13:48:53 GMT Content-Type: text/html Content-Length: 1024 Last-Modified: Sat, 10 Sep 2016 13:11:33 GMT Connection: keep-alive ETag: "57d40685-400" Expires: Thu, 01 Jan 1970 00:00:01 GMT Cache-Control: no-cache Accept-Ranges: bytes ترويسة Expires مرتبطة بتاريخٍ في الماضي وترويسة Cache-Control مضبوطةٌ إلى no-cache، مما يجعل المتصفح يسأل الخادوم إن توفرت نسخةٌ جديدةٌ من الملف (باستخدام ترويسة ETag كما سبق). ستجد ردًا مختلفًا عندما تُجرِّب على صورة: curl -I http://localhost/test.jpg ناتج الأمر السابق: HTTP/1.1 200 OK Server: nginx/1.10.0 (Ubuntu) Date: Sat, 10 Sep 2016 13:50:41 GMT Content-Type: image/jpeg Content-Length: 1024 Last-Modified: Sat, 10 Sep 2016 13:11:36 GMT Connection: keep-alive ETag: "57d40688-400" Expires: Thu, 31 Dec 2037 23:55:55 GMT Cache-Control: max-age=315360000 Accept-Ranges: bytes ارتبطت الترويسة Expires في هذه المرة بتاريخٍ في المستقبل البعيد، واحتوت ترويسة Cache-Control على max-age التي تخبر المتصفح كم ثانية يجب أن يُبقي على الملف. وهذا يُخبِر المتصفح أن يُخزِّن الصورة المُنزَّلة مؤقتًا لأطول مدة ممكنة، وبالتالي إذا ظهرت الصورة مرةً أخرى فستُستعمَل النسخة المحلية ولن تُرسَل الطلبية إلى الخادوم بتاتًا. يجب أن تكون النتيجة مشابهةً لملفَي test.js و test.css لأنهما ملفا JavaScript و CSS ويُضبَط لهما ترويسات التخزين المؤقت أيضًا، مَثَلُهُما كَمَثل الصور. إن ظهر عندك مثلما عرضنا في أمثلتنا، فاعلم أنَّ ترويسات التحكم بالتخزين المؤقت قد ضُبِطَت ضبطًا صحيحًا وسيستفيد موقعك من ناحية الأداء، وسيقل الحِمل على خادومك نتيجةً لتخزين المتصفح للملفات محليًا وعدم طلبها من الخادوم. عليك الآن أن تُخصِّص إعدادات التخزين المؤقت اعتمادًا على محتوى موقعك، لكن قد تجد أنَّ الضبط الذي وفرناه في هذا الدرس مناسبًا لتبدأ منه. الخلاصة يمكن أن تُستعمَل وحدة headers لإضافة أي نوع من الترويسات إلى رد HTTP، لكن من أفضل تطبيقات هذه الوحدة هو ضبط ترويسات التحكم بالتخزين المؤقت. إذ سيساعد ذلك في تحسين أداء مواقع الويب المُستضافة على خادومك، خصوصًا في الشبكات ذات زمن التأخير المرتفع (نسبيًا) مثل شبكات الهواتف المحمولة. يمكن أن يؤدي ذلك إلى تحسين ظهور موقعك في محركات البحث التي تأخذ عامل سرعة الموقع بالحسبان. حيث يُعتَبَر ضبط ترويسات التخزين المؤقت من أبزر نصائح أدوات اختبار سرعة الصفحات من Google (أقصد Google PageSpeed). لمزيدٍ من المعلومات التفصيلية عن وحدة headers، فارجع إلى توثيق Nginx الرسمي. ترجمة -وبتصرّف- للمقال How to Implement Browser Caching with Nginx’s header Module on Ubuntu 16.04 لصاحبه Mateusz Papiernik.
  12. سنتعلّم في هذا الدّرس كيفيّة استخدام HAProxy (والذي يرمز إلى الوسيط عالي التوفّر High Availability Proxy) كمُوازِن حمل عن طريق الطبقة السّابعة layer 7 load balancer من أجل تخديم تطبيقات متعدّدة من اسم مجال واحد Single Domain أو عنوان IP، بإمكان موازنة الحمل أن تزيد أداء، توفّر، ومرونة بيئتنا. تكون موازنة الحمل والوسيط العكسي للطبقة 7 ملائمة لموقعك إن أردت أن تملك اسم نطاق واحد يقوم بتخديم تطبيقات متعدّدة، حيث يمكن تحليل طلبات http لتقرّر أي تطبيق ينبغي عليه أن يستقبل حركة مرور البيانات. تمّت كتابة هذا الدّرس باستخدام ووردبريس وموقع ثابت Static website كأمثلة، ولكن يمكن استخدام مفاهيمه العامّة مع تطبيقات أخرى للحصول على تأثير مماثل. المتطلبات الأساسية قبل متابعة هذا الدّرس ينبغي عليك أن تملك تطبيقين على الأقل يعملان على خادومين منفصلين، سنستخدم موقعًا ثابتًا مستضافًا على Nginx و ووردبريس كتطبيقين لدينا، وبالإضافة للبيئة الحاليّة لديك سنقوم بإنشاء الخواديم التالية: haproxy-www: وهو خادوم HAProxy لأجل موازنة الحمل والوسيط العكسي wordpress-2: وهو خادوم الويب الثاني لووردبريس (تحتاجه فقط إن أردت موازنة حمل مكونات ووردبريس في بيئتك) web-2: خادوم ويب Nginx الثاني (تحتاجه فقط إن أردت موازنة حمل مكونات Nginx في بيئتك) إن لم يسبق لك التّعامل مع المفاهيم أو المصطلحات الأساسيّة لموازنة الحمل، مثل موازنة الحمل عن طريق الطبقة 7 أو الواجهات الخلفيّة backends أو قوائم تحكّم الوصول ACLs فهذا هو الدّرس الذي يشرح الأساسيّات: مقدّمة إلى HAProxy ومبادئ موازنة الحمل (Load Balancing). هدفنا بنهاية هذا الدّرس نريد أن نحصل على بيئة تبدو كما يلي: أي سيقوم المستخدمون لديك بالنفاذ لكلا تطبيقيك عبر http://example.com، وسيتم تمرير كل الطلبات التي تبدأ بـ http://example.com/wordpress إلى خواديم ووردبريس، ويتم تمرير جميع باقي الطلبات إلى خواديم Nginx الأساسيّة، لاحظ أنّه لا تحتاج بالضرورة لموازنة حمل تطبيقاتك حتى تظهر على مجال واحد، ولكن سنقوم بتغطية موازنة الحمل في هذا الدّرس. تثبيت HAProxy نقوم بإنشاء خادوم جديد مع الشّبكات الخاصّة، سنسمّيه في هذا الدّرس haproxy-www. نقوم بتثبيت HAProxy على الخادوم haproxy-www باستخدام apt-get: sudo apt-get update sudo apt-get install haproxy نحتاج لتمكين سكريبت التهيئة init script لـ HAProxy كي يبدأ ويتوقف HAProxy مع الخادوم لدينا: sudo vi /etc/default/haproxy نغيّر قيمة ENABLED إلى 1 لتمكين سكريبت التهيئة لـ HAProxy: ENABLED=1 نقوم بالحفظ والخروج، سيبدأ ويتوقف HAProxy الآن مع خادومنا، نستطيع أيضًا الآن استخدام الأمر service للتحكّم بـ HAProxy، فلنتحقّق من أنّه قيد التشغيل: user@haproxy-www:/etc/init.d$ sudo service haproxy status haproxy not running. نجد أنّه لا يعمل، لا مشكلة لأنّه يحتاج إلى إعداده قبل أن نتمكّن من استخدامه، فلنقم الآن بإعداد HAProxy لأجل بيئتنا. إعداد HAProxy يكون ملف إعدادات HAProxy مُقسّمًا إلى قسمين رئيسيين: العمومي Global: يقوم بتعيين المُعامِلات parameters على نطاق العمليّة الوسطاء Proxies: يتكون من المُعامِلات الافتراضيّة defaults، الاستماع listen، الواجهة الأماميّة frontend، والواجهة الخلفيّة backend. مرّة أخرى إن لم يسبق لك أن سمعت عن مفاهيم أو المصطلحات الأساسيّة لموازنة الحمل، فقم بالرجوع إلى هذا الدّرس: مقدّمة إلى HAProxy ومبادئ موازنة الحمل (Load Balancing). إعداد HAProxy: العمومي يجب أن يتم ضبط إعدادات HAProxy على الخادوم haproxy-www. في البداية لنقم بعمل نسخة من الملف haproxy.cfg الافتراضي: cd /etc/haproxy; sudo cp haproxy.cfg haproxy.cfg.orig نقوم الآن بفتح الملف haproxy.cfg باستخدام مُحرِّر نصوص: sudo vi /etc/haproxy/haproxy.cfg سنشاهد وجود قسمين معرّفين مسبقًا: global و defaults، سنلقي نظرة في البداية على بعض المعاملات القياسية default. تحت القسم defaults نبحث عن الأسطر التالية: mode http option httplog يقوم اختيار http كوضع بضبط HAProxy ليعمل كموازن حمل عن طريق الطبقة 7 (أو طبقة التطبيقات)، يعني هذا أنّ موازن الحمل سينظر إلى محتوى طلبات http ويقوم بتمريرها إلى الخادوم المناسب اعتمادًا على القواعد المعرّفة في الواجهة الأماميّة frontend، إن لم يكن هذا المفهوم مألوفًا لديك فمن فضلك اقرأ قسم أنواع موازنة الحمل في درس مقدّمة إلى HAProxy. لا تقم بإغلاق ملف الإعدادات الآن، لأنّنا سنضيف إعدادات الوسيط. إعداد HAProxy: الوسطاء إعداد الواجهة الأماميّة أول شيء نريد إضافته هو واجهة أماميّة frontend، ولأجل إعداد أساسي لوسيط عكسي وموازنة حمل عن طريق الطبقة 7 سنحتاج لتعريف قائمة تحكّم وصول ACL تُستخدَم لتوجيه حركة مرور بياناتنا إلى خواديم الواجهة الخلفيّة المناسبة، هنالك العديد من قوائم تحكّم الوصول التي يُمكن استخدامها في HAProxy، سنغطي فقط واحدة منها في هذا الدّرس (وهي path_beg)، ولأجل الحصول على قائمة كاملة من قوائم تحكّم الوصول في HAProxy قم بمراجعة التّوثيق الرسميّ: HAProxy ACLs. نضيف واجهتنا الأماميّة www في نهاية الملف، تأكّد من أن تضع عنوان IP الخاص بخادوم haproxy-www لديك بدلًا من haproxy_www_public_IP: frontend www bind haproxy_www_public_IP:80 option http-server-close acl url_wordpress path_beg /wordpress use_backend wordpress-backend if url_wordpress default_backend web-backend وهذا شرح لما يعنيه كل سطر من المقطع السابق المأخوذ من إعدادات الواجهة الأماميّة: frontend www: يُعيِّن واجهة أماميّة اسمها "www"، حيث سنستخدمها للتعامل مع حركة مرور بيانات www الواردة. bind haproxy_www_public_IP:80: ضع عنوان IP خادوم haproxy-www لديك بدلًا من haproxy_www_public_IP، يُخبر هذا السطر HAProxy أنّ هذه الواجهة الأماميّة ستتعامل مع حركة مرور بيانات الشبكة الواردة إلى عنوان IP هذا على هذا المنفذ. option http-server-close: يقوم بتمكين وضع إغلاق اتصال HTTP على الخادوم، ويحافظ على القدرة على دعم ترويسة HTTP keep-alive وتقنيّة HTTP pipelining على العميل (وهي تقنيّة لإرسال العديد من طلبات HTTP ضمن اتصال TCP وحيد بدون انتظار الموافقة لها)، يسمح هذا الخيار بأن يقوم HAProxy بمعالجة طلبات متعدّدة للعميل ضمن اتصال وحيد، والذي عادة ما يزيد من الأداء. acl url_wordpress path_beg /wordpress: يُعيِّن قائمة تحكّم وصول ACL تُدعى url_wordpress والتي تكون قيمتها صحيحة true إن كان مسار الطلب يبدأ بـ "wordpress/"، على سبيل المثال http://example.com/wordpress/hello-world. use_backend wordpress-backend if url_wordpress: يقوم بإعادة توجيه أي حركة مرور بيانات تتوافق مع قائمة تحكّم الوصول url_wordpress إلى wordpress-backend، والتي سنقوم بتعريفها قريبًا. default_backend web-backend: يُحدِّد أنّه أي حركة مرور بيانات لا تتوافق مع قاعدة use_backend سيتم تمريرها إلى web-backend، والتي سنقوم بتعريفها في الخطوة القادمة. إعداد الواجهة الخلفية Backend بعد أن تنتهي من إعداد الواجهة الأماميّة، قم الآن إضافة واجهتك الخلفيّة الأولى عن طريق إضافة الأسطر التالية، تأكّد من أن تضع عنوان IP المناسب بدلًا من web_1_private_IP: backend web-backend server web-1 web_1_private_IP:80 check وهذا شرح لما يعنيه كل سطر من المقطع السابق المأخوذ من إعدادات الواجهة الخلفيّة: backend web-backend: يُعيِّن واجهة خلفيّة تُدعى web-backend. server web-1 ... : يُعيِّن خادوم واجهة خلفيّة يُدعى web-1، مع عنوان IP الخاص (وهو الذي يجب أن تستبدله) والمنفذ الذي يستمع عليه، وهو 80 في هذه الحالة، يُخبِر الخيار check مُوازِن الحمل أن يُجري دوريًّا تحقّق من السّلامة على هذا الخادوم. بعدها أضف الواجهة الخلفيّة لتطبيق ووردبريس لديك: backend wordpress-backend reqrep ^([^\ :]*)\ /wordpress/(.*) \1\ /\2 server wordpress-1 wordpress_1_private_IP:80 check وهذا شرح لما يعنيه كل سطر من المقطع السابق المأخوذ من إعدادات الواجهة الخلفيّة: backend wordpress-backend: يُعيِّن واجهة خلفيّة تُدعى wordpress-backend. reqrep ... : يعيد كتابة الطلبات من wordpress/ إلى / عند تمرير حركة مرور البيانات إلى خواديم ووردبريس، وهو ليس ضروريًّا إن كان تطبيق ووردبريس مُثبّتًا على جذر root الخادوم ولكن نحتاج إليه لقابلية النفاذ عبر wordpress/ على خادوم HAProxy. server wordpress-1 ... : يُعيِّن خادوم واجهة خلفيّة يُدعى wordpress-1، مع عنوان IP الخاص (وهو الذي يجب أن تستبدله) والمنفذ الذي يستمع عليه، وهو 80 في هذه الحالة، يُخبِر الخيار check مُوازِن الحمل أن يُجري دوريًّا تحقّق من السّلامة على هذا الخادوم. إعدادات HAProxy: الإحصائيات Stats إن أردت تمكين إحصائيّات HAProxy، والتي قد تكون مفيدة في تحديد كيفيّة تعامل HAProxy مع حركة مرور البيانات الواردة، ستحتاج إلى إضافة الأسطر التالية إلى إعداداتك: listen stats :1936 stats enable stats scope www stats scope web-backend stats scope wordpress-backend stats uri / stats realm Haproxy\ Statistics stats auth user:password وهذا شرح لما تعنيه الأسطر غير البديهيّة من المقطع السابق المأخوذ من إعدادات listen stats: listen stats :1936: يقوم بإعداد صفحة إحصائيّات HAProxy لتكون قابلة للنفاذ على المنفذ 1936 (أي http://haproxy_www_public_IP:1936). stats scope ... : يجمع الإحصائيّات على الواجهة المُحدّدة سواء كانت أماميّة أو خلفيّة. / stats uri: يُعيِّن رابط صفحة الإحصائيّات إلى / . stats realm Haproxy\ Statistics: يقوم بتمكين الإحصائيّات وتعيين اسم الاستيثاق realm Authentication (وهو استيثاق ذو نافذة منبثقة)، يُستخدَم بالترابط مع الخيار stats auth. stats auth haproxy:password: يُعيِّن اعتمادات credentials الاستيثاق لصفحة الإحصائيّات، قم بوضع اسم المستخدم وكلمة السّر الخاصّة بك. الآن قم بالحفظ والإغلاق، عند تشغيل HAProxy تكون صفحة الإحصائيّات متوفّرة عبر الرابط http://haproxy_www_public_ip:1936/ حالما تبدأ خدمة HAProxy لديك، تكون HAProxy جاهزة الآن لتشغيلها ولكن فلنقم بتمكين التسجيل logging أولًا. تمكين تسجيل HAProxy إنّ تمكين التسجيل في HAProxy بسيط جدًّا، قم في البداية بتحرير الملف rsyslog.conf: sudo vi /etc/rsyslog.conf ثم ابحث عن السطرين التاليين وأزل التعليق عنهما لتمكين استقبال UDP syslog، يجب أن تبدو كما يلي عند الفراغ منها: $ModLoad imudp $UDPServerRun 514 $UDPServerAddress 127.0.0.1 الآن أعد تشغيل rsyslog لتمكين الإعدادات الجديدة: sudo service rsyslog restart تم تمكين تسجيل HAProxy الآن، سيتم إنشاء ملف السّجل في المسار var/log/haproxy.log/ بعد أن يتم تشغيل HAProxy. تحديث إعدادات ووردبريس الآن وقد تم تغيير رابط تطبيق ووردبريس فيجب علينا تحديث بعض الإعدادات في ووردبريس. قم بتعديل الملف wp-config.php على أي خادوم ووردبريس، هذا الملف موجود في مكان تثبيت ووردبريس (في هذا الدّرس تم تثبيته على المسار var/www/example.com/ ولكن قد يكون مختلفًا لديك): cd /var/www/example.com; sudo vi wp-config.php ابحث عن السطر الموجود في بداية الملف الذي يحتوي على ('define('DB_NAME', 'wordpress وقم بإضافة الأسطر التالية فوقه مع استبدال http://haproxy_www_public_IP: define('WP_SITEURL', 'http://haproxy_www_public_IP'); define('WP_HOME', 'http://haproxy_www_public_IP'); قم بحفظ وإغلاق الملف، تمّ الآن إعداد روابط ووردبريس لتشير إلى موازن الحمل بدلًا من خادوم ووردبريس الأصلي والتي تلعب دورها عند محاولتك النفاذ إلى لوحة تحكم ووردبريس. تشغيل HAProxy قم بتشغيل HAProxy على الخادوم haproxy-www ليتم تطبيق تغييرات الإعدادات: sudo service haproxy restart إتمام الوسيط العكسي Reverse Proxy أصبحت الآن تطبيقاتنا قابلة للوصول إليها عبر نفس المجال، example.com، عبر الوسيط العكسي للطبقة 7، ولكن لم يتم تطبيق موازنة الحمل عليها بعد، تبدو الآن البيئة لدينا كالمخطط التالي: وفقًا للواجهة الأماميّة التي عرفناها سابقًا، هذا وصف حول كيفيّة تمرير HAProxy لحركة مرور البيانات: http://example.com/wordpress: سيتم إرسال أي طلب يبدأ بـ wordpress/ إلى wordpress-backend (والذي يتكون من الخادوم wordpress-1). http://example.com/: سيتم إرسال أيّة طلبات أخرى إلى web-backend (والذي يتكون من الخادوم web-1). إن كان كل ما تريد فعله هو استضافة تطبيقات متعدّدة على مجال وحيد فقد أنجزت هذا بنجاح، أمّا إن أردت موازنة حمل تطبيقاتك أكمل قراءة الدّرس. كيفية إضافة موازنة الحمل موازنة حمل الخادوم web-1 لموازنة حمل خادوم ويب أساسي، كل ما تحتاج إليه هو إنشاء خادوم ويب جديد يمتلك إعدادات ومحتوى مطابق لخادوم الأصلي، سندعو هذا الخادوم الجديد: web-2. لديك خياران عند إنشاء الخادوم الجديد: إن كنت تملك خيار إنشاء خادوم جديد انطلاقًا من صورة web-1، فهذه هي الطريقة الأبسط لإنشاء web-2. إنشاؤه من الصفر، تثبيت نفس البرمجيّات، إعداده بشكل مماثل، ومن ثمّ نسخ محتوى جذر خادوم Nginx من web-1 إلى web-2 باستخدام rsync (اقرأ درس كيف تستخدِم Rsync لمزامنة مجلّدات بين الجهاز المحلّي والخادوم). ملاحظة: إن كل من الطريقتين السابقتين تقوم بإنشاء نسخة لمحتويات جذر الخادوم مرّة وحيدة، لذلك إن قمت بتحديث أي من الملفّات على أحد خواديمك، web-1 أو web-2، فتأكّد من مزامنة الملفّات مرّة أخرى. بعد أن يتم إعداد خادوم ويب المماثل لديك، قم بإضافته إلى web-backend ضمن إعدادات HAProxy. على الخادوم haproxy-www قم بتحرير الملف haproxy.cfg: sudo vi /etc/haproxy/haproxy.cfg ابحث عن القسم web-backend من الإعدادات: backend web-backend server web-1 web_1_private_IP:80 check وبعدها أضف الخادوم web-2 في السطر التالي: server web-2 web_2_private_IP:80 check قم بحفظ وإغلاق الملف، وأعد تحميل HAProxy لتطبيق التغييرات: sudo service haproxy reload يمتلك web-backend الآن خادومين يتعاملان مع حركة مرور البيانات غير المرتبطة بووردبريس، أي تمّ إعداد موازنة الحمل عليه بنجاح. موازنة حمل الخادوم wordpress-1 إنّ موازنة حمل تطبيق مثل ووردبريس أكثر تعقيدًا بقليل من موازنة حمل خادوم ثابت، لأنّه يجب عليك الاهتمام بأشياء مثل مزامنة الملفّات المُحمّلة ومستخدمي قواعد البيانات الإضافيّين. أكمل الخطوات الثلاث التالية لإنشاء خادوم ووردبريس الثاني wordpress-2: إنشاء خادوم تطبيق ويب الثاني. مزامنة ملفّات تطبيق الويب. إنشاء مستخدم قاعدة بيانات جديد. بعد أن تقوم بإنشاء الخادوم wordpress-2 مع إعداد قاعدة البيانات بشكل صحيح فكل ما تبقى عليك فعله هو إضافته إلى wordpress-backend ضمن إعدادات HAProxy. على الخادوم haproxy-www قم بتحرير الملف haproxy.cfg: sudo vi /etc/haproxy/haproxy.cfg ابحث عن القسم wordpress-backend من الإعدادات: backend wordpress-backend server wordpress-1 wordpress_1_private_IP:80 check وبعدها أضف الخادوم wordpress-2 في السطر التالي: server wordpress-2 wordpress_2_private_IP:80 check قم بحفظ وإغلاق الملف، وأعد تحميل HAProxy لتطبيق التغييرات: sudo service haproxy reload يمتلك web-backend الآن خادومين يتعاملان مع حركة مرور البيانات غير المرتبطة بووردبريس، أي تمّ إعداد موازنة الحمل عليه بنجاح. الخاتمة بعد أن أتممت الآن هذا الدّرس يجب أن تكون قادرًا على توسيع موازنة الحمل والوسيط العكسي لإضافة المزيد من التطبيقات والخواديم لبيئتك لجعلها تتوافق بشكل أفضل مع احتياجاتك، تذكّر أنّه لا توجد حدود لطرق إعداد بيئتك، وربّما تحتاج إلى البحث في توثيق HAProxy إن أردت متطلبات أكثر تعقيدًا. ترجمة -وبتصرّف- للمقال How To Use HAProxy As A Layer 7 Load Balancer For WordPress and Nginx On Ubuntu 14.04 لصاحبه Mitchell Anicas.
  13. يُعدّ Nginx خادوم ويب مفتوح المصدر يتسّم بالسرعة والاعتمادية، كسب شعبيّته نتيجة حجم الذاكرة القليل الذي يستهلكه، وقابليته الكبيرة للتوسعة، وسهولة إعداده، ودعمه لمعظم البروتوكولات المختلفة. ويعتبر بروتوكول HTTP/2 الجديد نسبيًا أحد البروتوكولات التي يدعمها خادوم Nginx، الأمر الذي تم منذ أقل من عام مضى، وتعتبر الميّزة الرئيسية في HTTP/2 هي سرعة نقله العالية للمحتويات الغنيّة بالمعلومات في مواقع الويب. سيساعد المقال على تثبيت وإعداد خادوم Nginx سريع وآمن مع دعم لبروتوكول HTTP/2. المتطلبات الأولية قبل أن نبدأ، سنحتاج للأمور التالية: نظام تشغيل Ubuntu 14.04، مستخدم عادي بدون صلاحيات مدير نظام، لكنّه يملك صلاحية تنفيذ أمر sudo. يمكن مراجعة الإعداد الابتدائي لخادوم أوبونتو 14.04 لمزيد من المعلومات، نطاق موقع، ويمكن شراء واحد من موقع Namecheap أو الحصول على واحد مجانًا من موقع Freenom، تأكّد من أنّ النطاق يشير إلى عنوان نظام التشغيل الذي ستستخدمه عبر الإنترنت، وستساعدك مقالة إعداد اسم مضيف مع DigitalOcean إن احتجت لمساعدة، شهادة SSL رقميّة، ويمكن إنشاء واحدة بشكل يدوي، أو الحصول على واحدة مجانًا من Let’s Encrypt، أو شراء واحدة من مزوّد آخر. هذا كل شيء، فإن كانت لديك جميع المتطلبات المذكورة، فأنت جاهز للبدء. الفرق ما بين HTTP 1.1 و HTTP/2 إن HTTP/2 هو الإصدار الجديد من بروتوكول نقل النصوص الفائقة HTTP، الذي يستخدم على الشبكة العنكبوتية لإيصال محتويات صفحات الويب من الخوادم إلى المتصفّحات، وهو أول تحديث ضخم طرأ على HTTPمنذ حوالي عقدين، حيث تم إطلاق الإصدار HTTP 1.1 عام 1999 حينما كانت الصفحات عبارة عن ملف HTML مستقل مع أنماط CSS ضمنيّة (أي مكتوبة ضمن مستند HTML وليست مستوردة من ملف خارجي). لقد تغيّرت شبكة الإنترنت بشكل متسارع في السنوات الستة عشر الأخيرة، وأصبحنا الآن نواجه صعوبة مع المحدودية التي يفرضها HTTP 1.1، حيث يَحُدّ البروتوكول من سرعة النقل الممكنة لمعظم مواقع الويب الحديثة لأنه يقوم بتحميل أجزاء الصفحة وفق مبدأ الطابور queue (بمعنى أنه يجب أن ينتهي تحميل كل جزء قبل أن يبدأ تحميل الجزء التالي له)، ويحتاج موقع ويب حديث وسطيًّا حوالي 100 طلب ليتم تحميل الصفحة(كل طلب يمثّل صورة، ملف js، ملف css، إلخ). يقوم بروتوكول HTTP/2 بحل هذه المشكلة لأنّه يقوم بتقديم تغييرات جذرية تتمثل في: تحميل جميع الطلبات على التوازي، وليس على التسلسل كما في مبدأ الطابور، ضغط ترويسة HTTP، نقل الصفحات عبر الشبكة بصيغة ثنائية binary، وليس كنصوص text، وهذا أكثر فعالية، قدرة الخادوم الآن على "دفع" البيانات قبل أن يطلبها المستخدم، مما سيحسّن من السرعة للمستخدمين الذين يعانون من بطء في الإرسال. وعلى الرغم من أن بروتوكول HTTP/2 لا يتطلب التشفير، إلا أن مطوّري أشهر متصفّحين، Google Chrome و Mozilla Firefox، صرّحوا بأنه -لدواع أمنيّة- سيتم دعم بروتوكول HTTP/2 في اتصالات HTTPS الآمنة فقط، ولهذا السبب إن قررت تثبيت خواديم تدعم HTTP/2 فيجب عليك الانتقال إلى استخدام HTTPS. الخطوة الأولى: تثبيت الإصدار الأخير من Nginx تم طرح دعم HTTP/2 في إصدار Nginx 1.9.5، ولسوء الحظ فإنّ المستودع الافتراضي في نظام Ubuntu متأخر عن إدراج آخر إصدار ويقوم حاليًّا بتوفير الإصدار 1.4.6. لكن لحسن الحظ فإن مطوّري Nginx لديهم مستودع apt خاص على نظام Ubuntu، حيث بالإمكان الحصول دومًا على آخر إصدار متوفّر. لإضافة المستودع الخاص إلى قائمة مستودعات apt لدينا، نحتاج أولًا للحصول على مفتاح التوقيع الرقمي الخاص بالمستودع، وهذا إجراء أمني يضمن بأن الحزم البرمجية التي سنحصل عليها من هذا المستودع صادرة عن المطوّرين الحقيقين وموقّعة منهم. سنقوم بتنفيذ الأمر التالي في سطر الأوامر: $ wget -qO - http://nginx.org/keys/nginx_signing.key | sudo apt-key add - بعد ذلك، سنقوم بإضافة المستودع إلى قائمة مصادر الحزم البرمجية، بتنفيذ الأمر التالي: $ sudo echo -e "deb http://nginx.org/packages/mainline/ubuntu/ `lsb_release -cs` nginx\ndeb-src http://nginx.org/packages/mainline/ubuntu/ `lsb_release -cs` nginx" | sudo tee /etc/apt/sources.list.d/nginx.list الآن وبعد أن أصبح نظام الحزم (الذي يدعى apt في نظامي Ubuntu و Debian) يعلم عن توفّر المستودع الجديد، سنقوم بتحديث قائمة الحزم البرمجية المتوفّرة وأخيرًا سنقوم بتثبيت الإصدار الأخير من Nginx: $ sudo apt-get update $ sudo apt-get install nginx ويمكن التحقق من رقم الإصدار بتنفيذ الأمر: $ sudo nginx -v حيث ينبغي أن يكون الخرج مشابهًا لـ nginx version: nginx/1.9.x. سنقوم في الخطوات التالية بتغيير الإعدادات الافتراضية في Nginx ليقوم بتخديم موقع الويب الخاص بنا. الخطوة الثانية: تغيير منفذ التنصّت الافتراضي سنقوم أولًا بتغيير رقم المنفذ من 80 إلى 443، وذلك بفتح ملف الإعدادات: $ sudo nano /etc/nginx/conf.d/default.conf ملاحظة: في حال ظهر خطأ يخبرك بأنه لم يتم التعرّف على الأمر nano، فتأكّد من تثبيت محرر النصوص nano وحاول مجدّدًا. ينبغي أن نخبر Nginx برقم المنفذ الذي يجب عليه تلقّي الاتصالات عبره، وهو المنفذ 80 افتراضيًا، المنفذ القياسي في بروتوكول HTTP. سنبحث في ملف الإعدادات عن السطر التالي: listen 80; سنقوم بتغيير المنفذ إلى 443 لأن HTTP/2 لن يعمل مع معظم المستخدمين إذا بقي يقوم بإرسال البيانات عبر المنفذ 80، كما أشرنا سابقًا إلى أنه مدعوم فقط عبر المنفذ 443 على متصفحات Chrome و Firefox.سنستبدل السطر السابق بـ: listen 443 ssl http2; لاحظ أننا أضفنا كلمة ssl و http2 في نهاية السطر، وتخبر هذه المتغيّرات Nginx بأن يستخدم بروتوكول HTTP/2 مع المتصفحات التي تدعم البروتوكول الجديد. الخطوة الثالثة: تغيير اسم الخادوم يأتي اسم الخادوم server_name بعد السطر السابق الذي يحوي على listen، وسنقوم بإعلام Nginx أيّ نطاق سيرتبط مع ملف الإعدادات. سنستبدل الاسم الافتراضي localhost الذي يعني بأن ملف الإعدادات مسؤول عن جميع الطلبات الواردة، وسنضع مكانه اسم النطاق الحقيقي، كـ example.com على سبيل المثال: server_name example.com; سنقوم الآن بحفظ التغييرات بالضغط على CTRL+O ومن ثم نضغط CTRL+X للخروج من محرر nano. الخطوة الرابعة: إضافة المسار إلى شهادات SSL الأمنية سنقوم بإعداد Nginx الآن ليستخدم الشهادات الأمنية اللازمة لـ HTTPS، وإن لم تكن تعلم ما هي الشهادة الأمنية أو لم تكن تملك واحدة فيرجى مراجعة المقالات المذكورة في قسم المتطلبّات الأولية في بداية المقال. لنقم أولًا بإنشاء مجلّد لحفظ الشهادات الأمنية فيه داخل مجلد إعدادات Nginx: $ sudo mkdir /etc/nginx/ssl سنقوم الآن بنسخ ملف الشهادة وملف المفتاح الخاص private key إلى داخل المجلد الجديد، وبعد ذلك سنقوم بتغيير أسماء الملفات لتظهر بوضوح أي نطاق ترتبط معه (تساعد هذه الخطوة في المستقبل على توفير الوقت والجهد إن امتلكت أكثر من نطاق واحد). لا تنسى استبدال example.com باسم النطاق الخاص بك. $ sudo cp /path/to/your/certificate.crt /etc/nginx/ssl/example.com.crt $ sudo cp /path/to/your/private.key /etc/nginx/ssl/example.com.key سنقوم بإضافة سطر جديد الآن إلى ملف الإعدادات ضمن كتلة server لتعريف مسارات الشهادة الرقمية مع مفتاحها الخاص ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; الخطوة الخامسة: تحويل جميع طلبات HTTP إلى HTTPS ينبغي الآن أن نخبر Nginx بأننا نرغب بتوفير المحتوى عبر HTTPS فقط إن استلم طلب HTTP عوضًا عن ذلك. سنقوم في نهاية ملف الإعدادات بإنشاء كتلة server جديدة لتحويل جميع طلبات HTTP إلى HTTPS، ومرة أخرى لا تنس استبدال النطاق باسم النطاق الخاص بك، ستكون الكتلة الجديدة على الشكل التالي: server { listen 80; listen [::]:80; server_name example.com; return 301 https://$server_name$request_uri; } لاحظ في الكتلة السابقة كيف أنّ Nginx عند استلامه لطلبات HTTP تخص النطاق example.com عبر المنفذ 80، فإنّه سيقوم بتحويل الطلب إلى HTTPS على نفس المسار المطلوب، مستخدمّا التحويل من النمط301 (moved permanently). سيصبح شكل ملف الإعدادات (إن تجاهلنا الأسطر الخاصة بالتعليقات) على النحو التالي: server { listen 443 ssl http2 default_server; listen [::]:443 ssl http2 default_server; root /var/www/html; index index.html index.htm index.nginx-debian.html; server_name example.com; location / { try_files $uri $uri/ =404; } ssl_certificate /etc/nginx/ssl/example.com.crt; ssl_certificate_key /etc/nginx/ssl/example.com.key; ssl_dhparam /etc/nginx/ssl/dhparam.pem; } server { listen 80; listen [::]:80; server_name example.com; return 301 https://$server_name$request_uri; } سنقوم الآن بحفظ ملف الإعدادات بالضغط على CTRL+O ومن ثم الخروج من محرر nano بالضغط على CTRL+X. الخطوة السادسة: تحميل ملف الإعدادات الجديد في ذاكرة Nginx لتطبيق التغييرات التي قمنا بها، سنحتاج لإعادة تشغيل خادوم Nginx: $ sudo service nginx restart وللتحقق من أن كل شيء سار على ما يرام، سنقوم بفتح المتصفح واستعراض النطاق الذي أعددناه مع Nginx، فإن كانت الإعدادات صحيحة، يجب أن يتم تحويل الطلب إلى HTTPS بشكل تلقائي، وللتأكد مما إذا تم استخدام البروتوكول الجديد فسنقوم بفتح أدوات المطوّر (في متصفح كروم يمكن فتحها من خلال قائمة View > Developer > Developer Tools)، ومن ثم نعيد تحميل الصفحة من جديد (View > Reload This Page)، ثم من خلال لسان Network، سنضغط بالزر الأيمن للفأرة على سطر رأس الجدول ونختار Protocol. يجب الآن أن يظهر عمود جديد عنوانه Protocol ستتمكن من خلاله من رؤية أن البروتوكول المستخدم هو h2 (الذي يرمز إلى بروتوكول HTTP/2) في حال تم الإعداد بشكل صحيح. إلى هنا سيكون Nginx قد أصبح قادرًا على تخديم المحتوى باستخدام بروتوكول HTTP/2، ولكن تبقى هناك بعض الأمور التي ينبغي إعدادها قبل استخدام الخادوم في بيئة التشغيل. الخطوة السابعة: تحسين Nginx لتقديم أداء أفضل سنقوم الآن بفتح ملف الإعدادات مجدّدًا لضبط إعدادات Nginx لتقديم أفضل أداء وحماية. تفعيل Connection Credentials Caching بالمقارنة مع HTTP، فإن HTTPS يتطلب وقتًا أطول نسبيًا لإنشاء اتصال ما بين الخادوم والمستخدم، ولتقليل الفرق في سرعة تحميل الصفحة، سنقوم بتفعيل ميّزة Connection Credentials Caching وهذا يعني بأنه عوضًا عن إنشاء جلسة عمل جديدة عند طلب كل صفحة، سيقوم الخادوم باستخدام نسخة خبء cache لمعلومات المصادقة. لتفعيل الميّزة، سنقوم بإضافة السطرين التاليين إلى نهاية كتلة http في ملف الإعدادات: ssl_session_cache shared:SSL:5m; ssl_session_timeout 1h; يقوم المتغيّر ssl_session_cache بتحديد حجم الخبء الذي سيحتوي على معلومات الجلسة، حيث يمكن لـ 1MB أن يقوم بتخزين معلومات 4000 جلسة عمل، وبالتالي ستكون القيمة الافتراضية 5MB أكثر من كافية لمعظم الحالات، ولكن إن كنت تتوقع أن يكون هناك حركة مرور كثيفة على الموقع، فيمكنك زيادة القيمة وفقًا لذلك. يحدّد المتغير ssl_session_timeout من الوقت الذي تكون ضمنه جلسة العمل فعّالة داخل الخبء، ولا ينبغي أن تكون هذه القيمة كبيرة (أكثر من ساعة)، وإلى جانب ذلك فإن تخفيضها كثيرًا سيخفض من الفائدة المرجوّة أيضًا. تحسين باقات التشفير Cipher Suites باقات التشفير هي مجموعة من خوارزميات التشفير التي تصف كيف ينبغي أن يتم تشفير البيانات المنقولة. يملك بروتوكول HTTP/2 قائمة كبيرة من خوارزميات التشفير القديمة وغير الآمنة التي يجب تجنّب استخدامها. سنقوم باستخدام مجموعة تشفير معتمدة من قبل جهات عملاقة مثل CloudFlare. لا تسمح هذه المجموعات باستخدام خوارزمية MD5 في التشفير (التي تم إثبات أنها غير آمنة في عام 1996، وبالرغم من ذلك، فما تزال منتشرة حتى يومنا هذا). سنقوم بإضافة السطرين التاليين بعد ssl_session_timeout: ssl_prefer_server_ciphers on; ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; تفعيل ميزة (Strict Transport Security (HSTS على الرغم من أنّا قمنا بتحويل جميع طلبات HTTP إلى HTTPS في إعدادات Nginx، فينبغي علينا أيضًا أن نقوم بتفعيل ميّزة Strict Transport Security لتجنّب الحاجة لإخبار Nginx بعملية التحويل بأنفسنا أساسًا. عندما يصادف المتصفح ترويسة HSTS، فلن يحاول الاتصال بالخادوم عبر HTTP التقليدي مجدّدًا قبل مضي فترة من الوقت، ومهما حصل، سيعمل على تبادل البيانات عبر اتصالات HTTPS مشفّرة. تساعد هذه الترويسة على حمايتنا من هجمات تخفيض البروتوكول. كل ما نحتاجه هو إضافة السطر التالي في ملف الإعدادات: add_header Strict-Transport-Security "max-age=15768000" always; يحدّد المتغير max-age القيمة التي يجب على المتصفح خلالها ألا يحاول التواصل مع الخادوم إلا عبر بروتوكول HTTPS، وهذه القيمة ممثّلة بالثواني وبالتالي فإن القيمة 15768000 تساوي 6 أشهر. وبشكل افتراضي فإن هذه الترويسة لن يتم إضافتها إلى الطلبات الموجّهة للنطاقات الفرعية، فإن كنت تملك نطاقات فرعية وترغب أن يتم تطبيق HSTS عليها جميعًا فيجب إضافة المتغير includeSubDomains حينها إلى نهاية السطر على الشكل التالي: add_header Strict-Transport-Security "max-age=15768000; includeSubDomains: always;"; لا تنس حفظ الملف الآن بالضغط على CTRL+O ومن ثم إغلاقه بالضغط على CTRL+X إن كنت تستخدم محرر nano. الخطوة الثامنة: رفع حماية تبادل المفاتيح الأمنية إن الخطوة الأولى في إنشاء اتصال آمن هو تبادل المفاتيح الخاصة بين الخادوم والعميل، وتكمن المشكلة في هذه العملية في أنّه حتى تلك اللحظة فالاتصال غير مشفّر بينهما وبالتالي فالبيانات المتبادلة يمكن التنصّت عليها من طرف ثالث. لهذا السبب، سنحتاج لاستخدام خوارزمية Diffie-Hellman-Merkle في تبادل المفاتيح. يستخدم Nginx بشكل افتراضي مفتاح DHE) Ephemeral Diffie-Hellman) بطول 1024 بت، والذي يمكن فك تشفيره بسهولة نسبيًا، وللحصول على أمان أعلى فينبغي علينا إنشاء مفتاح DHE خاص أكثر أمنًا. للقيام بذلك سنقوم بتنفيذ الأمر التالي في سطر الأوامر: $ sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048 تنبيه: يجب أن يتم إنشاء مُعاملات DH في المجلد الذي قمنا بتخزين الشهادات الأمنية فيه، وفي المقال قمنا بتخزين الشهادات في المسار /etc/nginx/ssl/. إن السبب وراء هذا هو أن Nginx يقوم دومًا بالبحث عن مفتاح DHE الخاص بالمستخدم في مجلد الشهادات الأمنية ويستخدمه إن وُجد. تحدّد القيمة 2048 في الأمر السابق طول المفتاح الذي نرغب بإنشائه، حيث سيكون مفتاح بطول 2048 بت أكثر أمنًا وينصح به من قبل مؤسسة موزيلّا، ولكن إن كنت تسعى خلف أقصى درجة أمان، فيمكنك استخدام مفتاح بطول 4096 بت. ستأخذ عملية إنشاء المفتاح حوالي 5 دقائق، ويمكنك أثناء ذلك الاسترخاء وارتشاف بعض القهوة. لتطبيق التغييرات التي قمنا بها على ملف الإعدادات، لا تنسى أن تقوم بإيقاف وإعادة تشغيل خادوم Nginx: $ sudo service nginx restart الخلاصة أصبح اتصال SSL الخاص بك أكثر أمنًا وقابلًا للاستخدام لنقل المعلومات الحساسة، ولكن إن أردت اختبار قوته الأمنية فقم بزيارة Qualys SSL Lab وبتشغيل اختبار على خادومك، حيث ينبغي أن تحصل على نتيجة A+إن كان كلّ شيء معدّ بشكل صحيح. هذا كلّ شيء، أصبح خادوم Nginx الخاص بك جاهزًا للاستخدام، وكما ترى فإن بروتوكول HTTP/2 هو حل رائع لتحسين سرعات نقل البيانات ومن السهل استخدامه كما أظهرنا في المقال. ترجمة -وبتصرّف- للمقال How To Set Up Nginx with HTTP/2 Support on Ubuntu 14.04 لصاحبه Sergey Zhukaev.
  14. تعتمد سرعة عرض صفحة ويب على حجم جميع الملفات المرتبطة بالصفحة والتي يجب تحميلها من قبل المتصفح، وبالتالي فتخفيف حجم الملفات المطلوبة يمكن أن يسرّع من عرض صفحة الويب، ويوفّر الكثير من المال على الأشخاص الذين يدفعون مقابل عرض الحزمة bandwidth المستهلكة. يعدّ gzip من البرامج المشهورة المستخدمة في ضغط البيانات، وبالإمكان إعداد خادوم Nginx لاستخدام gzip لضغط الملفات التي يتم تخديمها من قبل الخادوم قبل إرسالها للمتصفحات والتي ستقوم بدورها بفك الضغط عن الملفّات (تدعم جميع المتصفحات المشهورة فك ضغط gzip ويفترض أن تدعم -معظم- المتصفحات عمومًا هذه العملية) دون أي خسارة في دقة البيانات بعد فك الضغط، مستفيدة بذلك من تخفيف حجم البيانات المتبادلة ما بين خادوم الويب والمتصفح. ونظرًا لاختلاف الطرق التي تعمل بها خوارزميات الضغط عمومًا، وآلية عمل خوارزمية gzip خصوصًا، فإنّ بعض الملفات يمكن ضغطها بنسبة أكبر من بعضها الآخر. فعلى سبيل المثال، يتم ضغط الملفات النصيّة text بصورة جيّدة جدًا حيث قد تكون نتيجة الضغط أصغر بحوالي مرّتين من الحجم الأصلي. ومن ناحية أخرى، فالصور من نوع JPEG و PNG تأتي مضغوطة سلفًا بطبيعة الخوارزمية المنتجة لها وبالتالي لن نحصل على الكثير من الفائدة بعد تطبيق ضغط gzip عليها، وعلى اعتبار أن ضغط الملفّات يستهلك الكثير من مصادر الخادوم، فمن الأفضل أن يتم ضغط الملفّات التي تملك نسبة ضغط عالية. سنناقش في المقال كيفية إعداد خادوم Nginx المثبت على نظام تشغيل Ubuntu 14.04 ليستخدم gzip في الضغط لتخفيف حجم المحتوى المرسل إلى متصفّحي الموقع. المتطلبات الأولية نحتاج الأمور التالية قبل المتابعة: نظام تشغيل Ubuntu 14.04، مستخدم عادي بدون صلاحيات مدير نظام، لكنّه يملك صلاحية تنفيذ أمر sudo، يمكن مراجعة الإعداد الابتدائي لخادوم أوبونتو 14.04 لمزيد من المعلومات، نسخة Nginx مثبّته على النظام، ويمكنك اتباع هذا المقال لتثبيت Nginx للقيام بذلك. الخطوة الأولى: إنشاء ملفات تجريبية سنقوم في هذه الخطوة بإنشاء عدّة ملفات تجريبية في الجذر الافتراضي للمواقع المدارة من Nginx لاختبار ضغط gzip. ولتحديد الملف الذي سيتم تخديمه عبر الشبكة، يكتفي Nginx بالاعتماد على لاحقة الملف لتحديد نمط MIME الخاص به، عوضًا عن القيام بقراءة ترويسته وذلك بغية تنفيذ العملية بأسرع وقت ممكن. ونتيجة لهذا التصرّف فإن محتوى الملف لا يعود مهمًّا ويصبح من الممكن خداع Nginx بجعله يعتقد أن ملفًا فارغًا عبارة عن صورة، وملفًا آخر عبارة عن مستند css. في إعداداتنا التالية، لن يقوم Nginx بضغط الملفّات الصغيرة جدًا، لذا سنقوم بإنشاء ملفّات تجريبية يبلغ حجمها 1 كيلوبايت تمامًا. سيسمح هذا السيناريو بالتحقق فيما إذا كان Nginx يقوم بضغط الملفات التي من المفترض به القيام بضغطها. لنقم بإنشاء ملف بحجم 1 كيلوبايت وتسميته test.html في الجذر الرئيسي الافتراضي للمواقع المدارة من Nginx وذلك باستخدام أمر truncate عبر سطر الأوامر، كما في المثال التالي: $ sudo truncate -s 1k /usr/share/nginx/html/test.html لنقم بإنشاء المزيد من الملفّات التجريبية بنفس الطريقة: ملف صورة jpg، ملف css، وملف js. $ sudo truncate -s 1k /usr/share/nginx/html/test.jpg $ sudo truncate -s 1k /usr/share/nginx/html/test.css $ sudo truncate -s 1k /usr/share/nginx/html/test.js الخطوة الثانية: التحقق من التصرّف الافتراضي لـ Nginx سنقوم الآن بالتحقق من كيفية تصرّف Nginx عند ضغط الملفات التي قمنا بإنشائها توًّا. لنتحقق مما إذا سيتم تخديم ملف test.html بعد الضغط، سنقوم في الأمر التالي بطلب الملف من خادوم Nginx، ونخبره بأنّه لا مشكلة لدينا في الحصول على محتوى مضغوط باستخدام gzip وذلك بتمرير ترويسة HTTP مناسبة (Accept-Encoding: gzip). $ curl -H "Accept-Encoding: gzip" -I http://localhost/test.html سنحصل في جواب الخادوم على ما يشبه النص التالي: HTTP/1.1 200 OK Server: nginx/1.4.6 (Ubuntu) Date: Tue, 19 Jan 2016 20:04:12 GMT Content-Type: text/html Last-Modified: Tue, 04 Mar 2014 11:46:45 GMT Connection: keep-alive Content-Encoding: gzip ويمكن في السطر الأخير ملاحظة وجود ترويسة (Content-Encoding: gzip) والتي تخبرنا بأن المحتوى الذي حصلنا عليه قد تم ضغطه باستخدام gzip، ولكن كيف حصل ذلك دون أن نقوم بتفعيل gzip أولًا في Nginx؟ إنّ السبب خلف هذا هو أن الضغط باستخدام gzip مفعّل بشكل تلقائي في نسخة Nginx على نظام Ubuntu 14.04 بإعداداته الافتراضية. على الرغم من ذلك، فإن Nginx لن يقوم إلا بضغط ملفات HTML فقط، بينما يتم تخديم باقي أنواع الملفّات بدون ضغط، ويمكن التحقق من ذلك بطلب صورة بنفس الطريقة السابقة: $ curl -H "Accept-Encoding: gzip" -I http://localhost/test.jpg وسنحصل على رد مختلف قليلًا عن السابق: HTTP/1.1 200 OK Server: nginx/1.4.6 (Ubuntu) Date: Tue, 19 Jan 2016 20:10:34 GMT Content-Type: image/jpeg Content-Length: 0 Last-Modified: Tue, 19 Jan 2016 20:06:22 GMT Connection: keep-alive ETag: "569e973e-0" Accept-Ranges: bytes حيث نلاحظ عدم وجود ترويسة (Content-Encoding: gzip) وهذا يعني أن الملف تم إرساله لنا بدون ضغط. يمكن تنفيذ الاختبار ذاته مجدّدًا مع ملف test.css ومرّة أخرى سنحصل على الملف بدون ضغط. HTTP/1.1 200 OK Server: nginx/1.4.6 (Ubuntu) Date: Tue, 19 Jan 2016 20:20:33 GMT Content-Type: text/css Content-Length: 0 Last-Modified: Tue, 19 Jan 2016 20:20:33 GMT Connection: keep-alive ETag: "569e9a91-0" Accept-Ranges: bytes الخطوة الثالثة: تغيير إعدادات ضغط gzip في خادوم Nginx سنقوم الآن بتغيّير إعدادات Nginx ليتم ضغط ملفّات من أنواع أخرى عدا عن HTML، والتي من الممكن الاستفادة من نسبة الضغط المطبّقة عليها. سنقوم بفتح ملف إعدادات Nginx باستخدام محرر nano أو أي محرر آخر تفضّل استخدامه: $ sudo nano /etc/nginx/nginx.conf ومن ثم سنبحث عن كتلة إعدادات gzip التي ستبدو كما يلي: . . . ## # `gzip` Settings # # gzip on; gzip_disable "msie6"; # gzip_vary on; # gzip_proxied any; # gzip_comp_level 6; # gzip_buffers 16 8k; # gzip_http_version 1.1; # gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; . . . نلاحظ في الإعدادات السابقة أن الضغط بواسطة gzip مفعّل بشكل افتراضي بواسطة توجيه gzip on، بينما معظم الإعدادات الإضافية تم تعطيلها بإشارة التعليقات # في بداية السطر. سنقوم بإجراء بعض التعديلات على هذه الإعدادات مثل: تفعيل الإعدادات الإضافية من خلال حذف إشارة التعليقات # في بداية الأسطر، إضافة توجيه gzip_min_length 256; الذي يخبر Nginx ألّا يقوم بضغط الملفات التي يصغر حجمها عن 256 بايت، فهذا الحجم الصغير جدًا لن يحقق الفائدة المرجوّة بعد الضغط، ▪ إضافة توجيه gzip_types مع المزيد من أنماط الملفّات كخطوط الويب، الأيقونات والصور من نوع SVG. بعد إجراء التعديلات المذكورة سيبدو مقطع الإعدادات الجديد على النحو التالي: . . . ## # `gzip` Settings # # gzip on; gzip_disable "msie6"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_min_length 256; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon; . . . قم بحفظ الملف وإغلاقه وتطبيق التعديلات من خلال إعادة تشغيل خادوم Nginx باستخدام الأمر: $ sudo service nginx restart الخطوة الرابعة: التحقق من الإعدادات الجديدة سنقوم الآن بالتحقق من أنّ الإعدادات التي قمنا بتغييرها وإضافتها تعمل على النحو المطلوب، ويمكن القيام بذلك من خلال إعادة تنفيذ الاختبارات المذكورة في الخطوة الثانية عبر استخدام أمر curl على كلّ من الملفّات التجريبية والتحقق من وجود ترويسة Content-Encoding: gzip في الخرج: $ curl -H "Accept-Encoding: gzip" -I http://localhost/test.html $ curl -H "Accept-Encoding: gzip" -I http://localhost/test.jpg $ curl -H "Accept-Encoding: gzip" -I http://localhost/test.css $ curl -H "Accept-Encoding: gzip" -I http://localhost/test.js من المفترض الآن أن تكون جميع الملفّات مضغوطة وتظهر ترويسة Content-Encoding: gzip في الخرج، عدا ملف الصورة test.jpg، وتكون الإعدادات المطبّقة صحيحة والاختبار ناجحًا إن تحقق هذا. الخلاصة إن تغيّير إعدادات Nginx لاستخدام ضغط gzip عملية سهلة جدًا لكن الفوائد المحقّقة ستكون كبيرة، فستوفّر الكثير على الزوّار الذين يملكون اتصالات محدودة بعرض الحزمة، وبالإضافة إلى ذلك ستحصل على تقييم أفضل في محرّكات البحث مثل Google من خلال تحقيق سرعة عرض أعلى للصفحة، حيث أن عامل سرعة عرض الصفحة بدأ يأخذ حيّزًا مهمًا من عملية التقييم في المواقع الحديثة وخوارزمية الضغط gzip هي خطوة كبيرة باتجاه تحسين النتيجة. ترجمة -وبتصرّف- للمقال How To Add the gzip Module to Nginx on Ubuntu 14.04 لصاحبه Mateusz Papiernik.
  15. من المعروف أن حزمة LEMP (والتي هي اختصار لـ Linux, Nginx, MySQL, PHP) توفر سرعة وموثوقية عالية لتشغيل مواقع PHP، إلّا أنها تملك مزايا أخرى غير مشهورة كالأمن والعزل. في هذا المثال، سنعرض لك مزايا أمن وعزل المواقع على LEMP مع مستخدمين مُختلفين، وهذا عن طريق إنشاء أحواض pools خاصّة بـ php-fpm لكل جزء من خادوم nginx (سواء كان موقعًا أو مستضيفًا افتراضيًا virtual host). المتطلبات الأساسية تمت تجربة هذا الدرس على أوبنتو 14.04 وعلى الرغم من ذلك فإن طريقة التثبيت والإعداد ستكون مشابهة لها على بقية الأنظمة والإصدارات، لكن قد تختلف الأوامر وأماكن ملفات الإعداد بين الأنظمة. كما أننا نفترض أنك قد ثبتت nginx و php-fpm، وبخلاف ذلك أنصحك بإتباع الخطوة الأولى والثالثة من هذا المقال: كيف تثبت حزم MySQL ،nginx ،Linux :LEMP وPHP على أوبنتو 14.04. يجب تنفيذ جميع الأوامر في هذا الدرس التعليمي بمستخدم غير الجذر (non-root)، وإن إحتجنا لصلاحياته فسنستخدم sudo، وإذا لم تُعدّ بعد هذا المستخدم فأنصحك بإتباع هذا الدرس: الإعداد الابتدائي لخادوم أوبنتو 14.04. ستحتاج أيضا إلى اسم نطاق مؤهل بالكامل (fully qualified domain name (fqdn الذي يربط على خادوم أو خادوم للتجربة بالإضافة إلى localhost الافتراضي، وإذا لم يكن لديك واحد، يمكنك استخدام site1.example.org، وذلك عن طريق تعديل ملف etc/hosts/ باستخدام محررك المفضل كهذا sudo vim /etc/hosts وأضف هذا السطر (استبدل site1.example.org بـ fqdn الخاص بك إذا كنت تستخدمه): ... 127.0.0.1 site1.example.org ... أسباب لزيادة تأمين LEMP عند إعداد LEMP مشترك سيكون هنالك حوض pool php-fpm واحد فقط والذي سيشغل جميع سكربتات PHP لجميع المواقع باستخدام نفس المستخدم، وهذا يطرح مشكلتين كبيرتين: إذا تعرض تطبيق ويب على أحد أجزاء خادوم nginx -على سبيل المثال عنوان فرعي أو موقع ما- إلى خطر أو هجوم فستتعرض جميع مواقع الموجودة على هذا الخادوم أيضا، فالمهاجم سيتمكن من قراءة ملفات الإعداد (configuration files) بما في ذلك تفاصيل قواعد بيانات لمواقع أخرى أو حتى تغيير ملفاتها. إذا أردت إعطاء مستخدم صلاحيات للدخول إلى الخادوم الخاص بك، فسوف تعطيه صلاحيات الوصول إلى جميع المواقع، فعلى سبيل المثال، إذا كان مطورك يحتاج إلى العمل على بيئة الإدراج (staging environment)، فحتى مع صلاحيات صارمة جدا على الملفات، فستبقى له إمكانية وصوله إلى جميع المواقع بما في ذلك موقعك الرئيسي على نفس الخادوم. المشاكل أعلاه تم حلها في php-fpm بإنشاء أحواض مختلفة والتي تشتغل تحت مستخدم مختلف لكل موقع. الخطوة الأولى - إعداد php-fpm إذا غطيت المتطلبات الأساسية فسيكون لديك في الوقت الحالي موقع ويب يعمل على خادوم. سننشئ الآن موقعًا ثانيًا (site1.example.org) مع حوض php-fpm ومستخدم لينكس مخصصين له. لنبدأ بإنشاء المستخدم الضروري، ولأفضل عملية فصل يجب أن يحصل المستخدم الجديد على مجموعته الخاصة لذلك سننشئ أولا مجموعة المستخدم site1: sudo groupadd site1 وبعد ذلك سننشئ مستخدم site1 ينتمي إلى هذه المجموعة: sudo useradd -g site1 site1 حتى الآن لا يملك هذا المستخدم الجديد كلمة مرور ولا يمكنك تسجيل دخوله في خادوم، إذا أردت توفير صلاحيات وصول إلى هذه الملفات من الموقع لشخص معين، فيجب عليك في هذه الحالة إنشاء كلمة مرور لهذا المستخدم عن طريق الأمر: sudo passwd site1 ومع تركيبة اسم المستخدم/كلمة المرور سيتمكن المستخدم من تسجيل دخوله عن بعد باستخدام ssh أو sftp. بعد ذلك، أنشئ حوض php-fpm جديد لـ site1، فالحوض مهم للغاية وهو عبارة عن عملية (process) لينكس عادية والتي تعمل تحت مستخدم/مجموعة محددة وتستمع لـ Linux socket وقد تستمع أيضا لتركيبة IP:Port لكن سيتطلب هذا إلى المزيد من موارد الخادوم وهذه الطريقة ليست جيدة. بشكل افتراضي في نظام أبنتو 14.04، كل حوض php-fpm يجب أن يتم إعداده في ملف داخل مجلد etc/php5/fpm/pool.d/. كل ملف مع امتداد conf. في هذا المجلد سيتم تحميله تلقائيا في الإعداد العام لـ php-fpm. لذلك سننشئ ملف etc/php5/fpm/pool.d/site1.conf/ لموقعنا، يمكنك فعل ذلك مع محررك المفضل كالتالي: sudo vim /etc/php5/fpm/pool.d/site1.conf يجب أن يحتوي هذا الملف على: [site1] user = site1 group = site1 listen = /var/run/php5-fpm-site1.sock listen.owner = www-data listen.group = www-data php_admin_value[disable_functions] = exec,passthru,shell_exec,system php_admin_flag[allow_url_fopen] = off pm = dynamic pm.max_children = 5 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 3 chdir = / في الإعدادات أعلاه، لاحظ هذه الخيارات: إن [site1] هو اسم الحوض، فلكل حوض اسم خاص به. يشير كل من user و group إلى المستخدم المجموعة التي سيعمل عليها الحوض الجديد. ستشير listen إلى مكان خاص لكل حوض. إن كل من listen.owner و listen.group يعرّفان ملكية المستمع (listener) -على سبيل المثال socket الخاصة بحوض php-fpm الجديد- ويجب على Nginx أن يكون قادرا على قراءة هذا socket، وهذا هو سبب أن socket يُنشأ مع اسم المستخدم والمجموعة تحت nginx الذي يشغل www-data. يسمح لك php_admin_value بوضع قيم إعداد php مخصصة والتي سنستخدمها لتعطيل دوال التي تُشغّل أوامر لينكس مثل exec, passthru, shell_exec, system. إن php_admin_flag مشابه لـ php_admin_value لكنه مجرد مبدل لقيم المنطقية مثل on و off. سنعطل دالة PHP التي تدعى allow_url_fopen والتي تسمح لسكربت PHP بفتح ملفات عن بعد والتي يمكن أن تُستخدم بواسطة المهاجم. ملاحظة: إن قيم php_admin_value و php_admin_flag يمكن تطبيقها بشكل عام، وعلى الرغم من ذلك قد يحتاجهما الموقع وهذا هو سبب عدم إعدادهما بشكل افتراضي. إن من مميزات أحواض php-fpm أنها تسمح لك بتخصيص إعدادات أمن لكل موقع، وعلاوة على ذلك، فيمكنك استخدام هذه الخيارات لأي إعدادات php أخرى، خارج المجال الأمني، لتخصيص بيئة الموقع. لن نتحدث في درسنا حول الأمن عن خيارات pm، لكن يجب أن تعرف أنها تسمح لك بإعداد أداء الحوض. وبالنسبة إلى خيار chdir فيجب أن يكون / والذي يعبر عن جذر نظام الملفات، وهذا السطر لا يجب تغييره ما لم تكن تستخدم chroot. لم يتم تضمين خيار chroot في الإعدادات أعلاه لأنه سيسمح لك بتشغيل الحوض في بيئة مسجونة، مثل قفل المجلد، وهذا الأمر سيكون رائعًا لأغراض أمنية لأنه ستتمكن من قفل الحوض دخل مجلد الجذر للموقع، ولكن على الرغم من ذلك فإن هذا الخيار الأمني قد يتسبب بالعديد من المشاكل لأي تطبيق PHP يعتمد على تطبيقات النظام (system binaries) وتطبيقات مثل Imagemagick والتي لن تكون متوفرة. بمجرد انتهائك من الإعدادات أعلاه أعد تشغيل php-fpm لتفعيل الخيارات الجديدة وذلك عن طريق الأمر: sudo service php5-fpm restart تأكد من أن الحوض يعمل بشكل صحيح وذلك بواسطة البحث عن عملياته كالتالي: ps aux |grep site1 إذا اتبعت التعليمات بدقة فستحصل على مخرجات مشابهة لهذه: site1 14042 0.0 0.8 133620 4208 ? S 14:45 0:00 php-fpm: pool site1 site1 14043 0.0 1.1 133760 5892 ? S 14:45 0:00 php-fpm: pool site1 بالإضافة إلى ذلك، سنعطل التخزين المؤقت الذي يوفره opcache، فهذا الأخير قد يُحسّن الأداء لكنه قد يتسبب في مشاكل أمنية. لتعطيله، عدل ملف etc/php5/fpm/conf.d/05-opcache.ini/ باستخدام صلاحيات أعلى (super user) وأضف السطر التالي: opcache.enable=0 بعد ذلك أعد تشغيل php-fpm حتى تعمل الخيارات الجديدة: sudo service php5-fpm restart الخطوة الثانية - إعداد nginx بعد أن انتهينا من إعداد حوض php-fpm لموقعنا، سنقوم الآن بإعداد جزء الخادوم في nginx. ولذلك أنشئ ملفًا جديدًا وذلك باستخدام محررك المفضل كالتالي: sudo vim /etc/nginx/sites-available/site1 يجب أن يحتوي هذا الملف على: server { listen 80; root /usr/share/nginx/sites/site1; index index.php index.html index.htm; server_name site1.example.org; location / { try_files $uri $uri/ =404; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php5-fpm-site1.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } الشيفرة أعلاه تظهر إعدادات مشتركة لجزء الخادوم في nginx، لاحظ هذه الأجزاء: جذر الويب (Web root) هو usr/share/nginx/sites/site1/. اسم الخادوم يستخدم site1.example.org التي ذكرناها في جزء المتطلبات الأساسية من هذا الدرس. يحدد fastcgi_pass المتعامل (handler) لملفات php، يجب استخدام unix socket مختلفة لكل موقع مثل var/run/php5-fpm-site1.sock/. بعد ذلك أنشئ مجلد جذر الويب: sudo mkdir /usr/share/nginx/sites sudo mkdir /usr/share/nginx/sites/site1 لتفعيل الموقع أعلاه تحتاج إلى إنشاء رابط رمزي (symlink) له في مجلد /etc/nginx/sites-enabled/. يمكنك فعل ذلك باستعمال الأمر التالي: sudo ln -s /etc/nginx/sites-available/site1 /etc/nginx/sites-enabled/site1 في النهاية، أعد تشغيل nginx لتعمل التغييرات الجديدة كالتالي: sudo service nginx restart الخطوة الثالثة - التجارب للتجارب، سنستخدم دالة phpinfo والتي توفر لنا معلومات تفصيلية حول بيئة php. أنشئ ملفًا جديدًا باسم info.php والذي يحتوي على سطر واحد فقط: <?php phpinfo(); ?> ستحتاج هذا الملف في الموقع الافتراضي لـ nginx وفي جذر الويب /usr/share/nginx/html/، ولهذا الغرض يمكنك استخدام محرر النّصوص كالتالي: sudo vim /usr/share/nginx/html/info.php ثم انسخ الملف إلى جذر الويب للموقع الآخر (site1.example.org) كالتالي: sudo cp /usr/share/nginx/html/info.php /usr/share/nginx/sites/site1/ أنت الآن مستعد لتشغيل أبسط اختبار للتأكد من مستخدم الخادوم، يمكنك إجراء الاختبار عن طريق متصفح أو من خلال طرفية خادوم و lynx (متصفح يعمل عبر الطرفية)، وإذا لم تثبت lynx سابقا في خادوم فيمكنك تثبيته بكل سهولة عن طريق الأمر: sudo apt-get install lynx تأكد أولا من وجود ملف info.php في الموقع الافتراضي، ينبغي أن تتمكن من الوصول إليه عبر localhost كالتالي: lynx --dump http://localhost/info.php |grep 'SERVER\["USER"\]' في الأمر السابق نرشح المخرجات باستخدام grep لمتغير ["SERVER["USER فقط والذي يشير إلى مستخدم الخادوم، بالنسبة إلى الموقع الافتراضي يفترض أن تكون المخرجات تعرض مستخدم www-data الافتراضي كالتالي: _SERVER["USER"] www-data ونفس الشيء سنفعله للتأكد من مستخدم خادوم site1.example.org: lynx --dump http://site1.example.org/info.php |grep 'SERVER\["USER"\]' يجب أن ترى هذه المرة site1 في المخرجات: _SERVER["USER"] site1 إذا قمت بعمل أية تخصيصات في إعدادات php في أحواض php-fpm الأساسية، فيمكنك أيضا التأكد من قيمهما بنفس الطريقة السابقة وذلك عن طريق ترشيح المخرجات التي تهمك. حتى الآن، عرفنا أن موقعينا يعملان تحت مستخدمين مختلفين، لكن لنرى الآن كيف يمكننا تأمين الاتصال، لتفسير المشكلة الأمنية التي نريد حلها في هذا المقال، سننشئ ملفًا يحتوي على معلومات حساسة، في العادة يحتوي هذا الملف معلومات الاتصال بقاعدة البيانات ويحتوي على تفاصيل اسم المستخدم وكلمة المرور لقاعدة بيانات المستخدم، فإذا وُجد أن أحدهم يستطيع الوصول إلى هذه المعلومات فسيتمكن من فعل أي شيء لموقعنا. أنشئ باستخدام محررك المفضل ملفًا جديدًا في موقعك الرئيسي يدعىusr/share/nginx/html/config.php/ ويحتوي على التالي: <?php $pass = 'secret'; ?> في الملف أعلاه عرّفنا متغيرًا يدعى pass والذي يحتوي على قيمة secret، وطبعا نريد تقييد الوصول إلى هذا الملف لذلك سنغير الصلاحيات إلى 400، والتي تعطي صلاحيات القراءة فقط لمالك الملف. لتغيير الصلاحيات إلى 400 نفذ الأمر التالي: sudo chmod 400 /usr/share/nginx/html/config.php بالإضافة إلى ذلك موقعنا الرئيسي يعمل تحت مستخدم www-data والذي يجب أن يكون قادرًا على قراءة هذا الملف، وبالتالي، غيّر ملكية الملف إلى ذاك المستخدم كالتالي: sudo chown www-data:www-data /usr/share/nginx/html/config.php في مثالنا سنستخدم ملفًا آخر يدعى usr/share/nginx/html/readfile.php/ لقراءة المعلومات السرية ومن ثم طباعتها، ويجب أن يحتوي هذا الملف على الشيفرة البرمجية التالية: <?php include('/usr/share/nginx/html/config.php'); print($pass); ?> بعد ذلك غيّر ملكية هذا الملف لمستخدم www-data كالتالي: sudo chown www-data:www-data /usr/share/nginx/html/readfile.php للتأكد من جميع الصلاحيات والملكيات في جذر ويب، نفّذ الأمر التالي: ls -l /usr/share/nginx/html/ يجب أن تكون المخرجات شبيهة بهذه: -r-------- 1 www-data www-data 27 Jun 19 05:35 config.php -rw-r--r-- 1 www-data www-data 68 Jun 21 16:31 readfile.php الآن جرب الوصول إلى الملف السّابق على موقعك الافتراضي باستخدام الأمر: lynx --dump http://localhost/readfile.php ستلاحظ أن secret مطبوعة على الشاشة والتي تعني أن الملف مع المعلومات الحساسة يمكن الوصول إليه من داخل نفس الموقع، وهذا السلوك متوقع. الآن جرب نسخ ملف usr/share/nginx/html/readfile.php/ إلى موقعك الثاني site1.example.org كالتالي: sudo cp /usr/share/nginx/html/readfile.php /usr/share/nginx/sites/site1/ للحفاظ على علاقات الموقع/المستخدم، تأكد من أن الملفات داخل كل موقع مملوكة من طرف المستخدم المعني وذلك عن طريق تغيير ملكية الملف المنسوخ إلى site1 باستخدام الأمر التالي: sudo chown site1:site1 /usr/share/nginx/sites/site1/readfile.php للتحقق من وضعك الصلاحيات والملكيات الصحيحة للملفات، اعرض قائمة محتويات جذر ويب site1 باستخدام الأمر: ls -l /usr/share/nginx/sites/site1/ يجب أن ترى كالتالي: -rw-r--r-- 1 site1 site1 80 Jun 21 16:44 readfile.php بعد ذلك حاول الوصول إلى نفس الملف من site1.example.com باستخدام الأمر: lynx --dump http://site1.example.org/readfile.php سترى أنه تم إرجاع مساحة فارغة، وبالإضافة إلى ذلك، إذا بحثت عن الأخطاء في سجل الأخطاء لـ nginx باستخدام الأمر grep التالي: sudo grep error /var/log/nginx/error.log فسترى شيئا مشابها لهذا: 2015/06/30 15:15:13 [error] 894#0: *242 FastCGI sent in stderr: "PHP message: PHP Warning: include(/usr/share/nginx/html/config.php): failed to open stream: Permission denied in /usr/share/nginx/sites/site1/readfile.php on line 2 ملاحظة: سترى أيضا خطأ مشابهًا في مخرجات lynx إذا فعّلت خيار display_errors في إعدادات php-fpm في ملف etc/php5/fpm/php.ini/ (بوضع On في ذلك الخيار). يظهر التحذير أن السكربت من موقع site1.example.org لا يمكنه قراءة الملف الحساس (config.php) من الموقع الرئيسي وبالتالي، المواقع التي تعمل تحت عدة مستخدمين لا يمكنها تعريض أمن بقية المواقع. إذا ذهبت إلى نهاية جزء الإعدادات من هذا المقال، سترى أننا عطلنا التخزين المؤقت التي يوفرها opcache بشكل افتراضي، وإذا رغبت بمعرفة السبب حاول تفعيله مجددا وذلك عن طريق وضع opcache.enable=1 في ملفetc/php5/fpm/conf.d/05-opcache.ini/ عن طريق مستخدم sudo ومن ثم إعادة تشغيل php5-fpm باستخدام الأمر sudo service php5-fpm restart. ستجد أنه إذا قمت بإعادة خطوات الاختبار بنفس الترتيب فإنك ستتمكن من قراءة الملف الحساس على الرغم من صلاحياته وملكياته، وهذه المشكلة في opcache قد تم الإبلاغ عنها منذ فترة طويلة لكن لم يتم إصلاحها حتى وقت كتابة هذا المقال. الخاتمة من الناحية الأمنية، يجب استخدام أحواض php-fpm مع مستخدم مختلف لكل موقع على نفس خادوم ويب nginx، فهذا الأمر حتى لو كان يضْعف الأداء قليلا، فإن ميزة عملية الفصل يمكنها منع خروق أمنية خطيرة. الفكرة التي شرحناها في هذا المقال ليست فريدة، وهي موجودة في تقنيات فصل PHP أخرى مثل SuPHP. وعلى الرغم من ذلك، أداء بقية البدائل أسوء من php-fpm. ترجمة -وبتصرف- للمقال: How To Host Multiple Websites Securely With Nginx And Php-fpm On Ubuntu 14.04 لصاحبه Anatoliy Dimitrov.
  16. Nginx عبارة عن مشروع مفتوح المصدر، له استخدامات مُختلفة قد يكون أهمها هو استخدامه كخادوم ويب. يُمكن اعتبار Nginx كمنافس قوي لخادوم apache رغم قُوة هذا الأخير. إليكم دليلا سريعا حول كيفية تنصيبه، إعداده واستخدامه كخادوم ويب محلي. سأستعرض آلية تنصيب وإعداد nginx على نظام لينكس (توزيعة Archlinux) ويُمكنك تغيير مسارات الملفات لتتوافق مع مسارات الملفات على توزيعتك المُفضلة للوصول إلى نفس النتيجة. بداية سنحتاج أولا إلى تنصيب nginx عبر الأمر التالي (وفي حال ما إذا كانت مشاريعك مكتوبة بلغة php فإنك ستحتاج أيضا إلى تنصيب php-fpm): sudo pacman -S nginx php-fpm على توزيعة ubuntu سيكون أمر التنصيب هو: sudo apt-get install nginx php5-fpm بعد الفراغ من التنصيب سنقوم بتفعيل الخادوم (وphp-fpm) وتشغيله بالأمرين التاليين: sudo systemctl enable nginx php-fpm sudo systemctl start nginx php-fpm بعد قيامك بذلك ولو استعرضت عنوان localhost فستظهر لك صفحة تؤكد لك بأنه تم تنصيب الخادوم وتشغيله بنجاح. الآن وبحكم أنك ستعمل على أكثر من مشروع ويب في آن واحد على جهازك المحلي سنقوم بإعداد الخادوم لتمكيننا من ذلك. لنبدأ أولا بإلقاء نظرة على ملف nginx.conf الذي يتحكم في الخادوم. ستلاحظ الشفرة التالية المسؤولة عن إظهار صفحة البداية آنفة الذكر server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { root /usr/share/nginx/html; index index.html index.htm; } وكل ما نحتاجه هو إنشاء خادوم server جديد لكل مشروع تود العمل عليه، لكن ولإبقاء هذا الملف "نظيفا" ولتجنب حصول أية مشاكل بسبب تعديل غير مرغوب فيه سنقوم بإنشاء ملف مُنفصل لكل مشروع جديد. اذهب إلى المُجلد الذي تم تنصيب nginx فيه (/etc/nginx/ ) وقم بإنشاء مُجلدي sites-available وsites-enabled إن لم يكونا موجودين من قبل. لماذا سنحتاج إلى مُجلدين؟ سنضع في الأول المواقع (المشاريع) التي نعمل عليها و"سنضع" في الثاني المواقع (المشاريع) التي نود أن نقوم بتنفيذها. صحيح أن هذه الخُطوة قليلة أو ربما عديمة الفائدة على خادوم محلي، لكن من الأفضل أن تعود نفسك على ذلك قبل أن تقوم برفع مواقعك إلى خادوم فعلي. سنقوم بإنشاء ملف إعدادات لكل مشروع جديد داخل مُجلد site-available ولنسمي كل ملف باسم المشروع متبوعا بـ .dev (يُمكنك تجاهل هذه اللاحقة إن أردت أو استخدام أي لاحقة أخرى) بعبارة أخرى لو كان المشروع الأول الذي نود أن نقوم بتشغيله عبر nginx هو myproject فسيكون اسم الملف هو myproject.dev إليكم مثالا عن إعدادات phpmyadmin (بطبيعة الحال ستحتاج إلى تنصيبه أولا قبل أن تقوم بذلك): server { listen 80; server_name phpmyadmin.dev; location / { root /usr/share/webapps/phpMyAdmin; index index.html index.htm index.php; try_files $uri $uri/ /index.php$is_args$args; autoindex on; } location ~ \.php$ { root /usr/share/webapps/phpMyAdmin; fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } في حال ما إذا كان مشروعك داخل مُجلد آخر فيكفي أن تغير قيمة root. لو كان مشروعك متواجدا داخل /srv/http/myproject فيكفي أن تغيير root لتصبح root /usr/share/webapps/myproject; ستحتاج أيضا إلى تغيير قيمة fastcgi_pass لتتوافق مع مسار php-fpm على نظامك، فلو كنت على توزيعة ubuntu مثلا فسيكون المسار unix:/var/run/php5-fpm.sock; بطبيعة الحال يُمكنك إضافة، تعديل أو إزالة أية إعدادات أخرى حسب الحاجة كتفعيل أو تعديل مسار صفحة الخطأ error_page 404 أو تعطيل خاصية autoindex on; التي تسمح باستظهار مُحتوى المُجلدات التي لا تحتوي على ملفات index. الآن وبعد أن أنشأنا على الأقل ملفي إعدادات (واحد للمشروع myproject وآخر لسكربت phpMyAdmin) سنحتاج أن نقوم بنقلهما إلى مُجلد sites-enabled، لكن لن نقوم بنسخهما بل يكفي أن نقوم بإنشاء رابط وهمي. بعبارة أخرى سنقوم بإنشاء رابط وهمي من مُجلد sites-enabled إلى ملفات الإعدادات الموجودة في مجلد sites-available وذلك على النحو التالي: sudo ln -s /etc/nginx/sites-available/myproject.dev /etc/nginx/sites-enabled/myproject.dev sudo ln -s /etc/nginx/sites-available/phpmyadmin.dev /etc/nginx/sites-enabled/phpmyadmin.dev بقيت خُطوة أخيرة، وبحكم أننا سنتحكم في جميع مشاريعنا عبر ملفات فردية فإننا لن نحتاج بعد الآن إلى الإعدادات الموجودة في ملف nginx.conf. هذا من جهة، ومن جهة أخرى سنحتاج إلى تضمين هذه الملفات الفردية في الملف الرئيسي عبر الأمر: include sites-enabled/*; ليصبح الملف على النحو التالي: #user html; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; include sites-enabled/*; } الآن وبعد أن أنهينا إعداد ملفات الخواديم، سنحتاج إلى إعادة تشغيل nginx ليأخذ التغييرات في الحسبان عبر الأمر sudo systemctl restart nginx لكن كيف سنقوم باستعراض المشاريع على المُتصفح؟ بقيت خطوة أخيرة (ألم تقل في الخطوة السابقة أنها الخطوة الأخيرة؟؟:P) سنحتاج إلى تعديل ملف /etc/hosts وإضافة سطر لكل مشروع على النحو التالي: 127.0.0.1 myproject.dev localhost 127.0.0.1 phpmyadmin.dev localhost الآن يكفي أن أكتب في خانة العناوين العنوان phpmyadmin.dev أو myproject.dev لأتمكن من استعراض المشروعين. ملاحظة: هذا دليل سريع حول تنصيب nginx والشروع في استخدامه، قد تحتاج إلى إضافة إعدادات أخرى لتوافق ودعم أفضل لنظام إدارة المُحتوى الذي تعمل عليه أو للغة البرمجية المُفضّلة لديك. ملاحظة2: ستجد في الشفرات السابقة بعض الإعدادات المُعطلة (مسبوقة بمحرف #) تركت لتبيين بعض ما يُمكن إضافته للملف ابحث عن كل واحدة وفعلها حسب الحاجة.
  17. يُستخدَم Hexo، وهو إطار عمل للتدوين الثابت (Static) مبنيّ على Node.js، لنشر تدوينات مكتوبة في مستندات Markdown. تُعالَج التدوينات ثم تُحوَّل إلى HTML/CSS انطلاقا من قوالب معدَّة لهذا الغرض (تماما كما تفعل بقية مُولّدات المحتوى الثابت مثل Jekyll و Ghost). يعمل Hexo على هيئة وِحدات (Modules) يمكن ثبيتها وإعدادها حسب الحاجة. سنعدّ في هذا المقال Hexo اعتمادا على خادوم ويب Nginx ومنصة GitHub. المتطلبات في ما يلي قائمة بما ستحتاجه لإنجاز هذا الدرس: خادوم أوبنتو 14.04 مع حساب ذي صلاحيات إدارية غير المستخدم الجذر. يمكنك إعداد حساب بالمواصفات المطلوبة باتباع خطوات درس الإعداد الابتدائي لخادوم أوبنتو. تثبيت Git على خادوم أوبنتو وإعداده. يشرح درس تنصيب وإعداد Git و gitolite للتحكم في الإصدارات على أوبنتو الكيفية. تثبيت Node.js على خادوم أوبنتو. تثبيت Nginx على خادوم أوبنتو. حساب على GitHub الذي هو مستودع Git. تأكد من أن المتطلبات مثبتة ومضبوطة ثم انتقل إلى خطوات تثبيت Hexo وإعداده. الخطوة الأولى: تثبيت Hexo وبدء تشغيله تتضمن هذه الفقرة كل ما عليك فعله لتثبيت Hexo وجعله يعمل على خادومك. ابدأ أولا بتحديث الحزم: sudo apt-get update && sudo apt-get upgrade يتكوّن Hexo من الكثير من العناصر والحزم البرمجية. سنجلب اثنتين من الحزم الأكثر أهمية في Hexo باستخدام مدير الاعتمادات npm. العنصر الأول والأهم هو hexo-cli، يوفر أوامر Hexo الأساسية : npm install hexo-cli -g ثم نأتي للعنصر الثاني hexo-server وهو خادوم مضمَّن يمكن استخدامه للعرض المسبق للتدوينات واختبارها قبل النشر: npm install hexo-server -g تتوفر الكثير من الحزم الأخرى لـHexo، إلا أن الحزمتين أعلاه هما الأساس الذي لا يُستغنى عنه لإطلاق مدونة باستخدام Hexo. يمكن أن تستعرض الحزم الأخرى المكونة لإطار عمل Hexo بخاصية البحث في npm. نحتاج الآن لقاعدة ملفات لبناء مدونتنا عليها. يُوفِّر Hexo أمر init لهذا الغرض، كل ما عليك فعله هو تمرير المسار أو المجلد الذي تريد استخدامه لملفات إعداد المدونة إلى الأمر: hexo init ~/hexo_blog يستغرق اﻷمر بضع ثوان حسب سرعة الاتصال لديك: INFO Copying data to ~/hexo_blog INFO You are almost done! Don't forget to run 'npm install' before you start blogging with Hexo! . . . ننتقل إلى المجلد المستخدَم في الأمر السابق: cd ~/hexo_blog ثم ننفذ أمر التثبيت التالي: npm install يمكنك تجاهل التحذيرات الاختيارية (WARN notsup). نحصُل بعد انتهاء تنفيذ الأمر على ملفات الإعداد الأساسية. الخطوة الثانية: ضبط ملف الإعداد الأساسي في Hexo نسرُد محتويات مجلد المشروع: ls -l تظهر مخرجات على النحو التالي: -rw-rw-r-- 1 zeine77 zeine77 1483 Feb 17 15:48 _config.yml drwxrwxr-x 201 zeine77 zeine77 36864 Feb 17 15:53 node_modules -rw-rw-r-- 1 zeine77 zeine77 442 Feb 17 15:48 package.json drwxrwxr-x 2 zeine77 zeine77 4096 Feb 17 15:45 scaffolds drwxrwxr-x 3 zeine77 zeine77 4096 Feb 17 15:45 source drwxrwxr-x 3 zeine77 zeine77 4096 Feb 17 15:45 themes يعدّ الملف config.yml_ أهم هذه الملفات إذ تخزَّن به إعدادات نواة Hexo. إن احتجت مستقبلا لإجراء تعديلات على المدونة فعلى الأرجح سيكون ذلك من خلال هذا الملف. نفتح الملف لإجراء تخصيصات على البرنامج: nano _config.yml توجد في أعلى الملف فقرة معنونة بـSite (الموقع): # Site title: Hexo subtitle: description: author: John Doe language: timezone: يوجد في الأسطر الأربعة الأولى اسم المدونة، عنوان فرعي لها، وصف واسم صاحب المدونة. لديك كامل الحرية في اختيار ما يناسب لهذه الأسطر. انتبه إلى أن بعض قوالب Hexo لا تعرض كامل هذه المعلومات. يمكن اعتباره هذه الفقرة بيانات وصفية للمدونة. الخياران المواليان يمثلان اللغة والمنطقة الزمنية. تأخذ اللغة قيمة عبارة عن حرفين يرمزان للغة وفق معيار ISO-639-1. يُضبط الوقت مبدئيا على المنطقة الزمنية للخادوم ويستخدم صيغة قاعدة بيانات tz. إن قررت التعديل على إحدى المعطيين فتأكد أن القيمة وفق الصيغة المطلوبة. في ما يلي مثال على ملف الإعداد: #Site title: مدونة أكاديمية حسوب subtitle: مدونة تقنية تستخدم Hexo description: مثال على استخدام Hexo لإنشاء مدونة author: أكاديمية حسوب language: ar timezone: Africa/Nouakchott تضبط الفقرة الموالية إعدادات الروابط. يمكن استخدام عنوان IP قيمةً لمعطى url إن لم يكن لديك نطاق خاص. # URL ## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/' url: http://127.0.0.1 root: / permalink: :year/:month/:day/:title/ permalink_defaults: خيار آخر نودّ تغييره في ملف الإعداد وهو default_layout ضمن فقرة Writing إلى الأسفل قليلا. نحدد القيمة draft للمعطى. يعني هذا أن المنشورات الجديدة تُنشأ على هيئة مسودات يجب نشرها حتى تكون مرئية على المدونة. # Writing new_post_name: :title.md # File name of new posts default_layout: draft titlecase: false # Transform title into titlecase احفظ الملف ثم أغلقه. سنعود إليه لاحقا عندما نبدأ بالنشر. الخطوة الثالثة: كتابة تدوينة جديدة ونشرها تبدأ عملية نشر تدوينة (أو مسودة كما أسميناها في الإعداد أعلاه) بتنفيذ الأمر التالي، حيث أول-تدوينة هو اسم التدوينة التي تريد إنشاءها: hexo new أول-تدوينة تظهر الرسالة التالي في سطر الأوامر: INFO Created: ~/hexo_blog/source/_drafts/أول-تدوينة.md نفتح الملف لتحرير أول تدويناتنا: nano ~/hexo_blog/source/_drafts/أول-تدوينة.md يجب أن تحوي كل تدوينة على جبهة أمامية Front-matter، وهي كتلة تعليمات قصيرة مكتوبة بـJSON أو YAML لضبط إعدادات مثل عنوان التدوينة، تاريخ النشر، الوسوم Tags ومعلومات من هذا القبيل. تُعلَّم نهاية الجبهة الأمامية بعلامة --- أو ;;;. تمكن كتابة منشور المدونة بعد الجبهة الأمامية باستخدام صيغة Markdown. أبدل المحتوى المبدئي لملف "md.أول-تدوينة" بالمحتوى التالي: title: أول تدوينة في مدونة أكاديمية حسوب tags: - حسوب - مدونة categories: - إعلانات comments: true date: 2016-02-18 09:30:00 --- ## هنا تكتب تعليمات ماركداون **هذه هي تدوينتنا الأولى!** نص التدوينة الأولى احفظ الملف ثم أغلقه. سيبقى ملف ماركداون الذي أنشأناه للتو في مجلد hexo_blog/source/_drafts/~ إلى أن ننشره. كل الملفات الموجودة في هذا الملف غير مرئية لزوار المدونة. ننشر التدوينة لتتاح للزوار hexo publish first-post تظهر الرسالة التالية: INFO Published: ~/hexo_blog/source/_posts/أول-تدوينة.md سيصبح بالإمكان رؤية المنشور فور نشر المدونة. الخطوة الرابعة: تشغيل خادوم الاختبار أكملنا في الخطوات السابقة إعداد الخادوم، ونشرنا أول تدوينة. سنشغّل خادوم الاختبار لرؤية النتيجة: hexo server يمكن الآن رؤية المدونة بزيارة http://your_server_ip:4000 حيث your_server_ip عنوان IP الموقع. سيظهر لديك منشور Hello World المعرَّف مسبقا، إضافة للمنشور الذي كتبناه للتو. اضغط على الزرين CTRL+C لإيقاف خادوم الاختبار. يُستخدم خادوم الاختبار لعرض التغييرات والإضافات إلى المدونة، ثم يأتي وقت نشر المدونة على الشبكة بعد أن تنتهي من التعديلات. الخطو الخامسة: إعداد Git لنشر المدونة توجد وسائل عدة لنشر ما أعدنناه على Hexo. المقاربة المختارة في هذا الدرس هي استخدام Git لتخزين الملفات الثابتة، الخطافات Hooks لتوجيهها وNginx لتقديمها. تتيح حزم في Hexo الدعم لـ Heroku ،Rsync ،OpenShift وغيرها. سنحتاج لمستودع Git نخزّن فيه ملفات HTML التي يولّدها Hexo. سنستخدم مستودعا عموميا على GitHub لتسهيل الأمور. أنشئ مستودعا جديدا على GitHub باسم hexo_static أو أي اسم آخر تراه مناسبا، مع التأكد من أن المستودع عمومي (خيار Public). حدّد مربع Initialize this repository with a README لإضافة ملف README تلقائيا إلى المستودع. افتح ملف الإعداد الرئيسي لـHexo من أجل تحريره: nano _config.yml توجد في أسفل الملف فقرة معنونة بـDeployment: # Deployment ## Docs: https://hexo.io/docs/deployment.html deploy: type: حدّد خيارات النشر كما في المثال أدناه. يحيل رابط URL إلى المستودع الذي أنشأته للتو؛ لذا تأكد من وضع اسم حسابك في GitHub مكان your_github_username. أبدل كذلك اسم المستودع إن كنت اخترت اسما مغايرا. deploy: type: git repo: https://github.com/your_github_username/hexo_static.git branch: master احفظ الملف ثم أغلقه. بما أننا اخترنا النشر عن طريق Git فسنحتاج لحزمة Hexo التي ترسل الملفات الثابتة التي يولدها إلى مستودع Git. استخدم npm لتثبيتها: npm install hexo-deployer-git --save يمكنك الآن تجربة إرسال الملفات إلى مستودع hexo_static وإضافة أول إيداع بواسطة Hexo: hexo generate && hexo deploy أدخل معلومات الاستيثاق في GitHub عندما تطلب منك لبدء نقل الملفات. تبدو نتيجة تنفيذ الأمرين السابقين بعد نجاحه على النحو التالي: To https://github.com/username/hexo_static.git. * [new branch] master -> master Branch master set up to track remote branch master from https://github.com/username/hexo_static.git. INFO Deploy done: git الخطوة السادسة: إعداد Nginx يتميّز خادوم ويب Nginx في تقديم الملفات الثابتة للزوار، وهو ما يجعله اختيارا مناسبا لمدونتنا. نبدأ بإعداد Nginx لتقديم المدونة للزوار. ننشئ أولا مجلدات النظام التي سنطلب من Nginx استخدامها: sudo mkdir -p /var/www/hexo ثم نعطي للحساب الذي نستخدمه على أوبنتو ملكيةَ المجلد: sudo chown -R $USER:$USER /var/www/hexo نعدّل أذون المجلد على النحو التالي: sudo chmod -R 755 /var/www/hexo نفتح ملف الإعداد المبدئي لـNginx لتحريره: sudo nano /etc/nginx/sites-available/default نعدّل كلتة server في ملف الإعداد بحيث يصبح جذر المستند Document root يشير إلى المجلد الذي أنشأناه للتو: server { listen 80 default_server; listen [::]:80 default_server ipv6only=on; root /var/www/hexo; index index.html index.htm; احفظ الملف ثم أغلقه. يمكنك عند الحصول على اسم نطاق للمدونة تحرير هذا الملف وتحديد قيمة server_name بحيث تصبح اسمَ نطاقك. نعيد تشغيل Nginx لاعتماد التعديلات: sudo service nginx restart الخطوة السابعة: إنشاء خطافات Hooks في Git سنربط في هذه الخطوة مستودع hexo_static بمستودع Git آخر لنرسل عبره ملفات HTML إلى مجلد خادوم الويب. نبدأ بإنشاء مستودع Git فارغ الهدف منه توجيه محتوى المستودع hexo_static إلى مجلد خادوم الويب: git init --bare ~/hexo_bare أنشئ ملف خطاف جديدا داخل مجلد خطافات Git: nano ~/hexo_bare/hooks/post-receive أضف السطرين التاليين إلى الملف. نحدّد في الملف شجرة عمل Git التي تحوي الشفرة المصدرية ومجلد Git الذي يحوي الإعدادات، السجل وأمورا أخرى: #!/bin/bash git --work-tree=/var/www/hexo --git-dir=/home/$USER/hexo_bare checkout -f احفظ الملف ثم أغلقه. اجعل الملف post-receive قابلا للتنفيذ: chmod +x ~/hexo_bare/hooks/post-receive سنحتاج الآن لنسخ مستودع النشر hexo_static الذي أنشأناه في الخطوة الخامسة إلى الخادوم. تأكد من إبدال username في الأمر أدناه باسم حسابك في GitHub. git clone https://github.com/username/hexo_static.git ~/hexo_static انتقل إلى المجلد hexo_static: cd ~/hexo_static نضيف مستودع hexo_bare السابق على أنه مستودع بعيد باسم live: git remote add live ~/hexo_bare الخطوة الثامنة: إنشاء سكربت النشر يمكن باستخدام سكربت Shell قصير بدء كامل عملية النشر السابقة بدلا من أدائها يدويا. يعني هذا أننا لن نحتاج إلى تنفيذ أوامر Hexo الواحدة تلو الأخرى أو تشغيل خطّاف Git بأوامر متعدّدة. نعود إلى مجلد مدونة Hexo وننشء فيه ملفا للسكربت: cd ~/hexo_blog nano hexo_git_deploy.sh ألصق الشفرة التالية في الملف: #!/bin/bash hexo clean hexo generate hexo deploy ( cd ~/hexo_static ; git pull ; git push live master ) احفظ الملف ثم أغلقه. ينفذ السكربت أوامر Hexo التالية: أمر clean الذي يحذف الملفات المولَّدة سابقا من مجلد public. أمر generate الذي يولّد ملفات HTML انطلاقا من ملفات ماركداون ويضعها في مجلد public. أمر deploy الذي يُرسِل الملفات الموجودة في المجلد public إلى مستودع Git الذي عرّفناه سابقا في ملف الإعداد config.yml_. يشغّل السطر الأخير (cd ~/hexo_static ; git pull ; git push live master) خطاف Git ويحدّث مجلد المدونة على خادوم الويب بوضع ملفات HTML فيه. نجعل سكربت النشر قابلا للتنفيذ: chmod +x hexo_git_deploy.sh الخطوة التاسعة: تنفيذ سكربت النشر نفذ سكربت النشر السابق لاختبار كامل العملية: ./hexo_git_deploy.sh ستُطلب منك معلومات الاستيثاق أثناء إيداع الملفات في مستودع GitHub. انتظر اكتمال العملية ثم ألق نظرة على الملفات في المجلد var/www/hexo/: ls /var/www/hexo النتيجة: 2016 archives categories css fancybox index.html js tags تُظهر نتيجة الأمر أعلاه أن الملفات التي أنشأها Hexo نُقلت إلى مجلد خادوم الويب، يعني هذا أن بإمكانك تصفح المدونة بالذهاب إلى عنوان الخادوم http://your_server_ip/. يكفي تنفيذ السكربت hexo_git_deploy.sh مستقبلا لنشر التعديلات أو الإضافات على المدونة. تذكر أن تختبر التغييرات على خادوم Hexo الاختباري قبل نشرها. الخطوة العاشرة: اكتشاف نظام ملفات Hexo (اختيارية) يعتمد Hexo على ملفات للعمل عليها. ليس من الضروري تعديل هذه الملفات إلا أنه سيكون من الجيد معرفة دور كل واحد منها في نظام الملفات التابع لـHexo، فربما تحتاج لاستخدامه. يبدو مخطَّط الملفات والمجلدات على النحو التالي: ├── _config.yml ├── node_modules ├── package.json ├── scaffolds ├── source | └── _posts └── themes مجلد node_modules يخزّن Hexo في هذا المجلّد الوحدات التي تنزّلها بـ npm لاستخدامها في المدونة. بنهاية هذا الدرس لن توجد في هذا المجلد سوى الحزم التي نزلناها في الخطوة الأولى أو الحزم التي تأتي مضمَّنة في Hexo. على العموم لن تحتاج للتعديل على هذا المجلد. مجلد package.json يحوي ملف JSON هذا الإعدادات والإصدارات التي يستخدمها Hexo. الجأ لهذا الملف إن احتجت لتحديث الحزم يدويا، إرجاعها إلى إصدار أقدم Downgrade أو حذفها. لن تحتاج لتعديل هذا الملف على الأرجح إلا إذا حدث تعارض بين حزم Hexo وهو أمر غير شائع. مجلد scaffolds يستخدم Hexo القوالب الموجودة في هذا المجلد ليصيغ التدوينات وفقا لها. تأتي ثلاثة قوالب مبدئيا في الملف وهي draft (مسودة)، post (منشور) و page (صفحة). إن أردت استخدام قالب جديد فيجب وضعه هنا قبل الاستخدام. مجلد source توجد التدوينات المنشورة في مجلد فرعي من مجلد source، نفس الشيء ينطبق على المسودات. يوجد أغلب محتوى المدونة المكتوب بماركداون في هذا المجلد أو مجلد متفرع عنه. مجلد themes توضع قوالب المظهر Themes في هذا المجلد. تحوي أغلب القوالب على ملف config.yml_ خاص بها للاحتفاظ بإعدادات مخصّصة مثل تلك التي يعرّفها ملف الإعداد العام. استخدمنا خلال هذا الدليل القالب المبدئي في Hexo. خاتمة لم نتطرق في هذا الدرس للكثير مما يمكن تعلمه، إلا أنه يضع قاعدة متينة لإنشاء مدونة باستخدام Hexo. راجع التوثيق الرسمي لإطار العمل والذي يحوي الكثير من المعلومات الدقيقة إن أردت التعمق أكثر في البرنامج. الخطوة الموالية هي تخصيص المظهر ليناسب رغباتك في تطوير مدونة خاصة بك. ترجمة -وبتصرف- لمقال How to Create a Blog with Hexo On Ubuntu 14.04 لصاحبه C.J. Scarlett.
  18. تَعِد PHP 7، التي صدرت في 3 ديسمبر 2015، بتحسينات كبيرة في سرعتها على النُسخ السابقة من اللغة، مع مميزات جديدة مثل تلميح النوع العددي (scalar type hinting). سنشرح كيفية ترقية خادوم Apache أو Nginx يستخدم PHP 5.x (أي إصدار) إلى PHP 7. تحذير: كما هو الحال مع معظم النسخ الرئيسية لإصدارات اللغة، من الأفضل الانتظار لبعض الوقت قبل الانتقال إلى PHP 7 في بيئة الإنتاج. في غضون ذلك، يكون الوقت مناسب لاختبار توافقية تطبيقاتك مع الإصدار الجديد، إجراء مقاييس الأداء والتّعرف على الميزات الجديدة للغة. إذا كُنت تُشغل أي خدمات أو تطبيقات بمستخدمين نُشطاء، فالآمن اختبار PHP 7 في بيئة إدراج staging environment قبل تثبيتها في بيئة الإنتاج. ملحوظة: بيئة الإدراج (staging environment) هي بيئة تطوير تقع بين بيئة الاختبار وبيئة الإنتاج، تُستخدم في تجميع، اختبار واستعراض الإصدارات الجديدة من البرمجيات قبل نقلها إلى بيئة الإنتاج. المتطلبات الأساسية يُفتَرض أنك تستخدم PHP 5.x على أوبنتو 14.04، باستخدام إما mod_php بالتزامن مع Apache، أو PHP-FPM بالتزامن مع Nginx. ويُفتَرض أن لديك مُستخدم عادي غير المستخدم الجذر بصلاحيات sudo للمهام الإدارية. إضافة PPA لحزم PHP 7.0 أرشيف الحزم الشخصي، أو PPA، هو مُستودع Apt مُستضاف على Launchpad. وهذه الأرشيفات الشخصية تسمح لمطوري الطرف الثالث ببناء وتوزيع الحزم لأوبنتو خارج قنوات تطوير الحزم الرسمية. وهي مصادر مفيدة غالبًا من البرمجيات التجريبية، البنّى المُعدلة والمنقولات الخلفية backports لإصدارات النظام القديمة. ملحوظة: الحزم المنقولة خلفًا (package backports) هي حزم لبرمجيات حديثة أعيدت ترجمتها لتوزيعة قديمة (نُقلت إلى الخلف)، وعادة ما يكون النقل إلى التوزيعة المستقرة. يقوم Ondřej Surý على صيانة حزم PHP لدبيان، ويوفر أرشيف شخصي للنسخة PHP 7.0 على أوبنتو. قبل القيام بأي شيء، سجل دخولك إلى النظام، وأضف أرشيف Ondřej الشخصي إلى قائمة مصادر Apt بالنظام: $ sudo add-apt-repository ppa:ondrej/php-7.0 ستلاحظ وصف الأرشيف الشخصي، متبوعًا بمحث للاستمرار. اضغط Enter للمواصلة. ملحوظة: إذا كانت محليات نظامك مضبوطة لأي شيء غير UTF-8، فقد تفشل عملية إضافة الأرشيف الشخصي لوجود مشكلة برمجية في التعامل مع الحروف في اسم المؤلف. وكالتفاف حول المشكلة يمكنك تثبيت الحزمة language-pack-en-base لتتأكد من توليد المحليات المطلوبة، وتتجاوز إعدادات محليات النظام عند إضافة الأرشيف الشخصي: $ sudo apt-get install -y language-pack-en-base $ sudo LC_ALL=en_US.UTF-8 add-apt-repository ppa:ondrej/php-7.0 بمجرد انتهاء تثبيت الأرشيف الشخصي، حدّث ذاكرة الحزم المُخبأة لكي يتم تضمين محتويات الأرشيف: $ sudo apt-get update الآن أصبح لدينا وصول لحزم PHP 7.0، ويمكننا استبدال نسخة PHP الحالية. ترقية mod_php مع Apache هذا القسم يوضح عملية ترقية نظام يستخدم Apache كخادوم و mod_php لتنفيذ شفرة PHP. إذا كُنت تستخدم Nginx و PHP-FPM انتقل للقسم التالي. تثبت الحزم الجديدة سوف يُرقي كل حزم PHP الهامة، باستثناء php5-mysql، التي سيتم حذفها. $ sudo apt-get install php7.0 ملحوظة: إذا قُمت بتعديلات هامة على أي ملف من ملفات الضبط في/etc/php5/، فهذه الملفات ستظل في مكانها، ويمكن الرجوع إليها. ملفات ضبط PHP 7.0 تجدها الآن في etc/php/7.0/. إذا كُنت تستخدم MySQL، تأكد من إعادة تثبيت جسر PHP MySQL المُحدّثة: $ sudo apt-get install php7.0-mysql ترقية PHP-FPM مع Nginx هذا القسم يوضح عملية ترقية نظام يستخدم Nginx كخادوم و PHP-FPM لتنفيذ شفرة PHP. تثبيت حزم PHP-FPM الجديدة واعتمادياتها: $ sudo apt-get install php7.0-fpm سيطلب منك الاستمرار، اضغط Enter لإكمال التثبيت. إذا كُنت تستخدم MySQL، تأكد من إعادة تثبيت جسر PHP MySQL المُحدّثة: $ sudo apt-get install php7.0-mysql ملحوظة: إذا قُمت بتعديلات هامة على أي ملف من ملفات الضبط في/etc/php5/، فهذه الملفات ستظل في مكانها، ويمكن الرجوع إليها. ملفات ضبط PHP 7.0 تجدها الآن في etc/php/7.0/. ترقية مواقع Nginx لتستخدم مسار المقبس الجديد يتواصل Nginx مع PHP-FPM باستخدام مقبس نطاق يونكس. ترسم المقابس خريطة لمسار على نظام الملفات، تستخدم PHP 7 مسار افتراضيًا جديدًا : PHP 5: /var/run/php5-fpm.sock PHP 7: /var/run.php7.0-fpm.sock افتح ملف ضبط الموقع الافتراضي بالمحرر nano (أو أي مُحرر من اختيارك): sudo nano /etc/nginx/sites-enabled/default قد يختلف ضبطك قليلا. ابحث عن كتلة تبدأ بـ }$location ~ \.php وسطر يبدو مثل ;fastcgi_pass unix:/var/run/php5-fpm.sock غيّر هذا ليستخدم unix:/var/run/php/php7.0-fpm.sock. مثال لملف etc/nginx/sites-enabled/default/ server { listen 80 default_server; listen [::]:80 default_server ipv6only=on; root /var/www/html; index index.php index.html index.htm; server_name server_domain_name_or_IP; location / { try_files $uri $uri/ =404; } error_page 404 /404.html; error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } اخرج واحفظ الملف. يمكنك القيام بهذا في nano بالضغط على Ctrl-x للخروج، y للتأكيد و Enter للتأكيد على اسم الملف الذي سيتم الكتابة فوقه. ينبغي تكرار هذه الخطوة لأي مواقع مُعرّفة في المُجلّد etc/nginx/sites-enabled/ والتي تحتاج أن تدعم PHP. الآن يمكننا إعادة تشغيل nginx: $ sudo service nginx restart اختبار PHP بعد ضبط الخادوم وتثبيت الحزم الجديدة، يمكننا التحقق من أن PHP تعمل. ابدأ بالتحقق من نسخة PHP المُثبتة بالأمر: $ php -v المخرجات PHP 7.0.0-5+deb.sury.org~trusty+1 (cli) ( NTS ) Copyright (c) 1997-2015 The PHP Group Zend Engine v3.0.0, Copyright (c) 1998-2015 Zend Technologies with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2015, by Zend Technologies يمكننا كذلك إنشاء ملف اختبار في مُجلد جذر وثائق الخادوم (document root). مسار هذا المُجلد يعتمد على خادومك وضبطك، قد يكون واحدًا من: var/www/html/ /var/www/ usr/share/nginx/html/ افتح ملفًا جديدًا باستخدام nano يسمى info.php في جذر الوثائق. يكون على Apache، افتراضيًا بالمسار الأول: $ sudo nano /var/www/html/info.php على Nginx، قد تستخدم: $ sudo nano /usr/share/nginx/html/info.php وألصق الشيفرة التالية بالملف: <?php phpinfo(); ?> أغلق المُحرر، واحفظ info.php. الآن، حمل العنوان التالي في متصفحك: http://server_domain_name_or_IP/info.php استبدل server_domain_name_or_IP باسم نطاق أو عنوان ip الخادوم. ينبغي أن ترى رقم نُسخة PHP ومعلومات ضبط PHP 7. بمجرد أن تُراجع هذه المعلومات، فمن الأفضل (لزيادة أمان خادومك) حذف الملف info.php: $ sudo rm /var/www/html/info.php خاتمة الآن لديك PHP 7، مُثبت ويعمل. قد ترغب في إلقاء نظرة على دليل الهجرة الرسمي إلى PHP 7. ترجمة -وبتصرّف- للمقال How To Upgrade to PHP 7 on Ubuntu 14.04 لصاحبه Brennen Bearnes.
  19. سنواصل في هذا الدّرس حديثنا حول نشر تطبيق PHP باستخدام Ansible. هذا الدّرس هو الجزء الثّاني للسلسلة، إذا لم تقرأ الجزء الأول فمن الأفضل أن تشرع به أوّلا، حيث نُعالج فيه تثبيت Ansible وإعداده. إذا لم تكن لديك أيّة خلفية مُسبقة حول Ansible فمن الأفضل أن تبدأ مع مقال كيفيّة تثبيت وإعداد Ansible على Ubuntu. سنتحدث في هذا القسم من الدّرس عن كيفية الحصول على إطار عمل Laravel وإعداده وإعداد خادوم Nginx لتخديم تطبيق PHP. سنستخدم إطار عمل Laravel كمثال عن تطبيق PHP ولكن يُمكِن تعديل هذه التعليمات بسهولة لتدعم أطر عمل وتطبيقات أخرى في حال كانت متواجدة لديك. المتطلبات الأساسيةيبدأ هذا الدّرس مباشرة من حيث انتهى الجزء الأول من هذه السلسلة، ونحتاج كافّة الملفّات والإعدادات التي تم الحصول عليها في ذلك الجزء، إن لم تقم بإكمال أول درس من هذه السلسلة فنرجو أن تفعل ذلك قبل متابعة هذا الدّرس. الخطوة الأولى – استنساخ مستودع Gitفي هذا القسم سنقوم باستنساخ clone مستودع إطار عمل Laravel إلى الخادوم الخاص بنا باستخدام Git، سنشرح مثل الخطوة الثالثة كافّة الأقسام التي سنقوم بإضافتها إلى الـ playbook، ونضمّن بعدها كامل ملف php.yml من أجلك لتقوم بنسخه ولصقه. وقبل أن نستنسخ مستودع Git الخاص بنا نحتاج إلى التأكّد من وجود الدليل var/www/، نستطيع فعل هذا عن طريق إنشاء مهمّة مع وحدة الملف: - name: create /var/www/ directory file: dest=/var/www/ state=directory owner=www-data group=www-data mode=0700 نحتاج كما أشرنا سابقًا إلى استخدام الوحدة Git لاستنساخ المستودع إلى الخادوم الخاص بنا، وهي عمليّة بسيطة لأنّ كل ما نحتاجه بشكل طبيعي من أجل الأمر git clone هو مستودع المصدر source repository، في هذه الحالة سنعرّف أيضًا الوجهة destination ونخبر Ansible بعدم تحديث المستودع في حال وجوده مسبقًا عن طريق تعيين update=no، وبما أنّنا نستخدم Laravel سنستعمل رابط مستودع git التالي: https://github.com/laravel/laravel.git نحتاج مع ذلك إلى تشغيل المهمّة عن طريق المستخدم www-data للتأكّد من أنّ الصلاحيّات صحيحة، ولعمل هذا نستطيع إخبار Ansible أن ينفّذ الأمر كمستخدم محدّد باستخدام sudo، ستبدو المهمّة النهائية كما يلي: - name: Clone git repository git: > dest=/var/www/laravel repo=https://github.com/laravel/laravel.git update=no sudo: yes sudo_user: www-data ملاحظة: من أجل المستودعات المعتمدة على SSH نستطيع إضافة accept_hostkey=yes لمنع التحقّق من المضيف على SSH من تعليق المهمّة. نفتح الملف php.yml لتحريره: nano php.yml نضيف المهام السابقة إلى الـ playbook، يجب أن يبدو الملف النهائي كما يلي: ... - name: enable php5 mcrypt module shell: php5enmod mcrypt args: creates: /etc/php5/cli/conf.d/20-mcrypt.ini - name: create /var/www/ directory file: dest=/var/www/ state=directory owner=www-data group=www-data mode=0700 - name: Clone git repository git: > dest=/var/www/laravel repo=https://github.com/laravel/laravel.git update=no sudo: yes sudo_user: www-data handlers: - name: restart php5-fpm service: name=php5-fpm state=restarted - name: restart nginx service: name=nginx state=restarted نحفظ الـ playbook ونغلقها، ثمّ نقوم بتشغيلها: ansible-playbook php.yml --ask-sudo-pass الخطوة الثانية – إنشاء تطبيق باستخدام Composerسنستخدم في هذه الخطوة Composer لتثبيت تطبيق PHP واعتمادياته dependencies. يمتلك Composer الأمر create-project الذي يقوم بتثبيت كافّة الاعتماديات المطلوبة ومن ثمّ يُشغِّل خطوات إنشاء المشروع المُعرَّفة في القسم post-create-project-cmd من الملف composer.json، وهي الطريق المفضّلة للتأكّد من إعداد التطبيق بشكل صحيح لاستخدامه لأول مرّة. نستطيع استخدام مهمّة Ansible التالية لتنزيل وتثبيت Composer بشكل عمومي كـ usr/local/bin/composer/، سيكون بعدها قابلًا للنفاذ من قبل أي شخص يستخدم الخادوم بما فيهم Ansible: - name: install composer shell: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer args: creates: /usr/local/bin/composer ومع وجود Composer مُثبّتًا لدينا فهنالك وحدة لـ Composer يُمكننا استخدامها، في حالتنا نريد إخبار Composer عن مكان مشروعنا (باستخدام المُعامِل working_dir)، ونريد أيضًا تنفيذ الأمر create-project، نحتاج أيضًا لإضافة المُعامِل optimize_autoloader=no لأنّ هذا العَلَم غير مدعوم من قبل الأمر create-project، وكما في حالة الأمر git يجب علينا تنفيذ هذا عن طريق المستخدم www-data للتأكّد من صلاحيّة الأذونات permissions، وبوضع كل ذلك معًا نحصل على هذه المهمّة: - name: composer create-project composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no sudo: yes sudo_user: www-data ملاحظة: قد تستغرق المهمّة create-project قدرًا كبيرًا من الوقت على خادوم جديد، حيث يمتلك الـ Composer ذاكرة تخزين مؤقّت فارغة ويحتاج إلى تنزيل كل شيء من جديد. نفتح الآن الملف php.yml لتحريره: nano php.yml نضيف المهام السابقة في نهاية القسم tasks فوق handlers بحيث تتوافق نهاية الـ playbook مع التالي: ... - name: Clone git repository git: > dest=/var/www/laravel repo=https://github.com/laravel/laravel.git update=no sudo: yes sudo_user: www-data - name: install composer shell: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer args: creates: /usr/local/bin/composer - name: composer create-project composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no sudo: yes sudo_user: www-data handlers: - name: restart php5-fpm service: name=php5-fpm state=restarted - name: restart nginx service: name=nginx state=restarted نقوم أخيرًا بتشغيل الـ playbook: ansible-playbook php.yml --ask-sudo-pass ما الذي سيحدث إن قمنا بتشغيل Ansible مرّة أخرى الآن؟ سيتم تشغيل composer create-project مرّة أخرى، وفي حالة Laravel يعني هذا APP_KEY جديد، لذا نريد بدلًا من ذلك تعيين المهمّة لتعمل فقط بعد استنساخ clone جديد، نستطيع ضمان أنّها تعمل فقط مرّة واحدة عن طريق تسجيل متغيّر يحتوي نتائج المهمّة git clone ومن ثمّ التحقّق من هذه النتائج داخل المهمّة composer create-project، إن تمّ تغيير المهمّة git clone فسيتم تنفيذ composer create-project، أمّا إن لم يحدث ذلك فسيتم تخطّيها. ملاحظة: يبدو أنّه يوجد خطأ برمجي في بعض إصدارات وحدة composer في Ansible، وربّما تعيد الخَرْج OK بدلًا من Changed، حيث تتجاهل أنّه تمّ تنفيذ scripts على الرغم من أنّه لم يتم تثبيت اعتماديات. نفتح الملف php.yml من أجل تحريره: nano php.yml نبحث عن المهمّة git clone، نضيف الخيار register لحفظ نتائج المهمّة إلى المتغير cloned كما يلي: - name: Clone git repository git: > dest=/var/www/laravel repo=https://github.com/laravel/laravel.git update=no sudo: yes sudo_user: www-data register: cloned </code>نبحث بعدها عن المهمّة composer create-project، نضيف الخيار when للتحقّق من المتغيّر cloned لنرى إن تغيّرت قيمته أم لا: - name: composer create-project composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no sudo: yes sudo_user: www-data when: cloned|changed نقوم بحفظ الـ playbook وتشغيلها: ansible-playbook php.yml --ask-sudo-pass سيوقف الـ Composer الآن تغيير APP_KEY في كل مرّة يتم تشغيله فيها. الخطوة الثالثة – تحديث متغيرات البيئةفي هذه الخطوة سنقوم بتحديث متغيّرات البيئة Environment Variables من أجل تطبيقنا. يأتي Laravel مع ملف env. بشكل افتراضي والذي يقوم بتعيين قيمة APP_ENV إلى local وقيمة APP_DEBUG إلى true، نحتاج إلى تبديل هذه القيم إلى production و false على الترتيب، يُمكِن فعل هذا ببساطة باستخدام الوحدة lineinfile مع المهام التالية: - name: set APP_DEBUG=false lineinfile: dest=/var/www/laravel/.env regexp='^APP_DEBUG=' line=APP_DEBUG=false - name: set APP_ENV=production lineinfile: dest=/var/www/laravel/.env regexp='^APP_ENV=' line=APP_ENV=production نفتح الملف php.yml لتحريره: nano php.yml نضيف هذه المهمّة إلى الـ playbook، يجب أن تبدو نهاية الملف متطابقة مع التالي: ... - name: composer create-project composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no sudo: yes sudo_user: www-data when: cloned|changed - name: set APP_DEBUG=false lineinfile: dest=/var/www/laravel/.env regexp='^APP_DEBUG=' line=APP_DEBUG=false - name: set APP_ENV=production lineinfile: dest=/var/www/laravel/.env regexp='^APP_ENV=' line=APP_ENV=production handlers: - name: restart php5-fpm service: name=php5-fpm state=restarted - name: restart nginx service: name=nginx state=restarted نقوم بحفظ الـ playbook وتشغيلها: ansible-playbook php.yml --ask-sudo-pass إنّ الوحدة lineinfile مفيدة جدًا من أجل التطويعات tweaks السريعة لأي ملف نصّي، وهي رائعة للتأكّد من تعيين متغيّرات بيئة كهذه بشكل صحيح. الخطوة الرابعة – إعداد Nginxسنقوم في هذا القسم بإعداد Nginx لتخديم تطبيق PHP. إن زرت الآن الخادوم الخاص بك في متصفّح الإنترنت (على سبيل المثال http://your_server_ip )، فسترى صفحة Nginx الافتراضيّة بدلاً من صفحة المشروع الجديد في Laravel، حدث هذا لأنّنا لا زلنا نحتاج إلى إعداد خادوم ويب Nginx لدينا لتخديم التطبيق من الدليل var/www/laravel/public/، لفعل هذا نحتاج لتحديث إعدادات Nginx الافتراضيّة بهذا الدليل وإضافة دعم من أجل php-fpm بحيث يستطيع التعامل مع PHP scripts. نقوم بإنشاء ملف جديد يُدعى nginx.conf: nano nginx.conf نحفظ كتلة الخادوم التالية بداخل هذا الملف، تستطيع متابعة الخطوة الرابعة من هذا الدّرس من أجل المزيد من التفاصيل حول إعدادات Nginx، تُحدِّد التعديلات التالية مكان دليل Laravel العام وتتحقّق من استخدام Nginx لاسم المضيف الذي عرّفناه في الملف hosts كـ server_name مع المتغيّر inventory_hostname. nginx.conf server { listen 80 default_server; listen [::]:80 default_server ipv6only=on; root /var/www/laravel/public; index index.php index.html index.htm; server_name {{ inventory_hostname }}; location / { try_files $uri $uri/ =404; } error_page 404 /404.html; error_page 500 502 503 504 /50x.html; location = /50x.html { root /var/www/laravel/public; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } نحفظ الملف nginx.conf ونغلقه. بإمكاننا الآن استخدام وحدة القالب template module لدفع ملف الإعدادات الجديدة عبرها، تبدو وحدة template مشابهة جدًا للوحدة copy، ولكن يوجد فرق كبير بينهما، فالوحدة copy ستنسخ ملف أو عدّة ملفّات بدون القيام بأيّة تغييرات، بينما تنسخ الوحدة template ملفًّا واحدًا وتقوم بتحليل كافّة الملفّات الموجودة بداخله، ولأنّنا استخدمنا {{ inventory_hostname }} داخل ملف إعداداتنا سنستخدم الوحدة template بحيث يتم تحليلها بداخل عنوان IP الذي استخدمناه في الملف hosts، وبهذه الطريقة لا يتوجّب علينا كتابة شيفرة محدّدة لملفّات الإعدادات التي تستخدمها Ansible. ومع ذلك فكما هو معتاد عند كتابة المهام نحتاج إلى أن نأخذ بعين الاعتبار ما سيحدث على الخادوم، ولأنّنا نقوم بتغيير إعدادات Nginx نحتاج لإعادة تشغيل Nginx و php-fpm، يتم هذا باستخدام الخيار notify: - name: Configure nginx template: src=nginx.conf dest=/etc/nginx/sites-available/default notify: - restart php5-fpm - restart nginx نفتح ملف php.yml: nano php.yml نضيف مهمّة nginx هذه في نهاية قسم المهام، ينبغي أن يبدو الملف php.yml كما يلي: php.yml --- - hosts: php sudo: yes tasks: - name: install packages apt: name={{ item }} update_cache=yes state=latest with_items: - git - mcrypt - nginx - php5-cli - php5-curl - php5-fpm - php5-intl - php5-json - php5-mcrypt - php5-sqlite - sqlite3 - name: ensure php5-fpm cgi.fix_pathinfo=0 lineinfile: dest=/etc/php5/fpm/php.ini regexp='^(.*)cgi.fix_pathinfo=' line=cgi.fix_pathinfo=0 notify: - restart php5-fpm - restart nginx - name: enable php5 mcrypt module shell: php5enmod mcrypt args: creates: /etc/php5/cli/conf.d/20-mcrypt.ini - name: create /var/www/ directory file: dest=/var/www/ state=directory owner=www-data group=www-data mode=0700 - name: Clone git repository git: > dest=/var/www/laravel repo=https://github.com/laravel/laravel.git update=no sudo: yes sudo_user: www-data register: cloned - name: install composer shell: curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer args: creates: /usr/local/bin/composer - name: composer create-project composer: command=create-project working_dir=/var/www/laravel optimize_autoloader=no sudo: yes sudo_user: www-data when: cloned|changed - name: set APP_DEBUG=false lineinfile: dest=/var/www/laravel/.env regexp='^APP_DEBUG=' line=APP_DEBUG=false - name: set APP_ENV=production lineinfile: dest=/var/www/laravel/.env regexp='^APP_ENV=' line=APP_ENV=production - name: Configure nginx template: src=nginx.conf dest=/etc/nginx/sites-available/default notify: - restart php5-fpm - restart nginx handlers: - name: restart php5-fpm service: name=php5-fpm state=restarted - name: restart nginx service: name=nginx state=restarted نقوم بحفظ الـ playbook وتشغيلها مرّة أخرى: ansible-playbook php.yml --ask-sudo-pass حالما تكتمل نعود إلى متصفحنا ونقوم بتحديثه، ينبغي أن نرى الآن صفحة المشروع الجديد في Laravel. الخاتمةيُغطّي هذا الدرس نشر تطبيق PHP مع مستودع عام، وبينما يكون هذا مثاليًّا من أجل تعلّم كيفيّة عمل Ansible، فإنّك لن تعمل دائمًا على مشاريع مفتوحة المصدر بشكل كامل مع مستودعات مفتوحة، ويعني هذا أنّك ستحتاج إلى استيثاق git clone في الخطوة الثالثة مع مستودعك الخاص، يُمكِن فعل هذا بسهولة باستخدام مفاتيح SSH. على سبيل المثال بعدما تقوم بإنشاء وإعداد مفاتيح نشر SSH على مستودعك تستطيع استخدام Ansible لنسخها وإعدادها على خادومك قبل مهمّة git clone: - name: create /var/www/.<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr>/ directory file: dest=/var/www/.<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr>/ state=directory owner=www-data group=www-data mode=0700 - name: copy private <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr> key copy: src=deploykey_rsa dest=/var/www/.<abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr>/id_rsa owner=www-data group=www-data mode=0600يجب أن يسمح هذا للخادوم بالاستيثاق بشكل صحيح ونشر تطبيقك. لقد قمنا للتو بنشر تطبيق PHP بسيط على خادوم ويب Nginx معتمد على Ubuntu باستخدام Composer لإدارة الاعتماديّات، وتمّ كل هذا بدون الحاجة للدخول مباشرة إلى الخادوم الخاصّ بنا وتنفيذ أي أمر بشكل يدوي. ترجمة -وبتصرّف- لـ How To Deploy a Basic PHP Application Using Ansible on Ubuntu 14.04 لصاحبه Stephen Rees-Carter.
  20. حِزم LEMP هي مجموعة من البرامج يُمكِن استخدامُها لتقديم صفحات ويب ديناميكيّة وتطبيقات ويب. يُشير هذا الاختصار إلى بيئة تتكوَّن من نظام تشغيل Linux، وخادوم ويب Nginx؛ تُخزَّن البيانات في قاعدة بيانات MySQL ويتولّى PHP مُعالجةَ المحتوى الدّيناميكي. سنشرح في هذا الدّرس كيفيّة تثبيت حزم LEMP على خادوم Ubuntu 14.04. يُمثِّل Ubuntu اللّبنة الأولى من حزمة LEMP في هذا الدّرس؛ سنشرح كيفيّة الحصول على بقيّة المُكوِّنات وتشغيلها. المتطلباتلإجراء الخطوات المذكورة في هذا الدّليل، يجب أن يكون لديك حساب عادي (غير الحساب الجذر Root user) بصلاحيّات sudo. يُمكنك معرفة كيف تضبُط حسابًا بهذه المواصفات في الخطوات من 1 إلى 4 من درس الإعداد الابتدائي لخادوم أوبنتو 14.04. سجِّل الدّخول إلى خادومك عبر الحساب المذكور حتى تكون جاهزًا لتطبيق خطوات الشّرح. الخطوة الأولى: ثبت خادوم ويب Nginxلنكون قادرين على عرض صفحات ويب لزوّار موقعنا سنستخدم Nginx؛ وهو خادوم ويب حديث وفعّال. كلّ البرامج الّتي سنُثبِّتها موجودة في المُستودعات Repositories الرّسميّة لأوبنتو، لذا سنستعين ببرنامج apt لإدارة الحزم لإكمال عمليّة التّثبيت. نبدأ أوّلًا بتحديث فهرس الحزم، ثمّ نُثبِّت خادوم الويب: sudo apt-get update sudo apt-get install nginxفي أوبنتو 14.04 يبدأ Nginx بالعمل فور تثبيته. يُمكِن التّأكّد من ذلك عبر إدخال اسم نطاق Domain name أو عنوان IP الخادوم العموميّ في شريط العنوان الموجود في مُتصفِّح الويب. ملحوظة: إذا كنتَ تُجرِّب هذه الخطوات على جهازك الشّخصي (أو جهاز محلّي) فعنوان خادوم الويب هو 127.0.0.1 (أو localhost). يُمكنك معرفة عنوان IP خادومك العمومي إن لم تكن تعرفه، ولا تملك اسمَ نطاق يُشير إلى موقعك، عبرَ تنفيذ الأمر التّالي في الطّرفيّة: ip addr show eth0 | grep inet | awk '{ print $2; }' | sed 's/\/.*$//'مثال على نتيجة تنفيذ الأمر أعلاه: 111.111.111.111 fe80::601:17ff:fe61:9801 يُمكن أيضًا تجربة الأمر: curl http://icanhazip.comالنّتيجة: 111.111.111.111جرّب الدّخول إلى العنوان الّذي حصلتَ عليه عن طريق إدخاله في شريط عنوان المتصفِّح: http://server_domain_name_or_IPيجب أن تظهر لديك صفحة الهبوط Landing page الافتراضيّة لـNginx: إذا ظهرت لك هذه الصّفحة فمعناهُ أنّ Nginx ثُبِّت بنجاح. الخطوة الثانية: ثبت MySQL لإدارة بيانات الموقعنحتاج بعد تثبيت خادوم الويب إلى نِظامٍ لإدارة قواعد البيانات Database management system, DBMS من أجل حفظ وإدارة بيانات موقعنا. سنستخدم MySQL لهذا الغرض. لتثبيت MySQL نُنفِّذ الأمر: sudo apt-get install mysql-serverسيُطلب منك إدخال كلمة سر لحساب المُستخدم الأعلى (الجذر Root) ضمن نظام MySQL. ملحوظة: كلمة السّر هنا هيّ لحساب إداري ضمن MySQL ولا علاقةَ لها بالمستخدِم الجذر في أوبنتو. نُواصِل مع MySQL عبر استكمال إعداداتِه. أوّلًا، نُنفِّذ الأمر التّالي الّذي يطلُب من MySQL توليدَ بُنية المجلّدات الّتي يحتاجها من أجل حفظ قواعد البيانات: sudo mysql_install_dbثمّ ننتقل لإجراء بضعة إعدادات أمنيّة حيثُ سنُغيِّر قيّمًا افتراضيّة غير الآمنة، عبر تنفيذ سكربت "التثبيت الآمن": sudo mysql_secure_installation سيُطلَب منك إدخال كلمة سر حساب المُدير في MySQL (نفس كلمة السّر الّتي أدخلتها أثناء التّثبيت). بعدها ستظهر رسالة تسألك إذا ما كنتَ تُريد تغيير كلمة سر المُدير في MySQL، إن لم تكن ترغب في ذلك أدخل حرف N ثمّ اضغط زر Enter. بقيّة الأسئلة تتعلّق بإزالة بعض الحسابات وقواعد البيانات المُعَدَّة للتّجربة؛ فقط اضغط Enter للإجابة عليها وستُحذَف الإعدادات الافتراضيّة غير الآمنة. نظام إدارة قواعد البيانات MySQL جاهز الآن للعمل. الخطوة الثالثة: ثبت PHP لمعالجة البياناتثبّتنا كلًّا من Nginx لتقديم صفحات الموقع وMySQL لتخزين وإدارة البيانات؛ بقيَ ربطُ الاثنيْن من أجل توليد محتوى ديناميكي. يُؤدّي PHP هذه الوظيفة. لا يأتي خادوم ويب Nginx بمعالج PHP مُضَمَّن كما هي حال بعض خواديم الويب الأخرى، لذا سنحتاج إلى تثبيت php5-fpm (حيثُ fpm اختصار لـ fastCGI process manager، وهوّ مُكوِّن مسؤول عن تقديم المحتوى الديناميكي في PHP)، ثمّ نطلُب من Nginx تمريرَ طلبات PHP إلى هذا البرنامج لمُعالجتها. يُمكِن تثبيت هذا العُنصُر وفي نفس الوقت نُثبِّت المكوِّن الّذي يسمح ل PHP بالتّواصُل مع النّهاية الخلفيّة Backend متمثّلةً في قاعدة البيانات؛ سيُنزِّل أمرُ التّثبيت كافّةَ الملفّات الضّروريّة: sudo apt-get install php5-fpm php5-mysqlضبط مُعالج PHPينتُج عن تنفيذ الأمر السّابق تثبيتُ العناصِر الضّروريّة لعمل PHP، لكن يتوجّب ضبطُ بعض الإعدادات من أجل أمان أكثر. افتَح الملف الرّئيس لإعداد php5-fpm بصلاحيّات الجذر: sudo nano /etc/php5/fpm/php.iniنبحث عن مُعطى Parameter باسم cgi.fix_pathinfo. افتراضيًّا ستجد أنّه مسبوق بعلامة ";" (دلالةً على أن السّطر تعليق، أي أنه لا يُؤخذ في الاعتبار) بقيمة مُساويّة لـ"1". هذا الإعداد غير آمن بالمرة، فهو يطلب من PHP تخمينَ الملف الذي يبحث عنه المستخدِم وتنفيذه إن لم يجد تطابقا تامًّا مع طلبه. أي أنّ الإعداد يُتيح للمستخدمين إنشاءَ طلبات PHP بحيث تؤدّي إلى تنفيذ سكربتات لا يجوز السّماح لهم بتنفيذها. نُغيّر الإعداد عن طريق حذف علامة التّعليق (";") ثمّ تبديل قيمة المُعطى لتُصبح 0، كما يلي: cgi.fix_pathinfo=0احفظ الملف (Ctrl + O ثم زر Enter) ثم أغلقه بعد الانتهاء من تحريره (Ctrl + x). نُعيد تشغيل مُعالج PHP لأخذ التّغييرات بالاعتبار: sudo service php5-fpm restartالخطوة الرابعة: اضبط Nginx على استخدام معالج PHPجميع العناصِر مُثبَّتة الآن؛ تبقّى تعديلٌ واحدٌ وهو إعدادُ Nginx لاستخدام معالج PHP المُعدّ أعلاه للتّعامل مع المُحتوى الدّيناميكي. يُضبط هذا الإعداد على مُستوى مُربّع الخادوم Server block (مُربّعات الخادوم مُشابهة لـلمُستضيفات الافتراضيّة Virtual hosts على خادوم ويب Apache ). افتَح الملف الافتراضي لإعداد مُربّع خادوم Nginx عبر تنفيذ الأمر: sudo nano /etc/nginx/sites-available/defaultيبدو الملفّ، بعد حذف التّعليقات، كالتّالي: server { listen 80 default_server; listen [::]:80 default_server ipv6only=on; root /usr/share/nginx/html; index index.html index.htm; server_name localhost; location / { try_files $uri $uri/ =404; } }سنُجري بضع تعديلات على هذا الملف. نحتاج أوّلًا إلى إضافة خيّار index.php إلى تعليمة Directive الفهرس، ممّا يسمح بتقديم ملفّات فهارس PHP عند طلَب مُجلَّد. نحتاج أيضًا إلى تعديل تعليمة server_name حتّى تُشير إلى اسم نطاق الخادوم أو عنوانه العموميّ. يحوي ملفّ الإعداد على أسطُر تُعرِّف دوّالًا للتّعامل مع الأخطاء. توجد أمام هذه الأسطُر علامة تعليق. نحذف علامة التّعليق لكي تعمَل آليّات التّعامل مع الأخطاء. نفس الشّيْء بالنّسبة لمُعالج PHP، ننزع التّعليق عن أسطُر أخرى من ملفّ الإعداد. ثمّ أخيرًا نُضيف التّعليمة try_files للتّأكّد من أنّ Nginx لا يُمرّر طلباتٍ غير صالحة لمُعالج PHP. تظهر التّغييرات في مُحتوى الملفّ أدناه باللّون الأحمر: server { listen 80 default_server; listen [::]:80 default_server ipv6only=on; root /usr/share/nginx/html; index index.php index.html index.htm; server_name server_domain_name_or_IP; location / { try_files $uri $uri/ =404; } error_page 404 /404.html; error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } location ~ \.php$ { try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }يُمكِن حفظ الملف وغلقُه بعد إجراء التّعديلات. أعِد تشغيل Nginx لأخذ التّغييرات في الاعتبار: sudo service nginx restartالخطوة الخامسة: أنشئ ملف PHP لاختبار الإعداداتيُفترَض أن تكون حزم LEMP مُثبَّتة وجاهزة للعمل. سنتأكّد الآن أنّ خادوم ويب Nginx يتعامل مع ملفّات PHP ويُمرِّرها لمُعالج PHP. نُنشئ عبر الأمر التّالي ملفَّ اختبار PHP في مَبدَأ المستند Document root: sudo nano /usr/share/nginx/html/info.phpيُمكِن أن نُضيف الأسطُر التّالية؛ وهي شفرة برمجيّة Code صالحة في لغة PHP، ينتُج عنها عرض معلومات الخادوم على الصّفحة. <?php phpinfo(); ?>احفَظ الملفّ ثمّ أغلقه. اذهب إلى متصفِّح الويب ثم اعرض للصّفحة عبر إدخال اسم نطاق أو عنوان الموقع (server_domain_name_or_IP) متبوعًا ب info.php/ كما يلي: http://server_domain_name_or_IP/info.phpيجب أن تظهر لديك صفحة ويب تعرِض معلومات الخادوم، كما في الصّورة. يدُلّ ظهور الصّفحة على نجاح إعداد Nginx للتّعامل مع ملفّات PHP. من الأفضل حذفُ ملفّ info.php بعد انتهاء الاختبار، إذ أنّه يُمكن أن يكشف عن إعدادات موقعك، الأمر الّذي قد يُساعِد من يُحاول الحُصول على وُصول غير مُرَخَّص. يُمكِنك دائمًا إنشاء هذا الملفّ عندما تُريد إجراء اختبارات. للحذف، نفّذ الأمر التّالي: sudo rm /usr/share/nginx/html/info.phpخاتمةيُمكِّن اتّباع الخطوات السّابقة من إعداد وضبط حزمة LEMP على خادوم أوبنتو 14.04. تُعطي هذه الحزمة قاعدة جيّدة ومرنة من أجل تقديم مُحتوى ديناميكي لزوّار موقعك. ترجمة -وبتصرّف- للمقال How To Install Linux, nginx, MySQL, PHP (LEMP) stack on Ubuntu 14.04 لصاحبه Justin Ellingwood.
  21. سنتعلّم في هذا الدّرس كيفيّة الحصول على شهادة SSL من سلطة شهادات تجاريّة (Commercial Certificate Authority (CA وكيفيّة تثبيتها، تسمح شهادات SSL لخواديم الويب بتشفير حركة مرور بياناتها traffic وتُوفِّر آليّة للتحقّق من هويّات الخواديم من أجل الزوّار، إنّ الميزة الأساسيّة لشراء شهادة SSL من سلطة شهادات تجاريّة (CA) موثوقة عن الشهادات المُوقَّعة ذاتيًّا self-signed أنّه لن يتم عرض تحذير مُخيف للزوّار حول عدم القدرة على التحقّق من هويّة موقعنا. يغطّي هذا الدرس كيفيّة الحصول على شهادة SSL من سلطات الشهادات الموثوقة التالية: GoDaddyRapidSSL via Namecheapبإمكانك أيضًا استخدام أي سلطة شهادات CA من اختيارك. سنشرح بعد أن حصلنا على شهادة SSL كيفيّة تثبيتها على خواديم ويب Nginx و Apache HTTP. سنشاهد في هذا الدّرس كيفيّة الحصول على شهادة SSL مُفردة النطاق أو wildcard من GoDaddy وRapidSSL، ولكنّ الحصول على الأنواع الأخرى من الشهادات مماثل تمامًا. توليد CSR ومفتاح خاص Private Keyبعد أن تقوم بتجهيز المتطلبات الأساسيّة وتختار نوع الشهادة التي نريد الحصول عليها، تحتاج لتوليد طلب توقيع الشهادة (certificate signing request (CSR ومفتاح خاص private key. إن كنت تخطّط لاستخدام Apache HTTP أو Nginx كخادوم ويب لديك فاستخدم openssl لتوليد CSR ومفتاحك الخاص على خادومك الويب، سنبقي في هذا الدّرس كافّة الملفات المرتبطة بهذا في الدليل الرئيسي home directory ولكن لا تتردد في تخزينها في أي موقع آمن على خادومك: cd ~نقوم بتنفيذ هذا الأمر لتوليد مفتاح خاص يُدعى example.com.key و CSR يُدعى example.com.csr (ضع اسم نطاقك بدلًا من example.com): openssl req -newkey rsa:2048 -nodes -keyout example.com.key -out example.com.csrعند هذه النقطة سيتم حثنا على إدخال عدّة أسطر من المعلومات تُضمَّن في طلب شهادتنا، إنّ الجزء الأهم منها هو حقل الاسم الشائع Common Name والذي يجب أن يُطابق الاسم الذي نرغب باستخدام الشهادة معه، على سبيل المثال example.com ،www.example.com، أو (بالنسبة لطلب شهادة wildcard) *.example.com، إن كنت تُخطّط للحصول على شهادة OV أو EV فتأكّد من أن تتوافق كافّة الحقول الأخرى بدقة مع بيانات منظمتك أو عملك. على سبيل المثال: Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:New York Locality Name (eg, city) []:New York Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []:example.com Email Address []:sammy@example.comسيقوم هذا بتوليد ملفات key. و csr.، حيث يكون الملف key. هو مفتاحنا الخاص ويجب أن نبقيه في مكان آمن، والملف csr. هو الذي يجب أن نرسله إلى سلطة الشهادات لطلب شهادة SSL. نحتاج إلى نسخ ولصق CSR الخاصّة بنا عند تقديم طلب الشهادة إلى سلطة الشهادات، نستخدم هذا الأمر لطباعة محتويات ملف CSR لدينا (ضع اسم ملفّك بدلًا من التالي): cat example.com.csrنحن الآن مستعدون لشراء شهادة من سلطة الشهادات، سنعرض هنا مثالين، GoDaddy و RapidSSL عبر Namecheap، ولكن لك الحرية بالحصول على الشهادة من أي بائع آخر. مثال سلطة الشهادات الأول: RapidSSL via Namecheapتوفّر Namecheap طريقة لشراء شهادات SSL من مجموعة متنوعة من سلطات الشهادات، سنشرح عمليّة الحصول على شهادة نطاق مُفرَد من RapidSSL، ولكن إن أردت نوعًا مختلفًا من الشهادات فبإمكانك فعل ذلك. ملاحظة: إن طلبنا شهادة نطاق مُفرَد من RapidSSL من أجل النطاق الفرعي www لنطاقنا (على سبيل المثال www.example.com) فسيقومون بإصدار الشهادة لنا مع SAN لنطاقنا الأساسي، فإن كان طلب شهادتنا على سبيل المثال من أجل www.example.com فستعمل الشهادة الصادرة من أجل www.example.com و example.com. اختيار وشراء الشهادةنذهب إلى صفحة Namecheap لشهادات SSL . نستطيع هنا البدء في اختيار مستوى التحقّق، نوع الشهادة ("Domains Secured") أو ("CA Brand"). سنضغط في مثالنا على زر مقارنة المنتجات Compare Products في مربّع التحقّق من النطاق "Domain Validation"، بعدها نستطيع إيجاد "RapidSSL" والضغط على زر إضافة إلى السلّة Add to Cart. عند هذه النقطة يجب علينا التسجيل في Namecheap أو تسجيل الدخول إليه، وإنهاء عمليّة الدفع. طلب الشهادةنذهب بعد أن دفعنا من أجل الشهادة التي اخترناها إلى الرابط Manage SSL Certificates الموجود تحت القسم "Hi Username". سنشاهد هنا قائمة بكامل شهادات SSL التي اشتريناها عبر Namecheap، نضغط على رابط التفعيل الآن Activate Now من أجل الشهادة التي نريد استخدامها. نختار الآن برمجيّة خادوم الويب لدينا والتي تُحدِّد تنسيق الشهادة التي سيسلمها Namecheap لنا، الخيارات التي نختارها بشكل شائع هي "Apache + MOD SSL"، "nginx"، أو "Tomcat". نلصق CSR الخاصة بنا في المربّع ونضغط بعدها زر التالي Next. يجب أن نكون الآن في خطوة اختيار المُصادِق "Select Approver" من العمليّة، والتي سترسل بريد إلكتروني لطلب التحقّق إلى عنوان في تسجيل WHOIS لنطاقنا أو إلى عنوان من نوع مدير administrator للنطاق الذي نريد أن نحصل على شهادة له، نختار العنوان الذي نريد أن نرسل إليه البريد الإلكتروني للتحقّق. نقوم بتزويد معلومات التواصل الإداريّة "Administrative Contact Information" ونضغط على زر تقديم الطلب Submit order. التحقق من النطاقسيتم عند هذه النقطة إرسال بريد إلكتروني إلى عنوان المُصادِق "approver"، نفتح البريد الإلكتروني ونصادق على طلب الشهادة. تنزيل الشهاداتبعد المُصادَقة على الشهادة سيتم إرسالها عبر البريد الإلكتروني إلى القسم التقني Technical Contact، ستكون الشهادة الصادرة لنطاقنا وشهادة سلطة الشهادات الوسيطة CA's intermediate certificate في أسفل رسالة البريد الإلكتروني. ننسخها ونحفظها إلى خادومنا في نفس المكان الذي وضعنا فيه CSR ومفتاحنا الخاص. نقوم بتسمية الشهادة باسم النطاق مُضافًا إليه اللاحقة crt.، مثل example.com.crt، وتسمية الشهادة الوسيطة intermediate.crt. تكون الشهادة الآن جاهزة للتثبيت على خادوم الويب لدينا. مثال سلطة الشهادات الثاني: GoDaddyإنّ GoDaddy هي سلطة شهادات شائعة تملك كافّة أنواع الشهادات الأساسية، سنشرح عمليّة الحصول على شهادة نطاق مُفرَد، ولكن إن أردت نوعًا مختلفًا من الشهادات فبإمكانك فعل ذلك. اختيار وشراء الشهادةنذهب إلى صفحة GoDaddy لشهادات SSL. ننزل للأسفل ونضغط على زر البدء Get Started. نختار نوع شهادة SSL الذي نريده من القائمة المنسدلة: نطاق مُفرَد single domainنطاقات متعدّدة (multidomain (UCCwildcard نختار بعدها نوع الخطّة plan: نطاق domainمُنظَّمة organizationتحقّق مُوسَّع extended validationثم نختار المدى term (مُدّة الصلاحية). نضغط بعدها على زر إضافة إلى السلّة Add to Cart. نُراجع طلبنا الحالي ثم نضغط على المتابعة إلى الدفع Proceed to Checkout. ومن ثمّ نكمل التسجيل وعمليّة الدفع. طلب الشهادةبعد إكمال طلبنا نضغط على زر SSL Certificates* (أو نضغط على My Account > Manage SSL Certificates الموجودة في الزاوية العلوية اليمنى). نقوم بإيجاد شهادة SSL التي اشتريناها للتو ونضغط على زر الإعداد Set Up، إن لم تستخدم GoDaddy من قبل من أجل شهادات SSL فسيتم حثك على إعداد مُنتَج "SSL Certificates" وربط طلب شهادتك الأخيرة مع المُنتَج (نضغط على زر Set Up الأخضر وننتظر عدّة دقائق قبل تحديث متصفّحنا). بعد أن تتم إضافة مُنتَج "SSL Certificates" إلى حسابنا في GoDaddy ينبغي أن نرى شهادتنا الجديدة "New Certificate" وزر التنفيذ "Launch"، نضغط على الزر Launch الموجود بجانب شهادتنا الجديدة. نقوم بتقديم CSR الخاص بنا عن طريق لصقه في المربع، تُستخدَم خوارزميّة SHA-2 افتراضيًّا. نضع علامة في خانة التأشير I agree ونضغط على زر طلب الشهادة Request Certificate. التحقق من النطاقيجب الآن أن نُثبِت أنّنا نمتلك تحكّمًا بنطاقنا ونزوّد GoDaddy ببعض المستندات، تقوم GoDaddy بإرسال رسالة بريد إلكتروني للتحقّق من ملكيّة النطاق إلى العنوان الموجود في تسجيل WHOIS لنطاقنا، نتبع الخطوات الموجودة في رسائل البريد الإلكتروني التي تصلنا ونُصرِّح بإصدار الشهادة. تنزيل الشهادةبعد أن نُثبِت لـ GoDaddy أنّنا نمتلك النطاق، نتحقّق من بريدنا الإلكتروني (الذي قمنا من خلاله بالتسجيل في GoDaddy) بحثًا عن رسالة تقول أنّه تم إصدار شهادة SSL الخاصة بنا، نفتحها ونتبع رابط تنزيل الشهادة (أو نضغط على زر Launch بجانب شهادة SSL التي نريدها في لوحة تحكّم GoDaddy). نضغط الآن على زر التنزيل Download. نختار برمجيّة الخادوم التي نستخدمها من القائمة المنسدلة لنوع الخادوم Server type، إن كنّا نستخدم Apache HTTP أو Nginx نختار "Apache" ثم نضغط على زر تنزيل الملف المضغوط Download Zip File. نستخرج الملف المضغوط، الذي ينبغي أن يحتوي على ملفين crt.، أحدهما شهادة SSL الخاصّة بنا (التي ينبغي أن تملك اسمًا عشوائيًّأ) وحزمة bundle شهادة GoDaddy الوسيطة (gd_bundle-g2-1.crt)، نقوم بنسخهما إلى خادوم الويب لدينا، ونعيد تسمية الشهادة إلى اسم نطاقنا مع إضافة اللاحقة crt.، على سبيل المثال example.com.crt، ونعيد تسمية حزمة الشهادة الوسيطة إلى intermediate.crt. تكون الشهادة الآن جاهزة للتثبيت على خادوم الويب لدينا. تثبيت الشهادة على خادوم الويب لديناينبغي بعد الحصول على شهادتنا من سلطة الشهادات التي نختارها أن نقوم بتثبيتها على خادوم الويب لدينا، يتضمّن هذا إضافة بعض الأسطر المتعلّقة بـ SSL لملفّات إعدادات خادومنا. سنغطي في هذا القسم الإعدادات الأساسيّة لخادوم Nginx و Apache HTTP على Ubuntu. سنفترض الأمور التالية: يتوضّع المفتاح الخاص وشهادة SSL والشهادات الوسيطة لسلطة الشهادات-إن كان ذلك قابلًا للتطبيق- في الدليل الرئيسي على المسار home/sammy/يُدعى المفتاح الخاص باسم example.com.keyتُدعى شهادة SSL باسم example.com.crtتُوجد الشهادة أو الشهادات الوسيطة لسلطة الشهادات في ملف يُدعى intermediate.crtإن كنت تملك جدار ناري مُمكَّنًا لديك فتأكّد من أنّه يسمح بالمنفذ 443 (منفذ HTTPS)ملاحظة: يجب في البيئة الحقيقيّة تخزين هذه الملفّات في مكان يستطيع فقط المستخدم الذي يُشغِّل عملية خادوم الويب الرئيسيّة (عادة root) الوصول إليه، ينبغي الاحتفاظ بالمفتاح الخاص في مكان آمن. خادوم Nginxإن كنت ترغب باستخدام شهادتك مع خادوم Nginx على Ubuntu فاتبع هذا القسم. ينبغي في Nginx إن كانت سلطة الشهادات قد أعطتنا شهادة وسيطة أن نقوم بإنشاء ملف شهادة مُفرَد محمي بالسلاسل chained يحتوي على شهادتنا والشهادات الوسيطة لسلطة الشهادات. نذهب إلى الدليل الذي يحوي مفتاحنا الخاص، الشهادة، وشهادة سلطة البيانات الوسيطة (أي الملف intermediate.crt)، سنفترض أنّها في الدليل الرئيسي على سبيل المثال: cd ~بافتراض أنّ ملف الشهادة يُدعى example.com.crt نستخدم هذا الأمر لإنشاء ملف مُدمَج يُدعى example.com.chained.crt (نضع اسم نطاقنا بدلًا من example.com): cat example.com.crt intermediate.crt > example.com.chained.crtنذهب الآن إلى دليل إعدادات كتلة block خادوم Nginx، وبافتراض أنّه موجود في المسار etc/nginx/sites-enable/ نستخدم هذا الأمر للانتقال إليه: cd /etc/nginx/sites-enabledبافتراض أنّنا نريد إضافة SSL إلى ملف كتلة الخادوم الافتراضي default نفتح الملف من أجل تحريره: sudo vi defaultنبحث عن الأمر التوجيهي listen ونقوم بتعديله بحيث يبدو كما يلي: listen 443 ssl;نبحث بعدها عن الأمر التوجيهي server_name ونتأكد من أنّ قيمته مُطابِقة لاسم شهادتنا، نُضيف أيضًا الأوامر التوجيهيّة ssl_certificate و ssl_certificate_key لتحديد المسارات لشهادتنا وتحديد ملفّات المفاتيح الخاصّة (نضع الأسماء الموجودة لدينا بدلًا من example.com): server_name example.com; ssl_certificate /home/sammy/example.com.chained.crt; ssl_certificate_key /home/sammy/example.com.key;ولنسمح فقط بالشيفرات ciphers وميفاقات SSL protocols الأكثر أمانًا نُضيف الأسطر التالية إلى الملف: ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers AES256+EECDH:AES256+EDH:!aNULL;إن أردنا إعادة توجيه المرور عبر HTTP إلى HTTPS نستطيع إضافة هذه الكتلة الإضافيّة للخادوم في أعلى الملف (نضع معلوماتنا بدلًا من example.com): server { listen 80; server_name example.com; rewrite ^/(.*) https://example.com/$1 permanent; }نقوم بعدها بالحفظ والخروج. نعيد تشغيل خادوم Nginx الآن لتحميل الإعدادات الجديدة وتمكين TLS/SSL عبر HTTPS: sudo service nginx restartنختبر ذلك بالوصول إلى موقعنا عبر HTTPS، على سبيل المثال https://example.com. خادوم Apacheإن كنت ترغب باستخدام شهادتك مع خادوم Apache على Ubuntu فاتبع هذا القسم. نقوم بعمل نسخة احتياطيّة لملف إعداداتنا عن طريق نسخه، وبافتراض أنّ خادومنا يعمل على ملف إعدادات المُضيف الوهمي virtual الافتراضي، etc/apache2/sites-available/000-default.conf/، نستخدم هذه الأوامر لعمل النسخة: cd /etc/apache2/sites-available cp 000-default.conf 000-default.conf.origنفتح بعدها الملف لتحريره: sudo vi 000-default.confنبحث عن المُدخَل <VirtualHost *:80> ونقوم بتعديله بحيث يستمع خادوم الويب لدينا على المنفذ 443: <VirtualHost *:443>نقوم بعدها بإضافة الأمر التوجيهي ServerName إن لم يكن موجودًا مُسبقًا (نضع اسم نطاقنا هنا): ServerName example.comنضيف بعد ذلك الأسطر التالية لتحديد شهادتنا ومسارات المفاتيح (نضع مسارنا الفعلي هنا): SSLEngine on SSLCertificateFile /home/sammy/example.com.crt SSLCertificateKeyFile /home/sammy/example.com.keyإن كُنّا نستخدم Apache 2.4.8 أو أكثر نُحدِّد حزمة الشهادة الوسيطة لسلطة الشهادات بإضافة هذا السطر (نضع المسار الفعلي لدينا): SSLCACertificateFile /home/sammy/intermediate.crtإن كُنّا نستخدم إصدار أقدم من Apache نُحدِّد حزمة الشهادة الوسيطة لسلطة الشهادات بإضافة هذا السطر (نضع المسار الفعلي لدينا): SSLCertificateChainFile /home/sammy/intermediate.crtعند هذه النقطة أصبح خادومنا مُعدًّا ليستمع إلى HTTPS فقط (المنفذ 443)، لذا لن يتم تخديم طلبات HTTP (المنفذ 80)، لإعادة توجيه طلبات HTTP إلى HTTPS نضيف ما يلي إلى أعلى الملف (نكتب اسم نطاقنا بدلًا من example.com): <VirtualHost *:80> ServerName example.com Redirect permanent / https://example.com/ </VirtualHost>نقوم بالحفظ والخروج. نقوم بتمكين وحدة Apache SSL بتنفيذ هذا الأمر: sudo a2enmod sslنعيد تشغيل خادوم Apache الآن لتحميل الإعدادات الجديدة وتمكين TLS/SSL عبر HTTPS: sudo service apache2 restartنختبر ذلك بالوصول إلى موقعنا عبر HTTPS، على سبيل المثال https://example.com، نريد أيضًا اختبار الاتصال عبر HTTP، مثل http://example.com لنضمن أنّ إعادة التوجيه تعمل بشكل صحيح. الخاتمةنمتلك الآن فكرة جيّدة عن كيفيّة إضافة شهادة SSL موثوقة لتأمين خادوم الويب لدينا، احرص على أن تتسوّق من سلطة شهادات تجعلك مسرورًا معها. ترجمة -وبتصرّف- لـ How To Install an SSL Certificate from a Commercial Certificate Authority لصاحبه Mitchell Anicas.
  22. HHVM هي آلة افتراضية مفتوحة المصدر لتنفيذ الشيفرة المكتوبة بلغتي PHP وHACK. تُطور HHVM وتدعمها فيس بوك، الأمر الذي لفت الانتباه إليها كثيرا في الآونة الأخيرة. تختلف HHVM عن باقي محركات PHP لأنها تتبع منهج "الترجمة فقط في الوقت المناسب" JIT. HHVM تترجم الشيفرة PHP إلى شيفرة ثنائية وسيطة intermediate byte code ثم بعد ذلك إلى شيفرة بلغة الآلة x64 machine instructions قبيل وقت التنفيذ، هذا الأمر يسمح بكثير من التحسين وسرعة في الأداء مقارنة بالطرق التي تتبعها محركات PHP الأخرى. HHVM قوية وسريعة ، ولكنها -مقارنة بمحركات PHP الأخرى- تتطلب موارد أكثر من ذاكرة الوصول العشوائي RAM والمعالج CPU، مثلها مثل الآلات الافتراضية الأخرى (JVM مثلا). في هذه المقالة سوف نبين لك كيف تثبت HHVM وتدمجه مع Nginx. المتطلبات الأساسيةقد تم اختبار هذا الدرس على أوبنتو 14.04 . طريقة التثبيت الموصوفة في هذه المقالة والإعدادات المشروحة فيها ستكون هي نفسها في كل أنظمة التشغيل إلا بعض الأوامر ومسارات ملفات الإعداد. من أجل إتمام هذا الدرس وتطبيقه لا بد لك من الأمور التالية: نظام أوبنتو 14.04 مع ذاكرة وصول عشوائي RAM لا تقل عن 1 جيجا.مستخدم عادي له صلاحيات sudo.خادوم Nginx مثبت على النظام.كل الأوامر في هذا الدرس ينبغي أن تنفذ بصلاحيات المستخدم العادي، وفي حال كانت صلاحيات الجذر مطلوبة فسيُسبق الأمر بالكلمة sudo . في حال استخدمت أوبنتو 14.04 فإن له مستودعا رسميا يدعم HHVM، ومن أجل إضافة هذا المستودع يجب عليك استيراد المفتاح العام GnuPG بالأمر التالي: sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0x5a16e7281be7a449بعد هذا يمكنك تثبيت مستودع HHVM بكل أمان بالأمر التالي: sudo add-apt-repository "deb http://dl.hhvm.com/ubuntu $(lsb_release -sc) main"بعد إضافة المستودع يجب عليك تحديث قاعدة بيانات الحزم حتى تنضاف إليها حزم المستودع الجديد وذلك يكون بالأمر التالي: sudo apt-get updateوأخيرا يمكنك تثبيت HHVM بالأمر التالي: sudo apt-get install hhvmالأمر السابق يقوم بتثبيت HHVM وتشغيلها في الوقت نفسه ، ولكي نجعل التشغيل تلقائيا مع تشغيل النظام فلابد لنا من تنفيذ الأمر: sudo update-rc.d hhvm defaultsالإعداداتيأتي مع HHVM سكريبت يجعل دمجها مع خادوم Nginx أسهل. ونحن نفترض أنك ثبتّ خادوم Nginx بالطريقة الافتراضية، وعليه يمكنك تنفيذ السكريبت من غير أي مدخلات بالأمر التالي: sudo /usr/share/hhvm/install_fastcgi.shعند تنفيذ هذا السكريبت يقوم بإضافة ملف الإعدادات etc/nginx/hhvm.conf/ إلى الملف الافتراضي لإعدادات Nginx server block ألا وهو الملف etc/nginx/sites-enabled/default/، هذا السكربت يعمل فقط مع الإعدادت الإفتراضية لخادوم Nginx بدون أي تغييرات في FastCGI. إذا كنت قد غير في إعدادات Nginx server block وإعدادات FastCGI كما هو الشأن في PHP-FPM فيجب عليك استبدال الإعدادات الجديدة بالقديمة يدويا وذلك بالتعديل على الملف etc/nginx/sites-enabled/default/: location ~ \.(hh|php)$ { fastcgi_keep_conn on; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; }تعني الأسطر السابقة أنه على Nginx أن يعالج أي ملف مطلوب ينتهي باللاحقة php. أو hh. الخاصة بلغة hack، ويجب عليك بعدئذ إعادة تشغيل الخادوم Nginx من أجل تفعيل التغييرات: sudo service nginx restartوأيضا يفترض هذا السكريبت أنك لم تغير إعدادات HHVM التي تجعل الخدمة قابلة للوصول إليها عبر العنوان 127.0.0.1:9000، هذه الإعدادات تأتي افتراضيا في الملف etc/hhvm/server.ini/ الذي محتواه: ; php options pid = /var/run/hhvm/pid ; hhvm specific hhvm.server.port = 9000 hhvm.server.type = fastcgi hhvm.server.default_document = index.php hhvm.log.use_log_file = true hhvm.log.file = /var/log/hhvm/error.log hhvm.repo.central.path = /var/run/hhvm/hhvm.hhbcولعلك لاحظت في هذه الإعدادات لـ HHVM المتغير hhvm.server.port الذي يحدد أن هذه HHVM سوف تستمع على منفذ البروتوكول TCP 9000، وعلى الهوست المحلي localhost ما لم يتم تغيير ذلك. يفترض ب HHVM أن تعمل في بيئات ذات عبء ثقيل ، لذلك فإن التغيير الأول الذي ينبغي عليك فعله هو تغيير طريقة الاستماع من المنفذ TCP إلى المقبس socket ، هذا سيستهلك موارد أقل من الذاكرة العشوائية والمعالج في حال التواصل بين الخادوم Nginx والآلة الافتراضية HHVM. لكي تغير تلك الإعدادات افتح الملف etc/hhvm/server.ini/ بأي محرر نصوص مفضل لديك مثل vim : sudo vim /etc/hhvm/server.ini ثم احذف السطر الذي يبدأ بـ hhvm.server.port، وضع في مكانه السطر التالي: hhvm.server.file_socket=/var/run/hhvm/hhvm.sockاحفظ الإعدادات ثم أعد تشغيل HHVM بالأمر: sudo service hhvm restartبعد ذلك يجب عليك أن تجعل الخادوم Nginx يأخذ بعين الاعتبار التغييرات السابقة وذلك بتعديل الملف etc/nginx/hhvm.conf/: sudo vim /etc/nginx/hhvm.confفي هذا الملف تأكد أن الموجه fastcgi_pass يشير إلى مقبس HHVM وأنه يظهر بالشكل التالي: fastcgi_pass unix:/var/run/hhvm/hhvm.sock;ثم بعد ذلك يجب عليك أن تعيد تشغيل الخادوم Nginx حتى يتم تفعيل تلك التغييرات ، من أجل ذلك نفذ الأمر: sudo service nginx restartيمكن للسكريبت usr/share/hhvm/install_fastcgi.sh/ أن يوفر عليك بعض الوقت، ولكن هناك أشياء لابد عليك من فعلها بنفسك لا سيما فيما يخص Nginx server blocks ، مثال على ذلك أن الإعدادات الافتراضية لـ Nginx server blocks إذا طلب منه صفحة index فإنه يفتح فقط الملفين index.html و index.htm عندما يكون سرد المجلدات ممنوعا، هذا أحد الأشياء التي يجب عليك تغييرها لكي يضاف index.php إلى الملفات التي يفتحها الخادوم عند طلب index. لفعل ذلك افتح ملفات إعدادات server block بمحررك المفضل: sudo vim /etc/nginx/sites-enabled/defaultثم اذهب إلى الجزء المخصص للخادوم ثم أضف index.php حيث يوجد ملفات index ، سيظهر ذلك الجزء بالشكل التالي: index index.html index.htm index.php;مرة اخرى أعد تشغيل خادوم Nginx ليتم تفعيل هذه الإعدادات: sudo service nginx restartاختبار وتعديل HHVMأول اختبار يمكنه أداؤه هو بواجهة أوامر PHP (cli) /usr/bin/php التي تشير إلى etc/alternatives/php/، والتي هي أيضا تشير إلى الملف التنفيذي usr/bin/hhvm/ الخاص بـ HHVM، نفذ الأمر: /usr/bin/php --versionعندما تنفذ هذا الأمر فإنه ينبغي أن ترى رقم إصدار HHVM ومعلومات أخرى كهذا: HipHop VM 3.8.1 (rel) Compiler: tags/HHVM-3.8.1-0-g3006bc45691762b5409fc3a510a43093968e9660 Repo schema: 253b3802ce1bcd19e378634342fc9c245ac76c33إذا كنت قد ثبتّ PHP من قبل فربما ظهر لك معلومات النسخة القديمة من PHP، من أجل تغيير ذلك وجعله يشير إلى HHVM نفذ هذا الأمر: sudo /usr/bin/update-alternatives --install /usr/bin/php php /usr/bin/hhvm 60بعد ذلك يمكنك استعمال الدالة ()phpinfo من أجل إظهار إعدادات وخواص الـ HHVM، لفعل ذلك أنشئ ملفا اسمه info.php في المجلد الافتراضي لخادوم الويب Nginx والذي هو usr/share/nginx/html/ باستخدام محررك المفضل: sudo vim /usr/share/nginx/html/info.phpثم أضف فيه الأسطر التالية: <?php phpinfo(); ?>إنه من المنصوح به لدى الخبراء أن تجعل كل ملفات الويب التي يشغلها الخادوم Nginx مملوكة للمستخدم الخاص به www-data. قم بعمل ذلك بالأمر التالي: sudo chown www-data: /usr/share/nginx/html/info.phpالآن جرب الدخول إلى هذا الملف الذي أنشأته عبر هذا الرابط: http://your_server_ip/info.php. يجب عليك استبدال your_server_ip بـ IP خادومك، والنتيجة ستكون في متصفحك هكذا: إذا لم يظهر لك مثل هذه الصورة فتأكد أنك اتبعت الخطوات السابقة بطريقة صحيحة ، ثم تفقد ملف أخطاء الخادوم Nginx الذي مساره var/log/nginx/error.log/ وملف HHVM الذي مساره var/log/hhvm/error.log/. ارجع الآن إلى متصفحك وأعد النظر تر أن هذه البيانات التي أظهرتها الدالة ()phpinfo هي نفسها التي تظهر مع محركات PHP الأخرى غير أن كل المتغيرات كانت مسبوقة بـ hhvm. عند استكشاف المتغيرات ستلحظ أن الحد الأقصى للذاكرة المسموحة هو 17179869184 بايت أي ما يقارب 17 غيغابايت، وهذا بالتأكيد سوف يقتل النظام إذا كان لا يملك سوى القليل من ذاكرة الوصول العشوائي ويجعلها لا تستجيب، لذلك يجب عليك أن تخفض ذلك الحد إلى قيمة هي أقل من سعة الذاكرة العشوائية لكي نضمن أن أي خدمة أخرى لن تتأثر بنقص في موارد النظام. كمثال عام، إذا كان نظامك يملك ذاكرة بسعة 2 جيغا فإنه ينبغي عليك تخفيض الحد الأقصى لـ HHVM إلى ما يقارب 1.2 جيغا. لفعل ذلك عدّل الملف etc/hhvm/php.ini/ بمحررك المفضل: sudo vim /etc/hhvm/php.iniثم أضف المتغير الجديد بعد القسم ; php options memory_limit = 1200Mبالطريقة نفسها يمكنك تغيير أي شيء تريده في إعدادات PHP ، فقط تأكد دائما أن تعيد تشغيل HHVM بعد انتهائك من التغييرات بالأمر: sudo service hhvm restartبعد كل ذلك يمكنك إجراء اختبار أكثر تعقيدا مع تطبيق ويب مشهور. من المهم أن تعرف أن HHVM ليس متوافقا مائة بالمائة مع PHP المعتاد ولا مع جميع أطر PHP الأكثر الشعبية. وقد أظهرت اختباراتنا خلال وقت كتابة هذا المقال أن العديد من تطبيقات PHP على شبكة الإنترنت مثل ووردبريس تعمل بشكل جيد. ومع ذلك فإن أطر العمل المدعومة محدودة العدد. عندما تقوم بالاختبار مع تطبيق ويب حقيقي فإنه لا شيء يخص HHVM يجب فعله، التثبيت والإعدادات هي نفسها كما هو الشأن في LEMP القياسية، وذلك لأن HHVM تأتي مجمعة بوحدات PHP القياسية ، وذلك يجعلها أكثر توافقية مع تطبيقات وأطر PHP. مع ذلك وفي بعض الحالات النادرة قد تحتاج لتثبيت وحدة إضافية لـ HHVM. على سبيل المثال إذا كنت تستخدم PostgreSQL بمثابة خادوم قاعدة البيانات فسوف تحتاج إلى وحدة pgsql. في مثل هذه الحالات راجع الوثائق الرسمية لـ HHVM. الخلاصةكما رأيت في هذا المقال فإن HHVM سهلٌ تثبيتها سهل إعدادها سهل دمجها مع خادوم الويب Nginx. فإن كان لديك ما يكفي من الموارد فينبغي أن تجربها ثم ترى كيف يعمل منهج JIT الذي تتبعه HHVM من حيث الأداء والاستقرار. لابد من سبب وجيه لموقع مثل فايس بوك بوظائفه المعقدة وحركة بيانات لا مثيل لها أن تثق به. وأما المواقع الصغيرة التي لها حركة بيانات أقل فأولى لها أن تختار حلولا أقل استهلاكا للذاكرة مثل PHP-FPM، فإنه بالتأكيد أفضل خيار. مقال مترجم من How To Install HHVM with Nginx on Ubuntu 14.04 للكاتب Anatoliy Dimitrov.
  23. من المهم عند العمل على خادوم ويب تنفيذ تدابير أمنيّة لحماية موقعنا ومستخدمينا، إنّ حماية مواقع الإنترنت والتّطبيقات لدينا باستخدام سياسات الجّدار النّاري firewall policies وتقييد الوصول إلى بعض المناطق باستخدام استيثاق كلمة السّر password authentication هو نقطة بدء رائعة لتأمين النظام لدينا، ومع ذلك من المُرجَّح أن يجذب أي طلب لكلمة السّر مُتاح للعوام محاولات القوة القاسية brute force من قبل المستخدمين والروبوتات bots الخبيثين. يتمكّن إعداد fail2ban من المساعدة في الحد من هذه المشكلة، فعندما يفشل المستخدمون بالاستيثاق إلى خدمة ما بشكلٍ متكرّر (أو الانخراط في أي نشاط مشبوه آخر) تستطيع fail2ban أن تصدر حظرًا مؤقّتًا على عنوان IP المُهاجِم عن طريق التّعديل بشكل ديناميكي على سياسة الجّدار النّاري التي تعمل حاليًّا. تعمل كل "jail" تابعة لـ fail2ban عن طريق تفحّص السّجلّات المكتوبة من قبل خدمة ما بحثًا عن أنماط patterns تُشير إلى محاولات فاشلة بالاستيثاق. من السّهل إلى حدٍّ ما إعداد fail2ban لكي تراقب سجلّات Nginx باستخدام البعض من مُرشّحات filters الإعداد المُضمَّنة والبعض الآخر الذي سنقوم بكتابته بأنفسنا. سنشرح في هذا الدّرس كيفيّة تثبيت fail2ban وإعدادها لمراقبة سجلّات Nginx بحثًا عن محاولات التّسلّل، سنستخدم خادوم Ubuntu من أجل هذا. المتطلبات الأساسيةينبغي قبل أن نبدأ أن نمتلك خادوم Ubuntu مع إعداد حساب غير جذري non-root، ويجب أن يكون هذا الحساب مُعدًّا بامتيازات sudo من أجل إصدار أوامر إداريّة administrative commands. لكي تتعلّم كيفيّة إعداد مستخدم بامتيازات sudo اتبع دليلنا للإعداد الأولي لخادوم Ubuntu 14.04. تثبيت Nginx وإعداد استيثاق كلمة السرإن كنتَ مهتمًّا بحماية خادوم Nginx باستخدام fail2ban فمن الغالب أنك تملك مسبقًا خادومًا مُعدًّا وقيد التشغيل، وإن لم تكن كذلك تستطيع تثبيت Nginx من خلال مستودعات Ubuntu الافتراضيّة باستخدام apt. فلنقم بتحديث دليل الحِزَم المحلّي وتثبيت Nginx بكتابة ما يلي: sudo apt-get update sudo apt-get install nginxإنّ خدمة fail2ban مفيدة من أجل حماية نقاط تسجيل الدخول، ومن أجل أن يكون هذا مفيدًا لتثبيت Nginx يجب تنفيذ استيثاق كلمة السّر على الأقل لمجموعة فرعيّة من المحتوى على الخادوم، تستطيع اتباع هذا الدّليل لإعداد حماية كلمة السّر من أجل خادوم Nginx لديك. تثبيت Fail2Banبعد أن أصبح خادوم Nginx لدينا قيد التّشغيل وتمّ تمكين استيثاق كلمة السّر عليه نستطيع المضي قدمًا وتثبيت fail2ban (نقوم هنا بإدراج إعادة جلب للمستودع مرّة أخرى في حال قمتَ بالفعل بتثبيت Nginx في الخطوات السّابقة): sudo apt-get update sudo apt-get install fail2banسيقوم هذا بتثبيت برمجيّة fail2ban، والتي هي مُعدَّة افتراضيًّا لكي تحظر فقط محاولات تسجيل دخول SSH الفاشلة، نحتاج إلى تمكين بعض القواعد التي تقوم بإعدادها لكي تتفحّص سجلّات Nginx لدينا بحثًا عن أنماط تشير إلى نشاط خبيث. ضبط الإعدادات العامة داخل Fail2Banنحتاج لكي نبدأ إلى ضبط ملف الإعدادات الذي تستخدمه fail2ban لتحديد سجلّات التطبيقات التي يجب أن تراقبها والإجراءات التي يجب أن يتمّ اتخاذها عند إيجاد مُدخلات مُخالِفة، ومن الموارد الرئيسيّة التي يتم تزويدنا بها لهذا الأمر نجد الملف etc/fail2ban/jail.conf/. ولإجراء التعديلات نحتاج إلى نسخ هذا الملف إلى etc/fail2ban/jail.local/، وهذا يمنع الكتابة فوق التغييرات التي أجريناها إن قام تحديث الحِزمة package بتزويدنا بملف جديد افتراضي: sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.localنقوم بفتح الملف الجديد المنسوخ حتى نستطيع إعداد مراقبة سجلّات Nginx لدينا: sudo nano /etc/fail2ban/jail.localتغيير الإعدادات الافتراضيةينبغي أن نبدأ بتقييم المجموعة الافتراضيّة داخل الملف لنرى إن كانت تُلائِم احتياجاتنا، نستطيع إيجاد هذه المجموعة تحت قسم [DEFAULT] داخل الملف. تقوم هذه العناصر بتعيين السّياسة policy العامّة وبإمكاننا تجاوز أي منها في jails مُحدّدة. ومن أوائل العناصر التي يجب أن ننظر إليها هي قائمة العُمَلاء Clients التي لا تخضع لسياسات fail2ban، ويتم تعيينها باستخدام الأمر التّوجيهي ignoreip، من الجّيد أحيانًا إضافة عنوان IP الخاص بنا أو بشبكتنا إلى قائمة الاستثناءات لتجنّب حظر أنفسنا، على الرّغم من أنّ هذا أقل من أن يكون مشكلة مع تسجيلات الدّخول إلى خادوم الويب إن كان بإمكاننا المحافظة على النفاذ للـ Shell، حيث أنّنا دائمًا نستطيع إلغاء الحظر يدويًّا. نستطيع إضافة عناوين IP أو شبكات إضافيّة بفصلها بمسافة Space إلى القائمة الحاليّة: etc/fail2ban/jail.local/ [DEFAULT] . . . ignoreip = 127.0.0.1/8 your_home_IPومن العناصر الأخرى التي قد نرغب بضبطها نجد bantime والذي يتحكّم بعدد الثّواني التي سيتم خلالها حظر العضو المُخالِف، من المثالي تعيينه إلى مدّة طويلة كافية لتكون مُدمِّرة لجهود المستخدم الخبيث، وفي نفس الوقت قصيرة بما فيه الكفاية لتسمح للمستخدمين الشرعيّين لتصحيح أخطائهم، يتم تعيين هذه القيمة افتراضيًّا إلى 600 ثانية (10 دقائق)، قم بزيادتها أو إنقاصها على النحو الذي تراه مناسبًا: etc/fail2ban/jail.local/ [DEFAULT] . . . bantime = 3600يُحدّد العنصران التّاليان نطاق أسطر السّجلّات المستخدمة لتحديد العميل المُخالِف، يُحدِّد findtime المدّة الزمنية مُقدّرةً بالثواني ويُشير الأمر التّوجيهي maxretry إلى عدد المحاولات التي يتم التسامح معها خلال تلك المدّة، فإن قام العميل بعدد محاولات أكثر من maxretry خلال المدّة الزمنيّة المُحدّدة بواسطة findtime فسيتمّ حظره: etc/fail2ban/jail.local/ [DEFAULT] . . . findtime = 3600 # These lines combine to ban clients that fail maxretry = 6 # to authenticate 6 times within a half hourإعداد تنبيهات البريد الإلكتروني (اختياري)نستطيع تمكين تنبيهات البريد الإلكتروني إن كُنّا نرغب باستقبال بريد كلّما حدث حظر، ويتوجب علينا أولًا لفعل هذا أن نقوم بإعداد MTA على خادومنا بحيث يستطيع إرسال بريد إلكتروني، لتتعلّم كيفيّة استخدام Postfix من أجل هذه المهمّة اتبع هذا الدّليل. ويتوجّب علينا بعد الانتهاء من إعداد MTA أن نقوم بضبط بعض الإعدادات الإضافيّة داخل القسم [DEFAULT] من الملف etc/fail2ban/jail.local/. نبدأ بإعداد الأمر التّوجيهي mta، فإن قمنا بإعداد Postfix -كما هو واضح في الدّرس التعليمي المذكور بالأعلى- نُغيّر هذه القيمة إلى “mail”: etc/fail2ban/jail.local/ [DEFAULT] . . . mta = mailيجب أن نختار عنوان البريد الإلكتروني الذي سيتم إرسال التنبيهات إليه ونكتبه داخل الأمر التّوجيهي destemail، بإمكاننا استخدام الأمر التّوجيهي sendername لتعديل حقل المُرسِل Sender في تنبيهات البريد الإلكتروني: etc/fail2ban/jail.local/ [DEFAULT] . . . destemail = youraccount@email.com sendername = Fail2BanAlertsإنّ الإجراء action -بحسب تعبير fail2ban- هو العمليّة التي تتلو فشل العميل بالاستيثاق مرات كثيرة، الإجراء الافتراضي (يُدعى action_) هو ببساطة حظر عنوان الـ IP من المنفذ port قيد الطلب، ويوجد على أيّة حال إجراءان آخران مُعدّان مُسبقًا يُمكن استخدامهما إن كنّا نملك إعداد بريد إلكتروني. نستطيع استخدام الإجراء action_mw لحظر العميل وإرسال تنبيه بريد إلكتروني إلى الحساب المضبوط لدينا مع تقرير “whois” حول عنوان المُخالِف، بإمكاننا أيضًا استخدام الإجراء action_mwl والذي يقوم بنفس العمل ولكن يقوم بتضمين سطور سجلّات المُخالِف والتي قامت بإطلاق عمليّة الحظر: etc/fail2ban/jail.local/ [DEFAULT] . . . action = %(action_mwl)s إعداد Fail2Ban لمراقبة سجلات Nginxبعد أن قمنا بضبط بعض إعدادات fail2ban العامّة في مكانها الصحيح نستطيع التركيز على تمكين بعض jails المرتبطة بـ Nginx والتي ستراقب سجلّات خادوم الويب لدينا بحثًا عن أنماط سلوك مُعيّن. تتميّز كل jails داخل ملف الإعدادات بترويسة header تحتوي اسم الـ jail بين قوسين مربّعين (كل قسم يشير إلى إعدادات jail مُحدّدة ما عدا القسم [DEFAULT])، وافتراضيًّا نجد ssh] jail] هي الوحيدة المُمكّنة. لتمكين مراقبة السّجلّات بحثًا عن محاولات تسجيل دخول Nginx سنقوم بتمكين [jail [nginx-http-auth، نُعدّل الأمر التّوجيهي enabled داخل هذا القسم بحيث يصبح true: etc/fail2ban/jail.local/ [nginx-http-auth] enabled = true filter = nginx-http-auth port = http,https logpath = /var/log/nginx/error.log . . .إنّ jail السّابقة هي jail الوحيدة الخاصّة بـ Nginx التي يتم تضمينها مع حزمة fail2ban الخاصّة بـ Ubuntu. نستطيع على أيّة حال إنشاء jails الخاصّة بنا لإضافة وظائف إضافيّة، نجد في هذا الرابط بعض من تفاصيل تنفيذ jails الإضافيّة هنا وهنا. بإمكاننا إنشاء nginx-noscript] jail] لحظر العملاء الذين يبحثون عن تنفيذ واستغلال Script على الموقع، إن لم نكن نستخدم PHP أو أي لغة برمجة أخرى بالتزامن مع خادوم الويب لدينا فبإمكاننا إضافة هذه الـ jail لحظر من يطلب هذا النوع من الموارد: etc/fail2ban/jail.local/ [nginx-noscript] enabled = true port = http,https filter = nginx-noscript logpath = /var/log/nginx/access.log maxretry = 6 . . .نستطيع إضافة قسم يُدعى [nginx-badbots] لإيقاف بعض أنماط طلبات الروبوتات الخبيثة المعروفة: etc/fail2ban/jail.local/ [nginx-badbots] enabled = true port = http,https filter = nginx-badbots logpath = /var/log/nginx/access.log maxretry = 2وإن لم نكن نستخدم Nginx لتزويدنا بالنفاذ إلى محتوى الويب داخل الدّليل الرئيسي Home directory للمستخدم فبإمكاننا حظر المستخدمين الذين يطلبون هذه الموارد بإضافة nginx-nohome] jail]: etc/fail2ban/jail.local/ [nginx-nohome] enabled = true port = http,https filter = nginx-nohome logpath = /var/log/nginx/access.log maxretry = 2ينبغي علينا حظر العملاء الذين يحاولون استخدام خادوم Nginx لدينا كوسيط مفتوح open proxy، نستطيع إضافة nginx-noproxy] jail] لتتناسب مع هذه الطلبات: etc/fail2ban/jail.local/ [nginx-noproxy] enabled = true port = http,https filter = nginx-noproxy logpath = /var/log/nginx/access.log maxretry = 2بعد أن ننتهي من التعديلات التي نرغب بها نحفظ الملف ونغلقه، يتوجّب علينا الآن إضافة المُرشّحات filters من أجل jails التي قمنا بإنشائها. إضافة المرشحات من أجل Nginx Jails الإضافيةلقد قمنا بتحديث الملف etc/fail2ban/jail.local/ ببعض مواصفات jail الإضافيّة لتتناسب مع حظر مدى كبير من السّلوك السّيء، نحتاج لإنشاء ملفات ترشيح filter من أجل jails التي أنشأناها، حيث تُحدّد هذه الملفات الأنماط التي سنبحث عنها داخل سجلّات Nginx. فلنبدأ بالانتقال إلى دليل المُرشّحات filters: cd /etc/fail2ban/filter.dنريد فعليًّا أن نبدأ بضبط مُرشِّح الاستيثاق المزوّد مُسبقًا مع Nginx لكي يتناسب مع أنماط فشل تسجيل الدّخول الموجودة في السّجلّات، نفتح الملف لتحريره: sudo nano nginx-http-auth.confنُضيف نمط جديد تحت التّخصيص failregex، حيث يتناسب هذا النّمط مع الأسطر التي توافق عدم إدخال المستخدم لاسم مستخدم أو كلمة سر: etc/fail2ban/filter.d/nginx-http-auth.conf/ [Definition] failregex = ^ \[error\] \d+#\d+: \*\d+ user "\S+":? (password mismatch|was not found in ".*"), client: <HOST>, server: \S+, request: "\S+ \S+ HTTP/\d+\.\d+", host: "\S+"\s*$ ^ \[error\] \d+#\d+: \*\d+ no user/password was provided for basic authentication, client: <HOST>, server: \S+, request: "\S+ \S+ HTTP/\d+\.\d+", host: "\S+"\s*$ ignoreregex =بعد الانتهاء نقوم بحفظ وإغلاق الملف. بعد ذلك نستطيع نسخ الملف apache-badbots.conf لاستخدامه مع Nginx، بإمكاننا استخدام الملف كما هو ولكن سنقوم بنسخه إلى اسم آخر من أجل التوضيح، يتطابق هذا مع مرجعيّة المُرشّح التي قمنا بها داخل إعدادات jail: sudo cp apache-badbots.conf nginx-badbots.confننشئ بعد ذلك مُرشّح من أجل nginx-noscript] jail]: sudo nano nginx-noscript.confنلصق التعريف التالي بداخله، ونترك لك الخيار في ضبط اللواحق في الـ Script لكي تزيل ملفّات لغات البرمجة التي يستخدمها الخادوم لديك بشكل شرعي أو لكي تضيف لواحق أخرى: etc/fail2ban/filter.d/nginx-noscript.conf/ [Definition] failregex = ^<HOST> -.*GET.*(\.php|\.asp|\.exe|\.pl|\.cgi|\.scgi) ignoreregex =نقوم بحفظ الملف وإغلاقه. ننشئ بعد ذلك مُرشّحًا من أجل nginx-nohome] jail]: sudo nano nginx-nohome.confنضع معلومات المرشّح التالية في الملف: etc/fail2ban/filter.d/nginx-nohome.conf/ [Definition] failregex = ^<HOST> -.*GET .*/~.* ignoreregex =بعد الانتهاء نقوم بحفظ وإغلاق الملف. بإمكاننا أخيرًا إنشاء المرشّح من أجل nginx-noproxy] jail]: sudo nano nginx-noproxy.confيتوافق تعريف المرشّح مع محاولات استخدام خادومنا كوسيط proxy: etc/fail2ban/filter.d/nginx-noproxy.conf/ [Definition] failregex = ^<HOST> -.*GET http.* ignoreregex =بعد الانتهاء نقوم بحفظ وإغلاق الملف. تفعيل Nginx Jails لدينالكي يتم تنفيذ تغييراتنا على الإعدادات نحتاج إلى إعادة تشغيل خدمة fail2ban، نستطيع فعل ذلك بكتابة ما يلي: sudo service fail2ban restartينبغي أن يتم إعادة تشغيل الخدمة وتنفيذ سياسات الحظر المختلفة التي قمنا بإعدادها. الحصول على معلومات حول Jails التي تم تمكينهانستطيع رؤية جميع jails التي تمّ تمكينها لدينا باستخدام الأمر fail2ban-client: sudo fail2ban-client statusينبغي أن نشاهد قائمة بكامل jails التي قمنا بتمكينها: Status |- Number of jail: 6 `- Jail list: nginx-noproxy, nginx-noscript, nginx-nohome, nginx-http-auth, nginx-badbots, sshنستطيع النظر إلى iptables لكي نرى أنّ fail2ban قامت بتعديل قواعد الجّدار النّاري لدينا لإنشاء إطار عمل لمنع العملاء، وحتى بدون قواعد الجّدار النّاري السابقة سيكون لدينا الآن إطار عمل مُمكّن يسمح لـ fail2ban بحظر العملاء انتقائيًّا عن طريق إضافتهم إلى سلاسل chains مبنيّة لهذا الغرض: sudo iptables -S-P INPUT ACCEPT -P FORWARD ACCEPT -P OUTPUT ACCEPT -N fail2ban-nginx-badbots -N fail2ban-nginx-http-auth -N fail2ban-nginx-nohome -N fail2ban-nginx-noproxy -N fail2ban-nginx-noscript -N fail2ban-ssh -A INPUT -p tcp -m multiport --dports 80,443 -j fail2ban-nginx-noproxy -A INPUT -p tcp -m multiport --dports 80,443 -j fail2ban-nginx-nohome -A INPUT -p tcp -m multiport --dports 80,443 -j fail2ban-nginx-badbots -A INPUT -p tcp -m multiport --dports 80,443 -j fail2ban-nginx-noscript -A INPUT -p tcp -m multiport --dports 80,443 -j fail2ban-nginx-http-auth -A INPUT -p tcp -m multiport --dports 22 -j fail2ban-ssh -A fail2ban-nginx-badbots -j RETURN -A fail2ban-nginx-http-auth -j RETURN -A fail2ban-nginx-nohome -j RETURN -A fail2ban-nginx-noproxy -j RETURN -A fail2ban-nginx-noscript -j RETURN -A fail2ban-ssh -j RETURNوإن أردنا رؤية تفاصيل حظر مُطبَّق من قبل أي jail فمن الأسهل ربّما استخدام الأمر fail2ban-client مرة أخرى: sudo fail2ban-client status nginx-http-authStatus for the jail: nginx-http-auth |- filter | |- File list: /var/log/nginx/error.log | |- Currently failed: 0 | `- Total failed: 0 `- action |- Currently banned: 0 | `- IP list: `- Total banned: 0اختبار سياسات Fail2Banمن الهام اختبار سياسات fail2ban لكي نتأكّد من أنها تقوم بحظر نقل البيانات كما هو متوقّع، على سبيل المثال نستطيع إعطاء بيانات خاطئة في مُحث prompt استيثاق Nginx عدّة مرات، وبعد أن نتجاوز الحدّ ينبغي أن يتم حظرنا وألا نكون قادرين على الوصول للموقع، وإن قمنا بإعداد تنبيهات البريد الإلكتروني فيجب أن نرى رسائل حول الحظر في البريد الإلكتروني الذي قمنا باختياره لاستقبال التّنبيهات. عندما ننظر إلى الحالة باستخدام الأمر fail2ban-client سنشاهد أنّ عنوان IP الخاص بنا يتم حظره من الموقع: sudo fail2ban-client status nginx-http-auth Status for the jail: nginx-http-auth |- filter | |- File list: /var/log/nginx/error.log | |- Currently failed: 0 | `- Total failed: 12 `- action |- Currently banned: 1 | `- IP list: 111.111.111.111 `- Total banned: 1وعندما نكون مقتنعين بأنّ قواعدنا تعمل بشكل صحيح نستطيع فك الحظر يدويًّا عن عنوان IP الخاص بنا عن طريق الأمر fail2ban-client بكتابة ما يلي: sudo fail2ban-client set nginx-http-auth unbanip 111.111.111.111 نبغي أن نكون الآن قادرين على محاولة الاستيثاق مرة أخرى. الخاتمةإنّ إعداد fail2ban لحماية خادوم Nginx لدينا هو عمليّة سهلة إلى حدٍّ ما في أبسط الحالات، توفّر fail2ban على أيّة حال قدرًا كبيرًا من المرونة لبناء سياسات تُلائِم احتياجاتنا الأمنيّة، وبإلقاء نظرة على المتغيّرات والأنماط داخل الملف etc/fail2ban/jail.local/ والملفات التي يعتمد عليها داخل الدّليل etc/fail2ban/filter.d/ والدّليل etc/fail2ban/action.d/ نجد العديد من الأجزاء التي يمكننا تطويعها tweak وتغييرها لكي تلبّي احتياجاتنا، إنّ تعلّم أساسيّات كيفيّة حماية خادومنا باستخدام fail2ban يزوّدنا بقدرٍ كبير من الأمان وبأقل جهد. إن كنت ترغب في تعلّم المزيد حول fail2ban قم بزيارة الروابط التالية: كيف تعمل Fail2Ban لحماية الخدمات على خادوم لينِكس.كيفيّة حماية SSH باستخدام Fail2Ban على Ubuntu 14.04.ترجمة -وبتصرّف- لـ How To Protect an Nginx Server with Fail2Ban on Ubuntu 14.04 لصاحبه Justin Ellingwood.
  24. TLS، أو حماية طبقة النقل (Transport Layer Security)، وسلفها SSL أو طبقة الحِزَم الآمنة (Secure Sockets Layer) هما عبارة عن بروتوكولات آمنة يتم إنشاؤها بهدف توجيه تدفّق البيانات العادية (traffic) ضمن طريق مشفّر وآمن أثناء تنقّلها، وقد قمنا سابقا بشرح كيفية إعداد SSL على خادوم Apache، سنقوم في هذا الدرس بشرح كيفية إعداده مع خادوم nginx. باستخدام هذه التكنولوجيا، يمكن للخواديم أن تقوم بإرسال تدفّق البيانات بشكل آمن بينها وبين الزائر دون الحاجة إلى القلق بخصوص وجود إمكانية لاعتراض تدفّق البيانات بينها وقراءتها بواسطة شخص ما من الخارج. يساعد نظام الشهادات المستخدمين على التحقق من هوية المواقع التي يزورونها أيضًا. في هذا الدرس، سنشرح كيفيّة إنشاء شهادة SSL موقّعة ذاتيًا لخادوم Nginx على Ubuntu 14.04، لن تسمح الشهادة الموقّعة ذاتيًا لمستخدميك من أن يتحققوا من هوية موقعك بما أنّها ليست موقّعة بواسطة واحدة من الجهات التي يثق بها متصفّحك، ولكنّها ستسمح لك بتشفير الاتصالات مع زوّارك. المتطلباتقبل أن تبدأ، يجب أن تهتم ببعض الإعدادات بالطبع. سنستخدم مستخدمًا غير مستخدم الجذر مع صلاحيات sudo في هذا الدرس. يمكنك إعداد واحد عبر اتباع الخطوات المذكورة في درسنا حول إعداد خادوم أوبونتو 14.04 الابتدائي. ستحتاج أيضًا إلى تثبيت خادوم Nginx. إذا كنت تريد إعداد خادوم LEMP كامل (Linux, Nginx, MySQL, PHP) فإنّه يمكنك مراجعة درسنا حول تثبيت LEMP على أوبونتو 14.04. إذا كنت تريد خادوم Nginx فقط، فيمكنك تثبيته بواسطة: sudo apt-get update sudo apt-get install nginxالخطوة الأولى: إنشاء شهادة SSLفلنبدأ عبر إنشاء مسار فرعي ضمن مجلّد إعدادات خادوم Nginx لنضع ملفّات الشهادة التي سنقوم بإنشائها فيه: sudo mkdir /etc/nginx/sslوالآن وبعد أن قمنا بإنشاء ذلك المسار، يمكننا أن نقوم بإنشاء تلك الملفّات بأمر واحد وهو: sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crtسيتم سؤالك عدّة أسئلة. قبل أن نتعرّف عليها، فلنتعرّف على ما يعنيه الأمر السابق: openssl: هذا هو الأمر الأساسي الذي يتم توفيره بواسطة OpenSSL لإنشاء وإدارة الشهادات، المفاتيح وطلبات التوقيع.. إلخ.req: يحدد هذا الأمر الفرعي أننا نريد استخدام إدارة طلبات توقيع الشهادة X.509. X.509 هو عبارة عن معيار بنية تحتية للمفتاح العمومي يحتاجه كلٌّ من SSL وTLS لإدار الشهادات. نريد أن نقوم بإنشاء شهادة X.509 جديدة، ولذلك فإننا سنستخدم هذا الأمر الفرعي.x509-: يقوم هذا أيضًا بتعديل الأمر السابق عبر إخبار الأداة أننا نريد إنشاء شهادة موقّعة ذاتيًا عوضًا عن إنشاء طلب توقيع شهادة، والذي كان ليحدث بالحالة العادية.nodes-: يخبر هذا الخيار OpenSSL بأننا لا نريد تأمين ملفّ المفتاح الخاصّ بنا بجملة مرور، لأنّ استخدام هذا الخيار سيعترض طريق خادوم nginx عندما يتم تشغيله تلقائيًا حيث أنّه يجب علينا إدخال جملة المرور في كلّ مرّة يبدأ فيها الخادوم وفي كلّ مرّة يتم فيها إعادة تشغيله.days 365-: يحدد هذا أنّ الشهادة التي سنقوم بإنشائها صالحة لمدّة 365 يومًا.newkey rsa:2048-: سينشئ هذا الخيار طلب الشهادة ومفتاحًا خاصًّا جديدًا في الوقت ذاته. هذا ضروري جدًا بما أننا لم نقم بإنشاء مفتاح خاصّ مسبقًا. يقوم rsa:2048 بإخبار OpenSSL بأن يقوم بتوليد مفتاح RSA بطول 2048 بت.keyout-: يسمّي هذا المُعامِل الملفّ الناتج لملفّ المفتاح الخاصّ الذي يتم إنشاؤه.out-: يسمّي هذا الخيار ملفّ الشهادة الناتج الذي نقوم بإنشائه.كما وضّحنا أعلاه، ستقوم هذه الخيارات بإنشاء ملفّ مفتاح وشهادة. سيتم سؤالنا بضع أسئلة عن خادومنا بهدف تضمين المعلومات بشكل صحيح في تلك الشهادة. قم بكتابة الأجوبة بشكل صحيح، أهمّ واحد منها هو جواب ذاك السؤال الذي يسألك عن: "Common Name (e.g. server FQDN or YOUR name)". يجب أن تقوم بإدخال اسم نطاقك الذي تريد استخدامه مع خادومك، أو عنوان الـIP العام إذا كنتَ لا تمتلك نطاقًا بعد. أجوبة الأسئلة ستبدو شيئًا كهذا: Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:New York Locality Name (eg, city) []:New York City Organization Name (eg, company) [Internet Widgits Pty Ltd]:Bouncy Castles, Inc. Organizational Unit Name (eg, section) []:Ministry of Water Slides Common Name (e.g. server FQDN or YOUR name) []:your_domain.com Email Address []:admin@your_domain.comسيتم إنشاء الشهادة والمفتاح في مسار etc/nginx/ssl/. الخطوة الثانية: إعداد Nginx ليستخدم SSLالآن وبعد أن أصبح ملفّا الشهادة والمفتاح متوفّرين في مسار إعدادات Nginx، نحتاج الآن فقط إلى تعديل إعدادات خادوم Nginx الخاصّة بنا ليستفيد من التغييرات الجديدة. يمكنك تعلّم المزيد عن إعدادات خادوم Nginx من خلال قراءة تصنيف nginx على أكاديمية حسوب. يستطيع الإصدار 0.7.14 والأعلى منه من Nginx (تأتي أوبونتو 14.04 بالإصدار 1.4.6) أن يقوم بتفعيل SSL في نفس كتلة الخادوم (Server Block) كتدفّق HTTP عادي. يسمح لنا هذا بإعداد الوصول إلى نفس الموقع بطريقةٍ مختصرة بشكل أكبر. قد تبدو إعدادات الخادوم الخاصّة بك كالتالي: server { listen 80 default_server; listen [::]:80 default_server ipv6only=on; root /usr/share/nginx/html; index index.html index.htm; server_name your_domain.com; location / { try_files $uri $uri/ =404; } }الشيء الوحيد الذي يجب علينا فعله لنجعل SSL تعمل على نفس الخادوم مع السماح باتصالات HTTP العادية هو إضافة السطور التالية: server { listen 80 default_server; listen [::]:80 default_server ipv6only=on; listen 443 ssl; root /usr/share/nginx/html; index index.html index.htm; server_name your_domain.com; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; location / { try_files $uri $uri/ =404; } }عندما تنتهي، احفظ الملفّ وأغلقه. الآن ستحتاج إلى إعادة تشغيل خادوم Nginx فقط لكي تأخذ التغييرات مجراها: sudo service nginx restartسيقوم هذا بإعادة تحميل إعدادات موقعك، وسيصبح قادرًا على الاستجابة إلى كل من طلبات HTTP وHTTPS. الخطوة الرابعة: اختبر إعداداتكيجب الآن أن تعمل وظيفة SSL بشكلٍ جيّد معك، ولكن يجب علينا اختبارها لنتأكّد من ذلك. أولًا، دعنا نتحقق أنّه ما يزال بإمكاننا الوصول إلى الموقع عبر بروتوكول HTTP العادي. في متصفّحك، قم بزيارة اسم نطاق الخادوم الخاصّ بك أو عنوان الـIP: http://اسم_النطاق_أو_عنوان_الآي_بييجب أن ترى الموقع العادي. في حالتي، سأرى رسالة Nginx الافتراضية فقط: إذا وصلت إلى هذه الصفحة، فهذا يعني أنّ خادومك ما يزال يخدم طلبات HTTP بشكل صحيح. الآن يمكننا التحقق مما إذا كان خادومنا قادرًا على استخدام SSL للتواصل أم لا. قم بذلك عبر كتابة بروتوكول https عوضًا عن http: https://اسم_النطاق_أو_عنوان_الآي_بيسترى رسالة تنبيه أن متصفّحك لم يتمكّن من التحقق من هوية خادومك لأنّه لم يتم توقيع الشهادة الخاصّة به من قبل جهة من الجهات التي يثق بها ذلك المتصفّح. هذه رسالة متوقّعة بمّا أنّ شهادتنا هي شهادة موقّعة ذاتيًا (self-signed). صحيح أّنّه لن يكون من الممكن استخدام شهادتنا للتحقق من هوية خادومنا، إلّا أنّ الخادوم سيزال قادرا على التواصل المشفّر. بمّا أنّ هذه الرسالة هي رسالة متوقّعة، فيمكنك الضغط على زرّ "المتابعة على كلّ حال" أو "Proceed anyway" أو أيّ خيار مشابه تجده أمامك للمتابعة. يجب أن ترى صفحة موقعك مجددًا: قد يظهر لك متصفّحك اسم بروتوكول "https" مشطوبًا في شريط العنوان أو محطّمًا أو بجانبه إشارة قفل مشطوبة. إذا ضغطت على أيقونة القفل، ستجد بعض المعلومات عن الاتصال: كما يمكنك أن ترى، المشكلة هي أنّ المتصفّح غير قادر على التحقق من هوية الخادوم بسبب أنّ شهادته ليست موقّعة من جهة إصدارات شهادات موثوقة بالنسبة إلى المتصفّح لا أكثر. يُظهر لك القسم الذي بالمنتصف أنّ الاتصال مشفّر، وهذا يعني أننا حققنا هدفنا على كلّ حال. الخاتمةلقد قمتَ الآن بإعداد خادوم Nginx الخاصّ بك ليعالج كلًّا من طلبات HTTP وSSL. سيساعدك هذا على التواصل مع زوّارك بشكل أأمن بالإضافة إلى جعل الجهات الخارجية غير قادرة على قراءة تدفّق البيانات الخاصّ بك. إذا كنتَ تخطط لإطلاق موقعٍ للعموم وتحتاج SSL، فإنّه يجب عليك شراء شهادة SSL من جهة شهادات موثوقة لموقعك لتجنّب ظهور رسالة التحذير الصفراء لزوّاك موقعك. ترجمة -وبتصرف- للمقال: How To Create an SSL Certificate on Nginx for Ubuntu 14.04 لصاحبه: Justin Ellingwood. حقوق الصورة البارزة: Designed by Freepik.
  25. لقد أصبح Nginx أحد أكثر التطبيقات البرمجية المتوفرة لخواديم الويب Web Servers مرونةً وقوة. ولكن إذا ما نظرنا إليه من الناحية التصميمية فإنه يعد أولًا وقبل كل شيء خادومًا وسيطا Proxy Server. إن التركيز على أداء Nginx كوسيط يعني أنه ذو أداء عالي عندما يعمل على معالجة الطلبات بالتعاون مع خواديم أخرى. يمكن لـ Nginx أن يلعب دور الوسيط باستخدام بروتوكولات Protocols http ,FastCGI ,uwsgi ,SCGI ,memcached. سنناقش في هذه المقالة استخدام FastCGI للقيام بالوساطة proxying، فهو يعد واحدًا من أكثر البرتوكولات التي تُستخدم لذلك الغرض. لماذا نستخدم FastCGI للقيام بالوساطة؟يستخدم FastCGI للقيام بالوساطة ضمن Nginx كي يترجم طلبات المستخدمين Clients لخادوم التطبيقات Application Server الذي لا يقوم بمعالجة طلبات المستخدمين مباشرةً أو الذي لا ينبغي له ذلك. إنّ FastCGI هو برتوكول مبني على برتوكول Common Gateway Interface الأقدم والذي يشار إليه اختصارًا CGI، وقد أُريد من بروتوكول FastCGI أن يحسّن أداء البروتوكول السابق عبر عدم معالجة كل طلب في عملية Process خاصة به. يُستخدم البرتوكول ليمثّل واجهة interface ذات فعالية أكبر مع الخواديم التي تعالج طلبات المحتوى الديناميكي. إن معالجة PHP هي أحد حالات الاستخدام use-case الرئيسية لبرتوكول FastCGI ضمن Nginx. وعلى عكس أباتشي Apache، الذي يستطيع معالجة PHP مباشرةً باستخدام وحدة mod_php، فإنه ينبغي على Nginx الاعتماد على معالج PHP منفصل لمعالجة طلبات PHP. غالبًا ما تُنجز تلك المعالجة باستخدام php_fpm وهو معالج PHP قد اختبر بشكل كبير للعمل مع Nginx. يمكن أن يُستخدم Nginx مع FastCGI للعمل مع تطبيقات تستخدم لغاتٍ أخرى طالما أنه يتوفر مكونات مهيّأة للاستجابة لطلبات FastCGI. أسياسيات قيام FastCGI بالوساطةعادةً ما تتضمن طلبات الوساطة proxying requests عنوان الخادوم الوسيط- Nginx في حالتنا- الذي يوجّه الطلبات من قبل المستخدمين إلى الخادوم الوسيط بينه (الخلفي) Backend Server. يستخدم Nginx التعليمة fastcgi_pass للتعريف عن الخادوم الفعلي الذي ستوجّه إليه الطلبات باستخدام برتوكول FastCGI. فمثلًا، لتوجيه أي طلب موافق للغة PHP إلى الخادوم الخلفي المخصص لمعالجة PHP باستخدام برتوكول FastCGI، فقد يبدو المقطع البرمجي للموقع Location Block مشابهًا لما يلي: # server context location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; } . . . في الواقع، لن يعمل المقطع السابق إذا ما تم تنفيذه على حاله لأنه يقدّم معلوماتٍ قليلةً جدًا. في كل مرّة يتم فيها إنشاء اتصال وسيط Proxy Connection فإنه يجب ترجمة الطلب الأصلي لضمان أن يتمكن الخادوم الخلفي من فهم الطلب المُدار Proxied request. وباعتبار أننا نغيّر البرتوكولات بتمرير الطلب عبر FastCGI فإن ذلك يتطلب بعض العمل الإضافي، سنصطلح في هذه المقالة على عملية تمرير الطلبات عبر FastCGI بتمرير FastCGI أي FastCGI pass. إنّ القيام بالوساطة من بروتوكول Http وإليه http-to-http Proxying ينطوي بشكل رئيسي على زيادة حجم الترويسة Header ليضمن أن يمتلك الخادوم الخلفي المعلومات التي يحتاجها للرد على الخادوم الوسيط والذي ينوب بدوره عن المستخدم Client، أما FastCGI فهو برتوكول منفصل لا يستطيع قراءة ترويسات Http. مع أخذ ذلك بالحسبان فإن أية معلومات ذات صلة يجب أن تمرّر للخادوم الخلفي عبر وسيلة أخرى. إن الطريقة الأساسية لتمرير المعلومات الإضافية عند استخدام برتوكول FastCGI هي باستخدام الإعدادات Parameters. حيث يجب أن يُهيّئ الخادوم الخلفي لقراءة تلك الإعدادات ومعالجتها والتصرّف وفقًا لقيمها. يستطيع Nginx أن يحدّد إعدادات FastCGI باستخدام التعليمة fastcgi_param. إن الحد الأدنى للإعدادات الواجب ضبطها حتى يعمل FastCGI كوكيل PHP مشابهة لما يلي: # server context location ~ \.php$ { fastcgi_param REQUEST_METHOD $request_method; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass 127.0.0.1:9000; } . . . لقد قمنا في الإعدادات السابقة بضبط إعدادات FastCGI وهما REQUEST_METHOD و SCRIPT_FILENAME. إن كل من الإعدادات السابقة ضرورية للخادوم الخلفي حتى يتمكن من فهم طبيعة الطلب. إذ أن الإعداد الأول يخبره بنوع العملية التي يجب أن يقوم بإنجازها، أما الإعداد الثاني فيخبر مجموعة الخواديم Upstream - التي تعالج طلبات الخادوم الوسيط- بالملف الذي يجب أن ينفّذه. استخدمنا في المثال بعض المتغيرات variables في Nginx لضبط قيم تلك الإعدادات. سيحوي المتغير request_method$ على نوع الوظيفة http method التي طلبها المستخدم. من ناحية أخرى فإن قيمة الإعداد SCRIPT_FILENAME هي عبارة عن دمج قيمتي المتغيرين document_root$ و fastcgi_script_name$. أما المتغير document_root$ فسيحوي على مسار المجلد الرئيسي والذي ضبط عبر التعليمة root. سيضبط المتغير fastcgi_script_name$ بمعرف الموارد الموحد URI المطلوب. إن انتهى معرف URI للطلب request URI بالرمز (/)، فستلحق قيمة التعليمة fastcgi_index في النهاية. إن هذا النوع من المرجعية الذاتية self-referential في تعريف الموقع ممكن لأننا نشغّل معالج FastCGI على نفس الجهاز الذي يشغّل Nginx. فلنلقي نظرة على مثال آخر: # server context root /var/www/html; location /scripts { fastcgi_param REQUEST_METHOD $request_method; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_index index.php; fastcgi_pass unix:/var/run/php5-fpm.sock; } . . .إن اختير الموقع location في المثال السابق ليعالج طلبًا في المسار: /scripts/test/ فإن قيمة المسار الوسيط SCRIPT_FILENAME ستنتج عن دمج قيم تعليمة root ومعرّف URI للطلب بالإضافة للتعليمة fastcgi_index. وبالتالي ستكون قيمة الإعداد في مثالنا هذا هي: var/www/html/scripts/test/index.php/ هنالك تعديل هام آخر قمنا به في الإعدادات السابقة، إذ أننا ضبطنا خادوم FastCGI الخلفي FastCGI backend ليستخدم مقبس يونيكس Unix Socket عوضًا عن مقبس شبكة Network socket. يمكن لـ Nginx أن يستخدم أيًا من الواجهتين Interface ليتصل مع مجموعة خواديم FastCGI Upstream. إن كان معالج FastCGI يعمل على نفس الخادوم فعادةً ما يُستحسن استخدام مقبس يونيكس من أجل الأمان. شرح إعدادات FastCGIهنالك قاعدة أساسية لكتابة نص برمجي (كود) Code قابل للصيانة وهي محاولة اتباع مبدأ DRY أي لا تكرر نفسك "Don’t Repeat Yourself". يساعد ذلك في تقليل الأخطاء بالإضافة لجعل الكود قابلًا لإعادة الاستخدام كما أنها تتيح تنظيمًا أفضل. إنّ أحد أكثر التوصيات الأساسية لإدارة Nginx هي أن تُضبط كل الأوامر في أوسع مجال ممكن لها، تطبّق تلك الأهداف الأساسية على إعداداتNginx أيضًا. عند التعامل مع إعدادات الوسيط لـ FastCGI فسيتم تشارك الغالبية العظمى للإعدادات في معظم حالات الاستخدام. بسبب ذلك وبسبب الطريقة التي تعمل بها وحدة الوراثة inheritance التابعة لـ Nginx فإنه دائمًا ما يستحسن تعريف الوسطاء في مجال عام. التصريح عن تفاصيل إعدادات FastCGI في السياقات الأم Parent Contextsإن أحد الطرق لتقليل التكرار هو التصريح عن تفاصيل الإعدادات في السياق الأم، أي سياق أعلى. يمكن لكل الإعدادات الموجودة خارج التعليمة fastcgi_pass أن تُضبط في مستويات أعلى. إذ أنها ستتدفق للأسفل نحو الموقع الذي تم منه تمرير الإعداد. وذلك يعني أنّه يمكن لعدّة أماكن أن تستخدم نفس الإعدادات. فمثلًا، يمكننا أن نعدّل على القسم العلوي من المقطع البرمجي السابق لجعله مفيدًا في عدة مواقع: # server context root /var/www/html; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_index index.php; location /scripts { fastcgi_pass unix:/var/run/php5-fpm.sock; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; } . . .إنّ كلًا من تصاريح fastcgi_param والتعليمة fastcgi_index في المثال السابق متوفرين لدى مقطعي الموقع location block الواردين لاحقًا. تلك هي إحدى الطرق لإزالة التكرار. بكل الأحوال، إن للإعدادات السابقة مساوئ كبيرة، إن صُرّح عن أية fastcgi_param ضمن سياق أدنى فلن تتم وراثة أيٍّ من قيم fastcgi_param ضمن السياقات العليا (السياقات الأم). أي إما أن تستخدم القيم الموروثة فقط أو لا تستخدم أيًا منها. تُعد التعليمة fastcgi_param مصفوفةً array من التعليمات في لغةNginx. من منظور المستخدمين فإن أي مصفوفة تعليمات هي بشكل أساسي تعليمة يمكن استخدامها أكثر من مرة ضمن سياق واحد. وأي تصريح لاحق سيضيف معلومات جديدة إلى ما يعرفه Nginx من التصريح السابق. لقد صمّمت التعليمة fastcgi_param كمصفوفة من التعليمات حتى تسمح للمستخدمين بضبط عدّة إعدادات. تورّث أي مصفوفة تعليمات إلى سياق أدنى، أو سياق ابن child context، بطريقة مختلفة عن بعض التعليمات الأخرى. ستورّث معلومات مصفوفة التعليمات إلى سياقات الأبناء فقط إن لم تكن موجودة في أي مكان ضمن سياق الابن. وذلك يعني أنك إن استخدمت تعليمة fastcgi_param ضمن موقعك فإنها ستمحي القيم الموروثة من السياق الأعلى تمامًا. فمثلًا، يمكننا التعديل قليلًا على الإعدادات السابقة كما يلي: # server context root /var/www/html; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_index index.php; location /scripts { fastcgi_pass unix:/var/run/php5-fpm.sock; } location ~ \.php$ { fastcgi_param QUERY_STRING $query_string; fastcgi_pass 127.0.0.1:9000; } . . .قد تعتقد للوهلة الأولى أنه ستتم وراثة الإعدادات REQUEST_METHOD و SCRIPT_FILENAME في مقطع لموقع ثانٍ، بالإضافة لتوفير الإعداد QUERY_STRING ضمن ذلك السياق المحدّد. لكن ما يحدث في الحقيقة هو أنّ كل قيم fastcgi_param التابعة للأب ستُمحى ضمن السياق الثاني، وسيضبط الإعداد QUERY_STRING فقط. بينما ستبقى الإعدادات REQUEST_METHOD و SCRIPT_FILE دون ضبط. ملاحظة حول القيم المتعدّدة للوسطاء ضمن نفس السياقيجدر بالذكر هنا أثار ضبط قيم متعدّدة لنفس الإعدادات ضمن سياق واحد. فلنأخذ المثال التالي لمناقشة ذلك: # server context location ~ \.php$ { fastcgi_param REQUEST_METHOD $request_method; fastcgi_param SCRIPT_FILENAME $request_uri; fastcgi_param DOCUMENT_ROOT initial; fastcgi_param DOCUMENT_ROOT override; fastcgi_param TEST one; fastcgi_param TEST two; fastcgi_param TEST three; fastcgi_pass 127.0.0.1:9000; } . . .في المثال السابق، قمنا بضبط الإعدادات TEST و DOCUMENT_ROOT عدّة مرات ضمن سياقٍ واحد. باعتبار أن fastcgi_param مصفوفة تعليمات فإن كلّ تصريح لاحق سيُضاف إلى سجلات Nginx الداخلية. سيحظى الإعداد TEST بعدة تصاريح ضمن المصفوفة يضبط من خلالها بالقيم one و two و three. من المهم أن ندرك هنا أنّ كلّ ذلك سيمرّر إلى خادوم FastCGI الخلفي دون أي معالجة إضافية من Nginx. يعني ذلك أنّ القرار حول كيفية معالجة تلك القيم يعود بشكل كامل إلى معالج Nginx المختار. للأسف، على اختلاف معالجات FastCGI فإن كلًا منها يعالج القيم الممرّرة بطريقة تختلف تمامًا عن الأخرى. فمثلًا، إن استقبلت PHP-FPM الإعدادات السابقة فستفسر القيم النهائية لتحل محل أي قيم سابقة. بهذه الحالة سيُضبط الإعداد TEST بالقيمة three. وبالمثل سيضبط الإعداد DOCUMENT_ROOT بالقيمة override. ولكن إن مُرّرت القيم السابقة لخادومٍ مثل FsgiWrap، فستفسَّر القيم بشكل مختلف كثيرًا. ففي البداية سيقوم بتمرير تمهيدي ليقرر أي القيم ينبغي استخدامها لتشغيل البريمج script. وسيستخدم القيمة initial للإعداد DOCUMENT_ROOT ليبحث عن البريمج. إلا أنه عندما سيمرّر القيم الفعلية للبريمج فسيمرر القيم الأخيرة كما يفعل PHP-FPM تمامًا. إن التضارب inconsistency وعدم إمكانية التنبؤ unpredictability يعني أنك لا تستطيع، بل أنه لا ينبغي لك، أن تعتمد على الخادوم الخلفي لتفسير نيّتك بشكل صحيح إذا ما ضبطّت الإعدادات أكثر من مرّة واحدة. فالطريقة الوحيدة الآمنة هي بالتصريح عن كل إعداد مرّةً واحدة. يعني ذلك أيضًا أنه لا يوجد طريقة آمنة لإعادة تعريف overriding القيمة الافتراضية باستخدام تعليمة fastcgi_param. طريقة تضمين إعدادات مكتوبة بملف منفصل ضمن ملف إعدادات FastCGI الأساسييوجد طريقة أخرى لتفصل بنود إعداداتك الشائعة، أي التي تقوم بها بشكل متكرّر. بإمكاننا استخدام تعليمة include لقراءة محتوى ملف منفصل وتضمينها في الموقع الذي تم فيه التصريح عن التعليمة. يعني ذلك أنه بإمكاننا الاحتفاظ بكل الإعدادات الشائعة في ملف واحد ومن ثمّ تضمينه في أي مكان ضمن إعداداتنا إن اقتضى الأمر. وباعتبار أن Nginx سيضع محتوى الملف حيثما وجدت تعليمة include فلن نكون قد ورثنا من سياق الأم إلى سياق الابن. سيمنع ذلك قيم fastcgi_param من أن تُمحى وسيمنحنا القدرة على ضبط إعدادات إضافية عند الحاجة. يمكننا في البداية أن نضبط قيم إعدادات FastCGI الشائعة لدينا في ملف منفصل وتخزينه ضمن المسار الحاوي على ملف الإعدادات الأصلي، سنقوم بتسمية ذلك الملف fastcgi_common: fastcgi_param REQUEST_METHOD $request_method; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;يمكننا الآن أن نستورد محتوى الملف حيثما نريد استخدام قيم تلك الإعدادات: # server context root /var/www/html; location /scripts { include fastcgi_common; fastcgi_index index.php; fastcgi_pass unix:/var/run/php5-fpm.sock; } location ~ \.php$ { include fastcgi_common; fastcgi_param QUERY_STRING $query_string; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_index index.php; fastcgi_pass 127.0.0.1:9000; } . . . لقد قمنا هنا بنقل قيم بعض الإعدادات الشائعة إلى ملف اسمه fastcgi_common والموجود في المسار الافتراضي الحاوي على إعدادات NGINX. ثمّ نستورد القيم المصرّح عنها في الملف عندما نحتاج لإدخالها. هنالك العديد من الأمور التي يجب ملاحظتها حول هذه الإعدادات: أولًا، لم نضع في الملف الذي ننوي استيراده أي قيم قد نرغب بتخصيصها وفقًا لموقعه، بسبب مشكلة التفسير التي ذكرناها سابقًا والتي تحدث عندما نضبط عدة قيم لنفس الإعداد، ولأنه لا يمكن ضبط التعليمات التي ليست على شكل مصفوفة non-array directives إلا مرّةً واحدة خلال السياق، لذا نضع العناصر التي لن نرغب بتغييرها فقط في الملف المشترك. إنّ كلّ تعليمة (أو إعداد أساسي) قد نرغب بتخصيصه وفقًا لموقعه يجب ألا يضمّن في الملف المشترك. الأمر الآخر الذي ربما قد لاحظته أننا قد ضبطنا بعض إعدادات FastCGI الإضافية في المقطع البرمجي للموقع الثاني. وتلك هي الإمكانية التي كنا نأمل الوصول إليها. تمكّنا من إضافة إعدادات fastcgi_param إضافية كلما اقتضت الحاجة ومن دون أن تُمسح القيم المشتركة. استخدام الملف fastcgi_params أو الملف fastcgi.confبأخذ الاستراتيجية السابقة بالحسبان فإن مطوري Nginx والعديد من فرق تحزيم التوزيعات distribution packaging teams قد عملوا على توفير مجموعة من الإعدادات شائعة الاستخدام والتي يمكن أن تضمنها في مواقع تمرير FastCGI أي FastCGI pass location. تدعى تلك الإعدادات fastcgi_params أو fastcgi.conf. إنّ هذين الملفين متشابهين كثيرًا ولكن مع وجود اختلاف وحيد ممثّل في تمرير قيم متعدّدة لإعداد واحد، وهي المشكلة التي ناقشناها سابقًا، لا يحتوي fastcgi_params على تصريح عن الإعداد SCRIPT_FILENAME على عكس الملف fastcgi.conf. لقد أوجِد الملف fastcgi_params منذ وقتٍ أبعد. ثم ظهرت الحاجة لإنشاء ملف جديد عندما اتُّخذ قرارٌ لتوفير قيمةٍ افتراضية للإعداد SCRIPT_FILENAME وذلك حتى نتجنب تجزئة الإعدادات التي تعتمد على fastcgi_params، إن عدم فعل ذلك قد يؤدي إلى ضبط ذلك الإعداد في كل من الملف المشترك وموقع تمرير FastCGI. العديد من مشرفي تحزيم التوزيعات الشهيرة قد صوّتوا لتضمين إحدى هذين الملفين فقط أو لتطابق محتواهما تمامًا. إن توفّر لديك أحد هذين الملفين فقط فاستخدمه وعدّل عليه كما تشاء ليناسب احتياجاتك. إن كان كلا الملفين متوفرين لك، فقد يكون من الأفضل أن تضمّن الملف fastcgi.conf في معظم مواقع تمرير FastCGI، وذلك لأنه يتضمّن تصريحًا عن الإعداد SCRIPT_FILENAME. عادةً ما يُرغب بذلك إلا أنّ هنالك بعض الحالات التي قد ترغب فيها بتخصص هذه القيمة. يمكن تضمين هذين الملفين عبر الإشارة إلى موقعهما بالنسبة إلى المجلد الجذر root الحاوي على إعدادات Nginx. إن مسار المجلد الجذر لإعداداتNginx يكون مشابهًا لما يلي: etc/nginx/ وذلك إن تم تثبيته باستخدام مدير الحزم package manager. يمكنك تضمين الملفين كما يلي: # server context location ~ \.php$ { include fastcgi_params; # You would use "fastcgi_param SCRIPT_FILENAME . . ." here afterwards . . . }أو كما يلي: # server context location ~ \.php$ { include fastcgi.conf; . . . }تعليمات وإعدادات ومتغيرات FastCGI المهمّةلقد قمنا في القسم السابق بضبط عدد لا بأس به من الإعدادات بهدف شرح مفاهيمٍ أخرى، وعادةً ما كنا نضبطها بمتغيرات Nginx. كما أننا قدمنا بعض تعليمات FastCGI من دون شرحٍ وفير. سنناقش في هذا القسم بعض التعليمات شائعة الضبط، وبعض الإعدادات التي قد تحتاج لتعديلها، بالإضافة لبعض المتغيرات التي قد تحوي معلوماتٍ تحتاجها. تعليمات FastCGI الشائعة:سنستعرض فيما يلي بعض أكثر التعليمات المفيدة للعمل مع تمريرات FastCGI: fastcgi_pass: هي التعليمة التي تقوم بعملية تمرير الطلبات الموجودة ضمن السياق الحالي إلى الخادوم الخلفي. تعرٍّف هذه التعليمة الموقع الذي يمكن الوصول عبره إلى معالج FastCGI.fastcgi_param: وهي مصفوفة التعليمات التي يمكن استخدامها لضبط قيم الإعدادات. غالبًا ما يقترن استخدام هذه التعليمة مع متغيرات Nginx لضبط وسطاء FastCGI بالقيم المحدّدة في الطلب.try_files: ليست تعليمةً خاصة بـ FastCGI، إلا أنها استخدامها شائع في موقع تمرير FastCGI، عادةً ما تستخدم كجزء من إجراء الطلب الوقائي للتأكد من وجود الملف المطلوب قبل تمريره إلى معالج FastCGI.include: مجدّدًا، ليست تعليمةً خاصة بـ FastCGI، إلا أنها تستخدم بكثافة عالية في سياقات تمرير FastCGI أي FastCGI pass contexts. غالبًا ما تستخدم لتضمين تفاصيل الإعدادات الشائعة والمشتركة بين عدّة مواقع.fastcgi_split_path_info: تستخدم هذه التعليمة لتعريف التعابير النمطية regular expression مع مجموعتي التقاط captured groups. تُستخدم المجموعة الأولى كقيمة للمتغير fastcgi_script_name$ بينما تستخدم المجموعة الثانية كقيمة للمتغير fastcgi_path_info$. عادةً ما تستخدم كلا المجموعتين لتحليل parse الطلب بشكل صحيح حتى يعرف المعالج أي الأجزاء المشكّلة للطلب تمثل الملفات الواجب تشغيلها وأي الأجزاء تمثل المعلومات الإضافية الواجب تمريرها إلى السكربت.fastcgi_index: تعرّف هذه التعليمة ملف الفهرسة index file الذي ينبغي الحاقه بقيمة الإعداد fastcgi_script_name$ والتي تنتهي بـ (/.عادةً ما يكون ذلك مفيدًا إن كان الإعداد SCRIPT_FILENAME مضبوطًا بقيمة document_root$fastcgi_script_name$ وكان مقطع الموقع معدّا لقبول الطلبات الحاوية على معلومات المسار الإضافية.fastcgi_intercept_errors: تعرّف هذه التعليمة فيما إذا كان ينبغي معالجة الأخطاء المتلقاة من خادوم FastCGI أو تمريرها مباشرةً إلى المستخدم.تمثّل التعليمات السابقة أكثر التعليمات التي ستستخدمها عندما تصمّم تمرير FastCGI نموذجي. ومع أنك قد لا تستخدمها كلها بنفس الوقت، إلا أنك ستلاحظ أنها تتفاعل بشكل وثيق جدًا مع إعدادات ومتغيرات FastCGI التي سنتحدث عنها فيما يلي. المتغيرات شائعة الاستخدام مع FastCGI:قبل أن نتمكن من الكلام عن الإعدادات التي ستستخدمها على الأرجح مع تمريرات FastCGI، علينا الكلام قليلًا عن بعض نتغيرات Nginx الشائعة والتي ستستفيد منها في ضبط تلك الإعدادات. تعرّف وحدة FastCGI الخاصة بـ Nginx بـ Nginx’s FastCGI module بعض تلك المتغيرات، إلا أن معظمها من الوحدة الأساسية Core module. query_string$ أو args$: هي القيم الممرّرة arguments في الطلب الأصلي للمستخدم. is_args$: ستساوي قيمتها “?” إن حوى الطلب على قيم ممرّرة وإلا فستُضبط قيمتها بسلسلة نصية فارغة. يفيد ذلك عند إنشاء إعدادات قد تأخذ قيمًا أو لا تأخذ. request_method$: يشير هذا المتغير إلى نوع الطلب request method المستخدم الأصلي. يمكن أن يفيد ذلك بتحديد فيما إذا كان ينبغي السماح لعملية operation ما في السياق الحالي أم لا. content_type$: يضبط هذا المتغير بقيمة الحقل content-type الموجود في ترويسة الطلب. يحتاج الوسيط إلى هذه المعلومات إن كان نوع الطلب المستخدم هو POST وذلك حتى يتمكن من معالجة المحتويات اللاحقة بشكل صحيح. content_length$: يضبط هذا المتغير قيمة الحقل Content-Length الموجود في ترويسة المستخدم. هذه المعلومات لازمة لأي طلب للمستخدم من النوع POST. fastcgi_script_name$: يحتوي هذا المتغير على ملف السكربت الذي يجب تشغيله. إن انتهى الطلب بـ (/) فستحلق قيمة التعليمة fastcgi_index إلى النهاية. وبحال استخدام التعليمة fast_split_path_info فستضبط قيمة هذا المتحول بالمجموعة اللاقطة الأولى المعرّفة من قبل التعليمة. ينبغي على قيمة هذا المتغير أن تشير إلى الملف الفعلي الذي يجب تشغيله. request_filename$: يحتوي هذا المتغير على مسار الملف المطلوب. يحصل المتغير على هذه القيمة بأخذ المسار الحالي لمجلد المستندات الأساسي document root، مع أخذ كل من التعليمتين root و alias بعين الاعتبار. بالإضافة لأخذ قيمة المتغير fastcgi_script_name$. تعد هذه الطريقة مرنةً للغاية لإسناد قيمة للإعداد SCRIPT_FILENAME. request_uri$: يحتوي هذا المتغير على الطلب كاملًا كما استُقبل من المستخدم، يتضمّن ذلك السكربت، أية معلومات مسار إضافية، بالإضافة إلى أي عبارة استعلام query string. fastcgi_path_info$: يحتوي هذا المتغير على معلومات المسار الإضافية التي قد تتوفّر بعد اسم السكربت في الطلب. وقد تحوي قيمته أحيانًا على موقعٍ آخر ينبغي على السكربت أن يعلم به حتى يتم تنفيذه. يحصل هذا المتغير على قيمته من مجموعة التعابير النمطية regex الثانية عند استخدام تعليمة fastcgi_split_path_info. document_root$: يحتوي هذا المتغير على المسار الحالي لمجلد المستندات الأساسي. وسيتم ضبطه تبعًا لتعليمتي root و alias. uri$: يحتوي هذا المتغير على قيمة URI الحالية بعد تسويتها normalization. وبما أن تعليمات معينة تقوم بإعادة الكتابة rewrite أو بإعادة التوجيه الداخلي internallly redirect يمكن أن تترك أثرًا على معرّف URI فإن هذا المتغير سيستخلّص تلك التعديلات. كما ترى، يوجد العديد من المتغيرات المتوفّرة لك عندما تقرّر كيف تضبط إعدادات FastCGI. العديد منها متشابه إلا أنها تملك بعض الفوارق الصغيرة والتي ستنعكس على تنفيذ بريمجك. إعدادات FastCGI الشائعة:تمثّل إعدادات FastCGI المعلومات التي نرغب بجعلها متاحةً لمعالج FastCGI - الذي نرسل إليه الطلبات- على شكل أزواج مفتاح-قيمة key-value. لن تحتاج كلّ التطبيقات إلى نفس الإعدادات لذلك غالبًا ما ستحتاج لمراجعة توثيق التطبيق. تُعد بعض تلك الإعدادات ضروريةً للمعالج حتى يتمكن من تحديد السكربت - الذي ينبغي تشغيله- بشكل صحيح. بينما أُتيح البعض الآخر للسكربت، إذ أنها قد تغيّر سلوكه إن كان معدًّا ليعتمد على مجموعةٍ من الإعدادات. QUERY_STRING: ينبغي أن يُضبط هذا الإعداد بأي عبارة استعلام مقدّمة من قِبل المستخدم. عادةً ما تكون على شكل أزواج مفتاح-قيمة مزوّدةً بعد إشارة "?" في معرّف URI. عادةً ما يُضبط هذا الإعداد بقيمة أحد المتحولين query_string$ أو args$، إذ ينبغي عليهما أن يحويا على نفس البيانات. REQUEST_METHOD: يدّل هذا الإعداد معالجَ FastCGI على نوع الإجراء الذي طلبه المستخدم. وهو أحد الإعدادات القلائل التي يجب ضبطها حتى يتم التمرير بشكل صحيح. CONTENT_TYPE: إن ضُبط نوع الطلب في الإعداد السابق ليكون POST فيجب أن يُضبط هذا الإعداد. يشير هذا الإعداد إلى نوع البيانات التي ينبغي على معالج FastCGI توقعها. غالبًا ما يضبط هذا الإعداد بالمتغير content_type$ فقط، والذي يضبط بدوره وفقًا للمعلومات المأخودة من الطلب الأصلي. CONTENT_LENGTH: يجب أن يضبط هذا الإعداد إن كان نوع الطلب هو POST. يشير هذا الإعداد إلى طول المحتوى، وغالبًا ما يضبط بالمتغير content_length$ والذي يأخذ قيمته من المعلومات المتوفّرة في طلب المستخدم الأصلي. SCRIPT_NAME: يستخدم هذا الإعداد ليُشير إلى اسم السركبت الأساسي الذي يجب تشغيله. وهو إعداد هامٌ للغاية يمكن ضبطه بعدّة طرق وفقًا لاحتياجاتك. عادةً ما يُضبط بالمتغير fastcgi_script_name$ والذي يجب أن يكون معرّف URI للطلب، أو معرف URI للطلب متبوعًا بـ fastcgi_index إن انتهى المعرّف بـ (/)، أو المجموعة اللاقطة الأولى إن استُخدم fastcgi_fix_path_info. SCRIPT_FILENAME: يحدّد هذا الإعداد الموقع الفعلي على القرص للسكربت الذي يجب تشغيله. وبسبب ارتباطه مع الإعداد SCRIPT_NAME، تقترح بعض أدلة الاستخدام Guides أن تستعيض عن استخدامه بالمتغيرين document_root$fastcgi_script_name$. يتوفر بديلٌ آخر يملك العديد من المحاسن وهو استخدام request_filename$. REQUEST_URI: ينبغي أن تحوي على معرّف URI للطلب كاملًا ومن من دون تعديل، بالإضافة إلى السكربت الذي يجب تشغيله، ومعلومات المسار الإضافية، وأي قيمٍ ممرّرة. تفضّل بعض التطبيقات أن تحلّل تلك المعلومات بنفسها، ويقدم هذا الإعداد المعلومات اللازمة لهم للقيام بذلك. PATH_INFO: إن ضُبط cgi.fix_pathinfo بالقيمة “1” في ملف إعدادات PHP، فسيحوي هذا الإعداد على أية معلومات مسار إضافية additional path information مذكورة بعد اسم السكربت. عادةً ما يُستخدم هذا الإعداد لتعريف الملف الممرّر file argument والذي سيحدّد تصرُّف السكربت. قد يترتّب على ضبط cgi.fix_pathinfo بالقيمة "1" آثارٌ أمنية إن لم تكن طلبات السكربت قد فُحصت بوسائل أخرى (سنناقش ذلك لاحقًا). قد يُضبط هذا الإعداد أحيانًا بالمتغير fastcgi_path_info$ والذي يحوي على المجموعة اللاقطة لثانية من التعليمة fastcgi_split_path_info. وفي حالاتٍ أخرى، سيكون هنالك حاجةٌ لاستخدام متغير مؤقت، إذ أنه يمكن لمعالجةٍ أخرى أن تمسح تلك القيمة أحيانًا. PATH_TRANSLATED: يربط هذا الإعداد بين معلومات المسار المحتواة ضمن PATH_INFO والمسار الفعلي على نظام الملفات filesysem path. عادةً ما يُضبط هذا الإعداد بـ document_root$fastcgi_path_info$، ولكن أحيانًا يجب استبدال المتغير الأخير بالمتغير المؤقت الذي أشرنا إليه سابقًا. التحقق من الطلبات قبل تمريرها إلى FastCGI إنّ أحد المواضيع بالغة الأهمية التي لم نغطها حتى الآن هو كيفية تمرير الطلبات الديناميكية للخادوم بشكلٍ آمن. إن تمرير كلّ الطلبات للخادوم الخلفي بغض النظر عن صحتها لا يسبب خفض فاعلية الخادوم فحسب، بل إنه خَطِرٌ أيضًا. إذ أنه من الممكن للمهاجمين إنشاء طلباتٍ خبيثة في محاولةٍ منهم لتشغيل نص برمجي ما. في الواقع، حتى نعالج هذا الخطأ علينا أن نضمن إرسال الطلبات الصالحة فقط لمعالج FastCGI، يمكننا القيام بذلك بعدة طرق وذلك تبعًا لاحتياجات إعدادنا الخاص وفيما إن كان معالج FastCGI يعمل على نفس النظام المشغِّل لـ Nginx أم لا. إحدى القواعد الأساسية التي يجب أن تحدد لنا كيفية ضبط الإعدادات، هي أنه علينا ألا نسمح بأي معالجة أو تفسير لملفات المستخدم. إذ أنه من السهل نسبيًا على المستخدمين المخادعين malicious users أن يضمّنوا نصًا برمجيًا صالحًا valid code في ملفاتٍ تبدو في الظاهر أنها ملفاتٍ غيرُ مؤذيةٍ كالصور. حالما يُرفع ملفٌ كهذا إلى الخادوم علينا أن نضمن ألا يجد طريقًا للوصول إلى معالج FastCGI. إنّ المشكلة الأساسية التي نحاول حلها هنا هي في الواقع محدّدةٌ في مواصفات CGI specification. تتيح لك تلك المواصفات تحديد ملف السكربت الذي ترغب بتشغيله متبوعًا بمعلومات المسار الإضافية التي يمكن للسكربت أن يستخدمها. إن نموذج التنفيذ هذا يسمح للمستخدمين بطلب معرف URI قد يبدو كسكربت صالح legitimate، إلا أن الجزء الذي سيتم تنفيذه سيكون مذكورًا قبله في المسار. فالنأخذ مثلًا طلبًا لـ: test.jpg/index.php/ إن كانت إعداداتك تمرّر ببساطة كل الطلبات التي تنتهي بـ .php إلى المعالج دون التحقق من مدى صحتها فسيتحقق المعالج، إن كان يحقّق المواصفات، من وجود ذلك الموقع وسينفذّه إن أمكن. أما إذا لم يجد الملف فسيتّبع المواصفات وسيحاول تنفيذ الملف test.jpg/ وسيعتبر أن index.php/ تمثّل معلومات المسار الإضافية الخاصة بالسكربت. كما ترى يمكن لذلك أن يسمح ببعض النتائج غير المرغوب بها إطلاقًا عندما يجتمع مع فكرة رفع المستخدم للملفات. هنالك مجموعة من الطرق المختلفة لحل تلك المشكلة. أسهل تلك الطرق هو ببساطة تعطيل خاصية معالجة معلومات المسار من قِبَل المعالج، وذلك إن كان تطبيقك لا يعتمد على تلك المعلومات الإضافية. يمكن تعطيل تلك الخاصية لدى PHP-FPM من خلال الملف php.ini، فمثلًا إن كنت تستخدم نظام أوبونتو Ubuntu فيمكن تحرير الملف التالي: sudo nano /etc/php5/fpm/php.iniببساطة، ابحث عن الخيار cgi.fix_pathinfo وألغِ تعليقه ثم اضبطه بالقيمة “0” لتعطّل هذه “الميزة” كما يلي: cgi.fix_pathinfo=0أعد تشغيل عملية PHP-FPM حتى تأخذ التعديلات حيّز التنفيذ: sudo service php5-fpm restartسيدفع ذلك PHP لتنفيذ الجزء الأخير من المسار فقط، وبالتالي ففي المثال السابق إن لم يكن الملف test.jpg/index.php/ موجودًا فسيصدر PHP خطأ عوضًا عن محاولة تنفيذ الملف test.jpg/ إذا كان معالج FastCGI يعمل على نفس الخادوم الذي يُشغل Nginx فلدينا خيارٌ آخر وهو ببساطةٍ التحقق من وجود الملفات على القرص قبل تمريرها إلى المعالج. فإذا لم يكن الملف التالي موجودًا test.jpg/index.php/ فسيصدر خطأ. أما إن كان موجودًا فسيُرسل إلى الخادوم الخلفي لتتم معالجته. سينتج عن ذلك عمليًا سلوكٌ يشبه إلى حد بعيد ما رأيناه سابقًا. location ~ \.php$ { try_files $uri =404; . . . }إن كان تطبيقك يعتمد في سلوكه على معلومات المسار حتى يقوم بعملية التفسير بشكل صحيح فما زال بإمكانك السماح بتطبيق ذلك السلوك بأمان عبر القيام بالاختبارات قبل اتخاذ قرارٍ بإرسال الطلب إلى الخادوم الخلفي. فمثلًا، بإمكاننا مطابقة المجلدات التي نخرن فيها الملفات المرفوعة غير الموثوقة تحديدًا وضمان ألا تمرّر إلى المعالج. مثلًا، إن كان مجلد الملفات المرفوعة على المسار: /uploads/ فعلينا إنشاء مقطع موقع يتم مطابقته قبل أن يتم تقييم أي عبارة منتظمة: location ^~ /uploads { }بإمكاننا إضافة أي نوع من معالجة ملفات PHP داخل المقطع البرمجي: location ^~ /uploads { location ~* \.php$ { return 403; } }سيعمل الموقع الأم parent location على مطابقة أي طلب يبدأ بـ uploads/ وأيُّ طلب يتعامل مع ملفات PHP سيُرد عليه بالخطأ 403 عوضًا عن إرساله إلى الخادوم الخلفي. يمكنك أيضًا استخدام التعليمة fastcgi_splite_path_info للتعريف يدويًا عن الجزء من الطلب، الذي يجب تفسيره كسكربت والجزء الدي يجب تعريفه على أنه معلومات المسار الإضافية باستخدام التعابير النمطية. يسمح لك ذلك بأن تستمر في الاعتماد على وظيفة معلومات المسار، على أن تعرّف بدقة ما تعتبره بريمجًا وما تعتبره مسارًا. فمثلًا، بإمكاننا إعداد مقطع لموقع يقوم باعتبار أن أول جزء مكون للمسار ينتهي ب .php هو السكربت الذي ينبغي تشغيله. ويعتبر الباقي معلومات المسار الإضافية. وذلك يعني أنه من أجل الطلب: test.jpg/index.php/ فسيتم إرسال كامل المسار إلى المعالج باعتباره اسم السكربت ولا يحوي معلومات مسار إضافية. يمكن أن يكون الموقع كالآتي: location ~ [^/]\.php(/|$) { fastcgi_split_path_info ^(.+?\.php)(.*)$; set $orig_path $fastcgi_path_info; try_files $fastcgi_script_name =404; fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $request_filename; fastcgi_param PATH_INFO $orig_path; fastcgi_param PATH_TRANSLATED $document_root$orig_path; }ينبغي أن يعمل المقطع السابق عندما تكون قيمة cgi.fix_pathinfo في إعداد PHP مضبوطةً بالقيمة "1" حتى تسمح بمعلومات المسار الإضافية. وهنا، إن مقطع الموقع السابق لا يطابق الطلبات التي تنتهي بـ .php وحسب، بل تلك التي تنتهي بـ .php قبل إشارة "/" مباشرةً والتي تدل على مكون إضافي يتبع مسار المجلد directory. تعرّف التعليمة fastcgi_split_path_info داخل المقطع مجموعتين لاقطتين captured group باستخدام التعابير النمطية. تطابق المجموعة الأولى الجزء الممتد من بداية عنوان URI وحتى أول ورود لـ .php ويضعه في المتغير fastcgi_script_name$. ومن ثم يضع أي معلومة مذكورة في الجزء الباقي، والممتد بدءًا من النقطة التي انتهى عندها الجزء الأول وحتى نهاية العنوان، في المجموعة اللاقطة الثانية والتي تخزّن في متغير يدعى fastcgi_path_info$. نستخدم التعليمة set لنخزن القيمة المحفوظة في fastcgi_path_info$، حتى هذه النقطة، في متغير يدعى orig_path$. وذلك لأن قيمة المتغير fastcgi_path_info$ ستُمحى في لحظة عبر التعليمة try_files. بإمكاننا التحقق من اسم السكربت الذي التقطناه سابقًا باستخدام التعليمة try_files. وهي عبارة عن عملية تطبّق على ملف file operation تتأكد من أنّ السكربت الذي نحاول تشغيله مخزن على القرص. ولكن لذلك تأثيرًا جانبيًا يتمثل في مسح قيمة المتحول fastcgi_path_info$. بعد القيام بالتمرير التقليدي عبر FastCGI فإننا نضبط SCRIPT_FILENAME كما العادة. نضبط أيضًا الإعداد PATH_INFO بالقيمة التي المخزّنة في المتغير orig_path$. فبالرغم من أن قيمة fastcgi_path_info$ قد مُسحت، إلا أن قيمته الأصلية محفوظة في ذلك المتغير. كما أننا نضبط الوسيط PATH_TRANSLATED ليربط map بين معلومات المسار الإضافية والموقع الذي تُحفظ فيه على القرص، نقوم بذلك عبر دمج قيمتي المتغيرين document_root$ و orig_path$. يسمح لنا ذلك ببناء طلباتٍ مثل: index.php/users/view/ بحيث يتمكن الملف: index.php/ من معالجة المعلومات المتعلقة بالمجلد: users/view/ وبنفس الوقت نتجنب المواقف التي سيُشغّل بها الطلب: test.jpg/index.php/ سيُضبط البريمج دائمًا بأقصر مكوّن ينتهي بـ .php، وبالتالي سنتجنب تلك المشكلة. يمكننا أيضًا تحقيق ذلك باستخدام تعليمة alias إن احتجنا إلى تغيير موقع ملفات السكربتات. علينا فقط أن نأخذ ذلك بالحسبان في كل من ترويسة الموقع وتعريف fastcgi_split_path_info. location ~ /test/.+[^/]\.php(/|$) { alias /var/www/html; fastcgi_split_path_info ^/test(.+?\.php)(.*)$; set $orig_path $fastcgi_path_info; try_files $fastcgi_script_name =404; fastcgi_pass unix:/var/run/php5-fpm.sock; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $request_filename; fastcgi_param PATH_INFO $orig_path; fastcgi_param PATH_TRANSLATED $document_root$orig_path; }سوف يسمح لك ذلك لتشغيل تطبيقاتك التي تستخدم الإعداد PATH_INFO بأمان. تذكّر أنه عليك تعديل الخيار cgi.fix_pathinfo في ملف php.ini وضبطه بالقيمة "1" حتى يعمل بشكل صحيح. قد يترتب عليك أيضًا أن تعطّل security.limit_extensions في الملف php-fpm.conf. الخلاصةنأمل أنك تملك الآن فهمًا أفضل لإمكانية قيام FastCGI بالوساطة عنNginx. تسمح هذه الإمكانية لـ Nginx باستخدام قوته في معالجة الاتصالات بسرعة وتحضير المحتوى الثابت static content، بينما تُحمّل مسؤولية المحتوى الديناميكي dynamic content لبرمجيات مناسبة لذلك. يسمح FastCGI لـ Nginx بالعمل مع عدد كبير من التطبيقات، عبر إعدادات آمنة وذات أداء. ترجمة – وبتصرّف– للمقال Understanding and Implementing FastCGI Proxying in Nginx لمؤلفه Justin Ellingwood.
×
×
  • أضف...