<?xml version="1.0"?>
<rss version="2.0"><channel><title>DevOps: Nginx</title><link>https://academy.hsoub.com/devops/servers/web/nginx/?d=4</link><description>DevOps: Nginx</description><language>ar</language><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x62A;&#x62F;&#x648;&#x64A;&#x631; &#x627;&#x644;&#x633;&#x62C;&#x644;&#x627;&#x62A; &#x648;&#x636;&#x628;&#x637; &#x625;&#x639;&#x62F;&#x627;&#x62F;&#x627;&#x62A;&#x647;&#x627; &#x641;&#x64A; &#x62E;&#x627;&#x62F;&#x645; Nginx &#x64A;&#x639;&#x645;&#x644; &#x628;&#x646;&#x638;&#x627;&#x645; &#x623;&#x648;&#x628;&#x646;&#x62A;&#x648; &#x639;&#x644;&#x649; &#x62E;&#x627;&#x62F;&#x645; &#x627;&#x641;&#x62A;&#x631;&#x627;&#x636;&#x64A; VPS</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%AF%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D8%B3%D8%AC%D9%84%D8%A7%D8%AA-%D9%88%D8%B6%D8%A8%D8%B7-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF%D8%A7%D8%AA%D9%87%D8%A7-%D9%81%D9%8A-%D8%AE%D8%A7%D8%AF%D9%85-nginx-%D9%8A%D8%B9%D9%85%D9%84-%D8%A8%D9%86%D8%B8%D8%A7%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%81%D8%AA%D8%B1%D8%A7%D8%B6%D9%8A-vps-r802/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2024_02/-------Nginx--------VPS-d2-2.png.7c411e8468e1f59e066178a4ea884947.png" /></p>
<p>
	تعد إدراة السجلات جزءًا أساسيًا من إدارة الخوادم، ولتفادي ظهور المشاكل في خادم الويب، ينصح بإعداد السجلات Logging لتوثيق الأحداث والأنشطة المهمة على الخادم إذ إن معلومات السجلات الموجودة على خادمك تزوّدك بالبيانات اللازمة لاستكشاف الأخطاء وإصلاحها وتقييم المشاكل عند ظهورها.
</p>

<p>
	سنلقي في هذا المقال نظرةً على إمكانات سجلات خادم Nginx ونتعلم كيفية ضبطها لتخدم احتياجاتك على أفضل وجه، وذلك باستخدام خادم افتراضي خاص VPS يعمل بنظام تشغيل أوبنتو Ubuntu 22.04، ولكن يمكنك استخدام أي توزيعة حديثة لنظام لينكس.
</p>

<h3 id="">
	المتطلبات:
</h3>

<p>
	لإكمال هذا المقال بنجاح، ستحتاج إلى تجهيز بيئة العمل المكونة من:
</p>

<ul>
	<li>
		<p>
			خادم أوبنتو 22.04 يحتوي على مستخدم غير جذري non-root user ذي صلاحيات <code>sudo</code> و مثبت عليه جدار حماية. يمكنك اعداده بالعودة إلى <a href="https://academy.hsoub.com/devops/linux/%D8%A7%D9%84%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%8A%D8%A9-%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r431/" rel="">دليل إعداد الخادم الأولي</a>
		</p>
	</li>
	<li>
		<p>
			تثبيت Nginx على خادمك. يمكنك الاستعانة <a href="https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-nginx-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r434/" rel="">بالمقال التالي</a> لتثبيته على خادمك. أصبحت جاهزًا لبدء العمل بعد أن ثبّتَ Nginx على خادم أوبنتو 22.04.
		</p>
	</li>
</ul>

<h2 id="error_log">
	فهم آلية عمل سجل الأخطاء <code>Error_log</code>
</h2>

<p>
	يستخدم خادم Nginx عدة سجلات للتحكم في سجلات النظام. ويسمى السجل المستخدم في الوحدة الأساسية بسجل الأخطاء أو <code>Error_log</code>
</p>

<h3 id="error_log-1">
	صياغة سجل الأخطاء <code>Error_log</code>
</h3>

<p>
	يُستخدم سجل الأخطاء <code>Error_log</code> لتسجيل رسائل الخطأ العادية. إن استخدمت خادم أباتشي Apache ستجد أن هذا السجل مشابه لسجل أخطاء أباتشي <code>ErrorLog</code>. يعتمد سجل الأخطاء <code>Error_log</code> على الصياغة التالية:
</p>

<pre class="ipsCode">/etc/nginx/nginx.conf
error_log log_file log_level
</pre>

<p>
	يحدد <code>log_file</code> الملف الذي ستُحفظ فيه السجلات، أما <code>log_level</code> فيحدد أدنى مستوى تسجيل ترغب في تسجيله.
</p>

<h3 id="-1">
	مستويات التسجيل
</h3>

<p>
	يمكن ضبط سجل الأخطاء <code>Error_log</code> لتسجيل معلومات وفق ما تحتاجه. أما مستوى التسجيل فهو أحد المستويات التالية:
</p>

<ul>
	<li>
		<code>emerg</code>: يظهر في حالات الطوارئ حيث يكون النظام في حالة غير مستقرة
	</li>
	<li>
		<code>alert</code>: يظهر في المواقف الخطيرة التي تتطلب اتخاذ إجراء فورًا
	</li>
	<li>
		<code>crit</code>: يظهر عند حدوث المشاكل المهمة التي تحتاج إلى معالجة
	</li>
	<li>
		<code>error</code>: يظهر عند حدوث خطأ ما وفشل عملية ما
	</li>
	<li>
		<code>warn</code>: يظهر عند حدوث أمر غير مألوف، لكنه لا يدعو للقلق
	</li>
	<li>
		<code>notice</code>: يظهر عند حدوث أمر عادي، لكن يجب التنبيه عليه
	</li>
	<li>
		<code>info</code>: رسالة توضيحية
	</li>
	<li>
		<code>debug</code>: معلومات عن تصحيح الأخطاء تفيد في تحديد مكان حدوث المشكلة
	</li>
</ul>

<p>
	تعتبر المستويات الأعلى في القائمة السابقة ذات أولوية أعلى، فإذا حددت مستوىً ما، فإن السجل سيلتقط هذا المستوى، والمستويات الأعلى منه. على سبيل المثال، إذا حددت المستوى <code>error</code> فإن السجل سوف يجلب الرسائل التالية <code>error</code>و <code>crit</code> و <code>alert</code> و <code>emerg</code>، وتجد مثالًا على هذا السجل في ملف الإعدادات الرئيسي.استخدم محرر النصوص الذي تفضله للوصول إلى ملف الإعدادات التالي، سوف نستخدم في مثالنا محرر النصوص <strong>نانو</strong> <code>nano</code>:
</p>

<pre class="ipsCode">sudo nano /etc/nginx/nginx.conf
</pre>

<p>
	اذهب إلى أسفل الملف، إلى قسم إعدادات التسجيل <code>Logging Settings #</code> ولاحظ السجلات التالية:
</p>

<pre class="ipsCode">/etc/nginx/nginx.conf
. . .
##
# Logging Settings
##

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
. . .
</pre>

<p>
	إن أردت بأن لا يسجل <code>error_log</code> شيئًا، فعليك إرسال خرجه إلى <code>/dev/null</code>:
</p>

<pre class="ipsCode">. . .
/etc/nginx/nginx.conf
error_log /dev/null crit;
. . .
</pre>

<p>
	أما سجل <code>access_log</code> فسوف نناقشه في فقرة تالية.
</p>

<h2 id="httplogmodule">
	فهم آلية عمل سجل <code>HttpLogModule</code>
</h2>

<p>
	يُعد سجل <code>error_log</code> جزءًا من الوحدة الأساسية core module، أما سجل <code>access_log</code> فيُعد جزءًا من وحدة <code>HttpLogModule</code> التي تزودنا بإمكانية تخصيص السجلات. كما توجد بضع سجلات أخرى في هذه الوحدة تساعد في إعداد السجلات المخصصة custom logs.
</p>

<h3 id="log_format">
	سجل <code>log_format</code>
</h3>

<p>
	يُستخدم سجل <code>log_format</code> لوصف التنسيق المستخدم في السجلات باستخدام النص العادي والمتغيرات. ثمة تنسيق جاهز يأتي مع Nginx ويسمى <strong>التنسيق المدمج</strong> <code>combined</code>، وهو تنسيق شائع مُستَخدم في عدة خوادم. إليك مثالًا على التنسيق المدمج إن لم يكن مُعَّرفًا مسبقًا واضطررت إلى تعريفه مع سجل <code>log_format</code>:
</p>

<pre class="ipsCode">/etc/nginx/nginx.conf
log_format combined '$remote_addr - $remote_user [$time_local]  '
            '"$request" $status $body_bytes_sent '
            '"$http_referer" "$http_user_agent"';
</pre>

<p>
	لاحظ أن التعريف يتضمن عدة أسطر وينتهي عند الفاصلة المنقوطة (<strong>;</strong>). أما الأسطر التي تبدأ بالعلامة (<code>$</code>) فهي تعبر عن المتغيرات، وتُفسَر المحارف التالية <code>-</code> ، <code>[</code> ، <code>]</code> حرفيًا. أما الصياغة العامة للسجل فهي كالتالي:
</p>

<pre class="ipsCode">/etc/nginx/nginx.conf
log_format format_name string_describing_formatting;
</pre>

<p>
	يمكنك استخدام <a href="http://nginx.org/en/docs/http/ngx_http_core_module.html#variables" rel="external nofollow">المتغيرات</a> التي تدعمها الوحدة الأساسية وذلك لصياغة سلاسل تسجيل logging strings خاصة.
</p>

<h2 id="access_log">
	فهم آلية عمل سجل <code>access_log</code>
</h2>

<p>
	يستخدم سجل <code>access_log</code> صياغة مشابهة لصياغة سجل الأخطاء <code>Error_log</code>، لكنه أكثر مرونة، ولذلك يستخدم لضبط التسجيل المخصص Custom logging. الصياغة العامة لسجل <code>access_log</code> هي كالتالي:
</p>

<pre class="ipsCode">/etc/nginx/nginx.conf
access_log /path/to/log/location [ format_of_log buffer_size ];
</pre>

<p>
	إن القيمة الافتراضية لسجل <code>access_log</code> هي التنسيق المدمج <code>combined</code> الذي تحدثنا عنه سابقًا في سجل <code>log_format</code>، لكن يمكنك استخدام أي تنسيق معَرَّف في سجل <code>log_format</code>. قمة المخزّن المؤقت Buffer هي الحجم الأعظمي للبيانات التي يحتفظ بها خادم Nginx قبل أن ينقلها إلى السجل. ويمكنك أن تضغط حجم ملف السجل بواسطة إضافة المحدد <code>gzip</code> ضمن تعريف السجل، كما يلي:
</p>

<pre class="ipsCode">/etc/nginx/nginx.conf
access_log /path/to/log/location format_of_log gzip;
</pre>

<p>
	وبخلاف سجل الأخطاء <code>Error_log</code>، إن لم تُرِد التسجيل فبإمكانك إلغاؤه من <a href="https://academy.hsoub.com/devops/servers/web/nginx/%D9%81%D9%87%D9%85-%D8%A8%D9%86%D9%8A%D8%A9-%D9%85%D9%84%D9%81-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF%D8%A7%D8%AA-nginx-%D9%88%D8%B3%D9%8A%D8%A7%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF%D8%A7%D8%AA-r112/" rel="">ملف الإعدادات</a> كالتالي، ولا حاجة لإرساله إلى <code>/dev/null</code>:
</p>

<pre class="ipsCode">/etc/nginx/nginx.conf
. . .
##
# Logging Settings
##

access_log off;
error_log /var/log/nginx/error.log;

. . .
</pre>

<h2 id="-2">
	تدوير السجلات
</h2>

<p>
	مع ازدياد ملفات السجل، يصبح من الضروري إدارة آليات التسجيل لتجنب امتلاء مساحة القرص، وتدوير السجلات Log rotation هي عملية تبديل ملفات السجل وأرشفة الملفات القديمة لمدة زمنية محددة.
</p>

<p>
	لا يوفر Nginx أدوات لإدارة ملفات السجلات، لكنه يحتوي على آليات للمساعدة في تدوير السجلات.
</p>

<h3 id="-3">
	تدوير السجلات يدويًا
</h3>

<p>
	يمكنك إنشاء سكربت لتدوير السجلات يدويًا، على سبيل المثال، لنقل ملف السجل الحالي إلى ملف جديد وأرشفته، يمكنك إتباع الخطة التالية: أعد تسمية أحدث سجل بإضافة اللاحقة <code>.0</code> إلى اسمه، ثم أعد تسمية الملفات القديمة بإضافة اللاحقة <code>.1</code> وهكذا على التوالي:
</p>

<pre class="ipsCode">mv /path/to/access.log /path/to/access.log.0
</pre>

<p>
	إن الأمر الذي يدوّر ملفات السجل هو التالي
</p>

<pre class="ipsCode">kill -USR1 `cat /var/run/nginx.pid`
</pre>

<p>
	لا ينهي هذا الأمر عمليات خادم Nginx، لكنه يرسل لها إشارةً لتعيد تحميل ملفات السجل. سيؤدي هذا إلى تسجيل الطلبات الجديدة في ملف السجل المحدَّث:
</p>

<pre class="ipsCode">kill -USR1 `cat /var/run/nginx.pid`
</pre>

<p>
	يخزّن خادم Nginx معرف العملية الرئيسة <abbr title="Process IDentifier | معرّف العملية أو البرنامج">PID</abbr> في الملف <code>/var/run/nginx.pid</code> الموجود أعلى ملف الإعدادات <code>/etc/nginx/nginx.conf</code> في السطر الذي يبدأ بكلمة <code>pid</code>:
</p>

<pre class="ipsCode">sudo nano /etc/nginx/nginx.conf
</pre>

<pre class="ipsCode">/etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
...
</pre>

<p>
	بعد تدوير السجلات، نفّذ الأمر <code>sleep 1</code> كي تكتمل عملية النقل. كما يمكنك بعدها أن تضغط الملفات القديمة في ملف بصيغة .zip أو أن تجري العملية التي ترغب بها:
</p>

<pre class="ipsCode">sleep 1
[ post-rotation processing of old log file ]
</pre>

<h3 id="logrotate">
	تدوير السجلات باستخدام برنامج <code>logrotate</code>
</h3>

<p>
	يُستخدم برنامج <code>logrotate</code> لتدوير السجلات، وهو برنامج يُنَزّل تلقائيًا على نظام أوبنتو، كما يوجد سكربت مخصص لبرنامج <code>logrotate</code> على خادم nginx العامل بنظام أوبنتو. استخدم محرر النصوص الذي تفضله للوصول إلى ملف الإعدادات التالي، سوف نستخدم في مثالنا محرر النصوص <a href="https://academy.hsoub.com/programming/workflow/%D9%85%D9%82%D8%A7%D8%B1%D9%86%D8%A9-%D8%A8%D9%8A%D9%86-%D9%85%D8%AD%D8%B1%D8%B1-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-%D9%81%D9%8A%D9%85-vim-%D9%88%D9%86%D8%A7%D9%86%D9%88-nano-r1590/" rel=""><code>nano</code></a> :
</p>

<pre class="ipsCode">sudo nano /etc/logrotate.d/nginx
</pre>

<p>
	عليك تذكر أن السطر الأول من الملف يحدد الموقع الذي ستُطَبق فيه أوامر الأسطر اللاحقة، إن غيّرت موقع تسجيل الملفات في ملف إعدادات Nginx، أما بقية الملف فيُشير إلى أن السجلات ستُدَور يوميًا وسيُحتَفظ ب 52 سجل قديم. لاحظ أن قسم <code>postrotate</code> يحتوي على أمر مشابه لآليات التدوير اليدوية التي طبقناها سابقًا:
</p>

<pre class="ipsCode">/etc/logrotate.d/nginx
. . .
postrotate
    [ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid`
endscript
. . .
</pre>

<p>
	يوجه القسم السابق Nginx إلى إعادة تحميل ملفات السجل عند اكتمال التدوير.
</p>

<h2 id="-4">
	خاتمة
</h2>

<p>
	توفر إدارة السجلات وضبطها على نحو صحيح الوقت والجهد في حال حدوث مشكلة في الخادم، إذ إن الوصول إلى المعلومات التي تساعدك على تشخيص المشكلة يعد عاملًا مهمًا في حل المشكلة بسلاسة وسهولة. كما أن الاطلاع الدوري على سجلات الخادم يُعدّ أمرًا مهمًا لضمان عمل الموقع على نحو صحيح وعدم كشف أي بيانات حساسة. تعرفنا في هذا المقال على مقدمة عن التعامل مع السجلات في خادم Nginx يعمل بنظام تشغيل أوبنتو، كما يمكنك قراءة المزيد حول كشف المشاكل الشائعة للمواقع على خادوم لينكس. وللحصول على الدعم والمساعدة، أضف سؤالك في قسم الأسئلة والأجوبة في <a href="https://academy.hsoub.com/questions/" rel="">أكاديمية حسوب</a>.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-configure-logging-and-log-rotation-in-nginx-on-an-ubuntu-vps" rel="external nofollow">How To Configure Logging and Log Rotation in Nginx on an Ubuntu VPS</a> لكاتبه Justin Ellingwood.
</p>

<h2 id="-5">
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/devops/linux/%D9%83%D9%8A%D9%81-%D8%AA%D8%B3%D8%AA%D8%B9%D8%B1%D8%B6-%D9%88%D8%AA%D8%AF%D9%8A%D8%B1-%D8%B3%D8%AC%D9%84%D8%A7%D8%AA-%D9%84%D9%8A%D9%86%D9%83%D8%B3-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-%D9%88centos-r233/" rel="">كيف تستعرض وتدير سجلات لينكس على أوبنتو وCentOS</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/linux/redhat/%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D8%AD%D8%B2%D9%85%D8%8C-%D8%A3%D8%AA%D9%85%D8%AA%D8%A9-%D8%A7%D9%84%D9%85%D9%87%D8%A7%D9%85%D9%91-%D9%88%D9%85%D8%B1%D8%A7%D9%82%D8%A8%D8%A9-%D8%A7%D9%84%D8%B3%D9%91%D8%AC%D9%84%D8%A7%D8%AA-%D9%81%D9%8A-red-hat-enterprise-linux-r745/" rel="">إدارة الحزم، أتمتة المهامّ ومراقبة السّجلات في Red Hat Enterprise Linux</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/web/nginx/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%B6%D8%A8%D8%B7-%D8%AE%D8%A7%D8%AF%D9%85-nginx-r401/" rel="">تثبيت وضبط خادم Nginx</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/web/%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%AE%D8%A7%D8%AF%D9%85-%D9%88%D9%8A%D8%A8-caddy-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1604-r363/" rel="">تثبيت خادم ويب Caddy على أوبنتو 16.04</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/%D8%AF%D9%84%D9%8A%D9%84-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AE%D8%A7%D8%AF%D9%85-%D9%88%D9%8A%D8%A8-%D9%85%D8%AD%D9%84%D9%8A-%D8%AE%D8%B7%D9%88%D8%A9-%D8%A8%D8%AE%D8%B7%D9%88%D8%A9-r422/" rel="">دليل إعداد خادم ويب محلي خطوة بخطوة</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">802</guid><pubDate>Mon, 12 Feb 2024 12:01:01 +0000</pubDate></item><item><title>&#x625;&#x639;&#x62F;&#x627;&#x62F; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x62C;&#x627;&#x646;&#x63A;&#x648; &#x628;&#x648;&#x627;&#x633;&#x637;&#x629; Postgres &#x648;&#x62E;&#x627;&#x62F;&#x645; &#x625;&#x646;&#x62C;&#x646; &#x625;&#x643;&#x633; Nginx &#x648;Gunicorn</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%A8%D9%88%D8%A7%D8%B3%D8%B7%D8%A9-postgres-%D9%88%D8%AE%D8%A7%D8%AF%D9%85-%D8%A5%D9%86%D8%AC%D9%86-%D8%A5%D9%83%D8%B3-nginx-%D9%88gunicorn-r667/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_12/639ac9f107282_----Postgres--Nginx--Gunicorn.png.dd9892bbd848f0ba0901e01058eab9f7.png" /></p>

<p>
	<a href="http://xn--%20%20%20%20-r5fjdk2a9c8c1af2moagtqck6b" rel="external nofollow">جانغو هو إطار عمل ويب</a> قوي يساعدك في إطلاق تطبيق بايثون Python أو موقعك على الويب بسرعة. ومع أنه يتضمن خادم تطوير مبسط لاختبار شيفرتك محليًّا، فإنك تحتاج إلى <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r574/" rel="">خادم ويب</a> أقوى وأكثر أمانًا عندما يتعلق الأمر ولو قليلًا بعمليات الإنتاج أو الإطلاق الرسمي للتطبيقات أو المواقع.
</p>

<p>
	ستثبت وتضبط في هذه المقالة بعض المكونات على أوبنتو 18.04 لدعم وخدمة تطبيقات جانغو، وتجهّز <a href="https://academy.hsoub.com/devops/servers/databases/postgresql/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgresql-%D9%88%D8%AA%D8%A7%D8%B1%D9%8A%D8%AE-%D8%B8%D9%87%D9%88%D8%B1%D9%87%D8%A7-r493/" rel="">قاعدة بيانات PostgreSQL</a> بدلًا من <a href="https://academy.hsoub.com/devops/servers/databases/%d9%83%d9%8a%d9%81-%d9%88%d9%85%d8%aa%d9%89-%d9%86%d8%b3%d8%aa%d8%ae%d8%af%d9%85-sqlite-r111/" rel="">قاعدة بيانات SQLite</a> الافتراضية. بعد ذلك، ستضبط خادم تطبيقات غوني كورن للربط مع تطبيقاتك، ثم في الختام ستجهز إنجن إكس ليعمل مثل خادم وكيل لغوني كورن مما يعطيك وصولًا إلى مزاياه الأمنية ومزايا الأداء الخاصة التي يتصف بها لخدمة تطبيقاتك.
</p>

<h2>
	المتطلبات الأساسية
</h2>

<p>
	ستحتاج قبل المتابعة في هذه المقالة إلى خادم أوبنتو 18.04 مُعد وجاهز وإلى مستخدم غير جذر يتمتع بصلاحيات "sudo" مهيأة وإلى جدار ناري مُفعّل. <a href="https://academy.hsoub.com/devops/linux/%D8%A7%D9%84%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%8A%D8%A9-%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r431/" rel="">راجع دليل إعداد خادم أوبنتو 18.04 مبدئي للبدء</a>.
</p>

<h2>
	الخطوة الأولى - تثبيت الحزم البرمجية من مستودعات أوبنتو
</h2>

<p>
	ابدأ بتنزيل وتثبيت جميع العناصر التي تحتاجها من مستودعات أوبنتو. استخدم مدير حزم بايثون <code>pip</code> لتثبيت مكونات إضافية لاحقة.
</p>

<p>
	حدّث في البداية دليل الحزم <code>apt</code> المحلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5470_10" style="">
<span class="pln">$ sudo apt update</span></pre>

<p>
	ثم ثبّت الحزم بحسب إصدار بايثون الذي يستخدمه مشروعك، فإذا كنت تستخدم جانغو مع <a href="https://academy.hsoub.com/programming/python/%d8%a7%d9%84%d8%af%d9%84%d9%8a%d9%84-%d8%a7%d9%84%d8%b3%d8%b1%d9%8a%d8%b9-%d8%a5%d9%84%d9%89-%d9%84%d8%ba%d8%a9-%d8%a7%d9%84%d8%a8%d8%b1%d9%85%d8%ac%d8%a9-%d8%a8%d8%a7%d9%8a%d8%ab%d9%88%d9%86-python-3-r535/" rel="">بايثون 3</a> فنفذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_15" style="">
<span class="pln">$ sudo apt install python3</span><span class="pun">-</span><span class="pln">pip python3</span><span class="pun">-</span><span class="pln">dev libpq</span><span class="pun">-</span><span class="pln">dev postgresql postgresql</span><span class="pun">-</span><span class="pln">contrib nginx curl</span></pre>

<p>
	ننبه إلى أن جانغو 1.11 هو آخر إصدار من جانغو يدعم بايثون 2. لذلك، إذا كنت ستتفتح مشاريع جديدة، فننصحك باختيار بايثون 3، لكن إذا كنت ما تزال تريد استخدام بايثون 2 فنفّذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_17" style="">
<span class="pln">$ sudo apt install python</span><span class="pun">-</span><span class="pln">pip python</span><span class="pun">-</span><span class="pln">dev libpq</span><span class="pun">-</span><span class="pln">dev postgresql postgresql</span><span class="pun">-</span><span class="pln">contrib nginx curl</span></pre>

<p>
	سيثبت هذا <code>pip</code> وملفات تطوير بايثون اللازمة لبناء غوني كورن لاحقًا، وسيثبت أيضًا نظام قواعد بيانات Postgres والمكتبات اللازمة للتفاعل معها وخادم الويب إنجن إكس.
</p>

<h2>
	الخطوة الثانية - إنشاء قاعدة بيانات PostgreSQL ومستخدم لها
</h2>

<p>
	ستنشئ في هذه الخطوة قاعدة بيانات مع مستخدم <a href="https://academy.hsoub.com/programming/sql/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%B9%D9%86-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r584/" rel="">قاعدة بيانات</a> لتطبيق جانغو الخاص بك مع PostgreSQL -أو اختصارًا Postgres.
</p>

<p>
	تستخدم Postgres افتراضيًا مخطط استيثاق يُطلق عليه اسم استيثاق النظير peer authentication في حالة الاتصالات المحلية، والذي يعني أنه إذا طابق اسم مستخدم <a href="https://academy.hsoub.com/files/24-%D8%A3%D9%86%D8%B8%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%84%D9%85%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D9%86/" rel="">نظام التشغيل</a> للمستخدم اسم مستخدم Postgres صالح، فيمكن لمستخدم نظام التشغيل تسجيل الدخول إلى قاعدة البيانات دون أي شروط أمنية أخرى.
</p>

<p>
	أُنشئ أثناء تثبيتك لنظام Postgres مستخدم نظام تشغيل اسمه "postgres" ليكون نظيرًا للمستخدم الإداري لنظام PostgreSQL الذي اسمه "postgres"، إذ ستحتاج لحساب هذا المستخدم لإنجاز المهام الإدارية. سجل الدخول إلى جلسة Postgres تفاعلية باستخدام <code>sudo</code> ومرّر اسم المستخدم مستعملًا الخيار <code>u-</code>:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_22" style="">
<span class="pln">$ sudo </span><span class="pun">-</span><span class="pln">u postgres psql</span></pre>

<p>
	سيظهر لك محث PostgreSQL، إذ يمكنك إعداد متطلباتك. أنشئ أولًا قاعدة بيانات لمشروعك:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_24" style="">
<span class="pln">postgres</span><span class="pun">=#</span><span class="pln"> CREATE DATABASE myproject</span><span class="pun">;</span></pre>

<p>
	<strong>ملاحظة:</strong> يجب أن تنتهي كل تعليمة Postgres بفاصلة منقوطة، لذا تأكد من أنك طبقت هذه القاعدة إذا واجهت أي مشاكل.
</p>

<p>
	أنشئ مستخدم قاعدة بيانات مشروعك واختر كلمة مرور قوية:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_26" style="">
<span class="pln">postgres</span><span class="pun">=#</span><span class="pln"> CREATE USER myprojectuser WITH PASSWORD </span><span class="str">'password'</span><span class="pun">;</span></pre>

<p>
	وسيكون الخرج على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5470_28" style="">
<span class="pln">CREATE ROLE</span></pre>

<p>
	ستعدّل الآن بعض معاملات الاتصال للمستخدم الذي أنشأته، والهدف من هذه التعديلات هو تسريع عمليات قاعدة البيانات بحيث لا يبقى حاجة إلى الاستعلام عن القيم الصحيحة ووضع قيمها في كل مرة نحتاج فيها إلى الاتصال بقاعدة البيانات.
</p>

<p>
	بدايةً اضبط قيمة الترميز الافتراضي default encoding إلى "UTF-8" التي يتوقعها جانغو:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_30" style="">
<span class="pln">postgres</span><span class="pun">=#</span><span class="pln"> ALTER ROLE myprojectuser SET client_encoding TO </span><span class="str">'utf8'</span><span class="pun">;</span></pre>

<p>
	وسيكون الخرج على النحو التالي:
</p>

<pre class="ipsCode">
ALTER ROLE
</pre>

<p>
	ثم حدّد مخطط عزل الإجراءات الافتراضي بالقيمة "read committed" لمنع عمليات القراءة من المعاملات التي لم تودع بعد uncommitted:
</p>

<pre class="ipsCode">
postgres=# ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed';
</pre>

<p>
	وسيكون الخرج على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_32" style="">
<span class="pln">ALTER ROLE</span></pre>

<p>
	نظرًا لأن مشاريع جانغو ستُضبط على استخدام النطاق الزمني "UTC" افتراضيًّا، لذا حدد النطاق الزمني المناسب:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_34" style="">
<span class="pln">postgres</span><span class="pun">=#</span><span class="pln"> ALTER ROLE myprojectuser SET timezone TO </span><span class="str">'UTC'</span><span class="pun">;</span></pre>

<p>
	وسيكون الخرج على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_36" style="">
<span class="pln">ALTER ROLE</span></pre>

<p>
	كل هذه طبعًا توصيات من <a href="https://docs.djangoproject.com/en/4.0/ref/databases/#optimizing-postgresql-s-configuration" rel="external nofollow">مشروع جانغو</a>.
</p>

<p>
	الآن، اِمنح مستخدمك الجديد وصولًا إلى قاعدة بياناتك الجديدة ليتمكن من إدارتها:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_38" style="">
<span class="pln">postgres</span><span class="pun">=#</span><span class="pln"> GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser</span><span class="pun">;</span></pre>

<p>
	وسيكون الخرج على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_40" style="">
<span class="pln">GRANT</span></pre>

<p>
	وبعد أن تنتهي، غادر محث PostgreSQL بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_42" style="">
<span class="pln">postgres</span><span class="pun">=#</span><span class="pln"> \q</span></pre>

<p>
	وبهذا يكون POstgreSQL الآن معدًّا بنجاح بحيث يمكن لجانغو الاتصال بمعلومات قاعدة البيانات وإدارتها.
</p>

<h2>
	الخطوة الثالثة - إنشاء بيئة بايثون افتراضية لمشروعك
</h2>

<p>
	الآن وقد أصبح لديك قاعدة بياناتك، يمكنك البدء في تجهيز بقية متطلبات مشروعك. يستلزم هذا تثبيت متطلبات بايثون ضمن بيئة افتراضية لكي تكون الإدارة أكثر فاعلية، إذ سيسمح تثبيت جانغو داخل بيئة افتراضية مخصصة لمشروعك بمعالجة كلٌّ مشروع من مشاريعك ومتطلباته بمعزل عن المشاريع الأخرى.
</p>

<p>
	ستحتاج لإنجاز ذلك إلى وصول إلى الأمر <code>virtualenv</code> الذي ينشئ البيئات الافتراضية. ابدأ بتثبيت هذا الأمر مستخدمًا <code>pip</code>، وإذا كنت تستخدم بايثون 3 فلا بُد من ترقية <code>pip</code>:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_44" style="">
<span class="pln">$ sudo </span><span class="pun">-</span><span class="pln">H pip3 install </span><span class="pun">--</span><span class="pln">upgrade pip</span></pre>

<p>
	ثم ثبّت الحزمة:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_46" style="">
<span class="pln">$ sudo </span><span class="pun">-</span><span class="pln">H pip3 install virtualenv</span></pre>

<p>
	إذا كنت تستخدم بايثون 2 فلا بُد من ترقية <code>pip</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5470_48" style="">
<span class="pln">$ sudo </span><span class="pun">-</span><span class="pln">H pip install </span><span class="pun">--</span><span class="pln">upgrade pip</span></pre>

<p>
	ثم ثبّت الحزمة:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_50" style="">
<span class="pln">$ sudo </span><span class="pun">-</span><span class="pln">H pip install virtualenv</span></pre>

<p>
	مع تثبيت <code>virtualenv</code>، يمكنك البدء في تشكيل مشروعك. أنشئ أولًا المجلد الذي ستحفظ فيه ملفات مشروعك. سنسميه نحن هنا "myprojectdir" ويمكنك تسميته ما تشاء.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5470_52" style="">
<span class="pln">$ mkdir </span><span class="pun">~/</span><span class="pln">myprojectdir</span></pre>

<p>
	ثم انتقل إلى داخل المجلد:
</p>

<pre class="ipsCode">
$ cd ~/myprojectdir
</pre>

<p>
	ثم أنشئ بيئة بايثون الافتراضية داخل مجلد المشروع:
</p>

<pre class="ipsCode">
$ virtualenv myprojectenv
</pre>

<p>
	سينشئ هذا مجلدًا اسمه "myprojectenv" ضمن مجلد "myprojectdir"، وسيثبت داخله نسخةً محليةً من بايثون ونسخةً محليةً من <code>pip</code>. يمكنك استخدام هذا لتثبيت وضبط بيئة بايثون تعزل مشروعك عن بقية المشاريع.
</p>

<p>
	لكن قبل تثبيت متطلبات بايثون لمشروعك ستحتاج إلى تفعيل البيئة الافتراضية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5470_54" style="">
<span class="pln">$ source myprojectenv</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">activate</span></pre>

<p>
	يجب أن يتغير المحث الآن ليشير إلى أنك الآن تعمل ضمن بيئة بايثون افتراضية. سيبدو هذا مشابهًا لما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_56" style="">
<span class="pun">(</span><span class="pln">myprojectenv</span><span class="pun">)</span><span class="pln">user@host</span><span class="pun">:~/</span><span class="pln">myprojectdir$</span></pre>

<p>
	وهكذا بعد أن أصبحت بيئتك الافتراضية فعالة، ثبّت جانغو وغوني كورن وموائم PostgreSQL adaptor، اسمه <code>psycopg2</code> بالنسخة المحلية من <code>pip</code>:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_58" style="">
<span class="pln">pip install django gunicorn psycopg2</span><span class="pun">-</span><span class="pln">binary</span></pre>

<p>
	<strong>ملاحظة:</strong>:عندما تُفعّل البيئة الافتراضية، أي عندما يُسبق المحث باسم المجلد "(myprojectenv)"، استخدم <code>pip</code> بدلًا من <code>pip3</code> حتى لو كنت تستخدم بايثون 3. تُسمى نسخة الأداة للبيئة الافتراضية دائمًا باسم "pip"، بغض النظر عن نسخة <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">بايثون</a>.
</p>

<p>
	الآن أصبح لديك كل البرمجيات اللازمة للبدء في مشروع جانغو.
</p>

<h2>
	الخطوة الرابعة - إنشاء وضبط مشروع جانغو جديد
</h2>

<p>
	بعد أن ثُبّتت مكونات بايثون، أصبح بإمكانك إنشاء ملفات مشروع <a href="https://academy.hsoub.com/programming/python/django/%D8%A7%D9%84%D8%A8%D8%AF%D8%A1-%D9%85%D8%B9-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%84%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D9%88%D9%8A%D8%A8-r1625/" rel="">جانغو</a> الفعلية، وبما أن مجلد المشروع أصبح جاهزًا فيمكنك أن تطلب من جانغو أن يثبت الملف هنا، إذ سينشئ عندئذٍ مجلدًا في المستوى الثاني مع الشيفرة الفعلية وهذا أمرٌ طبيعي وسيضع سكريبت إدارة في هذا المجلد؛ وهذا مهمٌّ أنك تعرّف المجلد صراحةً بدلًا من السماح لجانغو باتخاذ قرارات متعلقة بمجلدك الحالي:
</p>

<pre class="ipsCode">
(myprojectenv) $ django-admin.py startproject myproject ~/myprojectdir
</pre>

<p>
	في هذه النقطة ستكون محتويات مجلد المشروع (في حالتنا هو "myprojectdir/~") هي:
</p>

<ul>
<li>
		"myprojectdir/manage.py/~": سكريبت إدارة مشروع جانغو.
	</li>
	<li>
		"/myprojectdir/myproject/~": حزمة مشروع جانغو. سيحتوي هذا على الملفات: "init__.py__" و "settings.py" و "urls.py" و "wsgi.py".
	</li>
	<li>
		"/myprojectdir/myprojectenv/~": مجلد البيئة الافتراضية الذي أنشأته من قبل.
	</li>
</ul>
<p>
	تتمثل المرحلة التالية في ضبط الإعدادات لملفات المشروع الجديدة. افتح ملف الإعدادات بمحرر النصوص المفضل لديك. سنستخدم نحن محرر النصوص نانو nano:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5470_63" style="">
<span class="pun">(</span><span class="pln">myprojectenv</span><span class="pun">)</span><span class="pln"> $ nano </span><span class="pun">~/</span><span class="pln">myprojectdir</span><span class="pun">/</span><span class="pln">myproject</span><span class="pun">/</span><span class="pln">settings</span><span class="pun">.</span><span class="pln">py</span></pre>

<p>
	اعثر أولًا على الموجّه <code>ALLOWED_HOSTS</code> الذي يعرّف قائمةً بعناوين الخوادم، أو أسماء النطاقات التي ستُستخدمُ للاتصال بنسخة جانغو، وسيظهر استثناء exception إذا وردت أي طلبات قادمة تحتوي على ترويسة <strong>Host</strong> غير مذكورة ضمن القائمة، ولذا يشدّد جانغو على تحديد هذا تفاديًا لصنف معين من الثغرات الأمنية.
</p>

<p>
	أدرِج داخل الأقواس المربعة عناوين IP أو أسماء النطاقات المترافقة مع خادم جانغو ضمن علامتي اقتباس مع الفصل بين كل عنصرين بفاصلة. إذا كنت تفضّل طلبات نطاق كامل وأي نطاقات فرعية، ضع نقطةً في بداية الإدخال. ألقِ نظرةً على الشيفرة التالية التي تحتوي على بعض الأمثلة الموضوعة على هيئة تعليقات بهدف التوضيح:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5470_65" style="">
<span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln">
</span><span class="com"># The simplest case: just add the domain name(s) and IP addresses of your Django server</span><span class="pln">
</span><span class="com"># ALLOWED_HOSTS = [ 'example.com', '203.0.113.5']</span><span class="pln">
</span><span class="com"># To respond to 'example.com' and any subdomains, start the domain with a dot</span><span class="pln">
</span><span class="com"># ALLOWED_HOSTS = ['.example.com', '203.0.113.5']</span><span class="pln">
ALLOWED_HOSTS </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'your_server_domain_or_IP'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'second_domain_or_IP'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.,</span><span class="pln"> </span><span class="str">'localhost'</span><span class="pun">]</span></pre>

<p>
	<strong>ملاحظة:</strong> تأكد من تضمين "localhost" ضمن الخيارات، لأنك ستحيلُ proxying الاتصالات من خلال نسخة إنجن إكس محلية.
</p>

<p>
	ثم أوجد القسمَ الذي يضبط الوصول إلى قاعدة البيانات، وهو يبدأ بالكلمة <code>DATABASES</code>.الضبط الموجود مسبقًا في الملف هو لقاعدة بيانات SQLite، ولكن نظرًا لأنك أنشأت قاعدة بيانات PostgreSQL لمشروعك فلا بُد من ضبط هذه الإعدادات.
</p>

<p>
	حدّث الإعدادات بمعلومات قاعدة بيانات PostgreSQL، ثم أخبر جانغو أن يستخدم الملائم <code>psycopg2</code> الذي ثبتته باستخدام <code>pip</code>. تحتاج أيضًا إلى التزويد باسم قاعدة البيانات واسم المستخدم لمستخدم قاعدة البيانات الذي أنشأته توًّا وكلمة المرور لمستخدم قاعدة البيانات والتحديد أيضًا بإمكانية العثور على قاعدة البيانات على الحاسوب المحلي، أما الإعداد <code>PORT</code> فيمكنك تركه سلسلةً فارغة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5470_67" style="">
<span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln">

DATABASES </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">'default'</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">'ENGINE'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'django.db.backends.postgresql_psycopg2'</span><span class="pun">,</span><span class="pln">
        </span><span class="str">'NAME'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'myproject'</span><span class="pun">,</span><span class="pln">
        </span><span class="str">'USER'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'myprojectuser'</span><span class="pun">,</span><span class="pln">
        </span><span class="str">'PASSWORD'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'password'</span><span class="pun">,</span><span class="pln">
        </span><span class="str">'HOST'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'localhost'</span><span class="pun">,</span><span class="pln">
        </span><span class="str">'PORT'</span><span class="pun">:</span><span class="pln"> </span><span class="str">''</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span></pre>

<p>
	ثم اذهب إلى نهاية الملف وأضف إعدادًا يشير إلى المكان الذي ينبغي أن توضع فيه الملفات الساكنة؛ وهذا ضروري ليتمكن إنجن إكس من معالجة الطلبات لتلك العناصر. يخبر السطر التالي جانغو أن يضع تلك الملفات الساكنة في مجلدٍ اسمه "static" في مجلد المشروع الأساسي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5470_69" style="">
<span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln">

STATIC_URL </span><span class="pun">=</span><span class="pln"> </span><span class="str">'/static/'</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> os
STATIC_ROOT </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">BASE_DIR</span><span class="pun">,</span><span class="pln"> </span><span class="str">'static/'</span><span class="pun">)</span></pre>

<p>
	احفظ الملف ثم أغلقه عندما تنتهي، وإذا كنت تستخدم محرر النصوص نانو يمكنك فعل ذلك بالضغط على المفتاحين "CTRL + X"، ثم المفتاح "Y و "ENTER".
</p>

<h2>
	الخطوة الخامسة - إكمال الإعداد المبدئي للمشروع
</h2>

<p>
	ستكون الخطوة التالية تهجير مخطط قاعدة البيانات المبدئي إلى قاعدة بيانات PostgreSQL باستخدام سكريبت الإدارة التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_71" style="">
<span class="pun">(</span><span class="pln">myprojectenv</span><span class="pun">)</span><span class="pln"> $ </span><span class="pun">~</span><span class="str">/myprojectdir/</span><span class="pln">manage</span><span class="pun">.</span><span class="pln">py makemigrations
</span><span class="pun">(</span><span class="pln">myprojectenv</span><span class="pun">)</span><span class="pln"> $ </span><span class="pun">~</span><span class="str">/myprojectdir/</span><span class="pln">manage</span><span class="pun">.</span><span class="pln">py migrate</span></pre>

<p>
	أنشئ مستخدمًا إداريًّا للمشروع:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_73" style="">
<span class="pun">(</span><span class="pln">myprojectenv</span><span class="pun">)</span><span class="pln"> $ </span><span class="pun">~</span><span class="str">/myprojectdir/</span><span class="pln">manage</span><span class="pun">.</span><span class="pln">py createsuperuser</span></pre>

<p>
	سيطلب منك اسم مستخدم وبريد إلكتروني وكلمة مرور مع تأكيدها.
</p>

<p>
	اجمع كل المحتوى الساكن في موقع المجلد الذي ضبطته بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_75" style="">
<span class="pun">(</span><span class="pln">myprojectenv</span><span class="pun">)</span><span class="pln"> $ </span><span class="pun">~</span><span class="str">/myprojectdir/</span><span class="pln">manage</span><span class="pun">.</span><span class="pln">py collectstatic</span></pre>

<p>
	عندئذ ستوضع الملفات الساكنة في مجلد اسمه "static" ضمن مجلد المشروع.
</p>

<p>
	إذا اتبعت دليل إعداد الخادم المبدئي فيفترض أن لديك <a href="https://academy.hsoub.com/devops/security/firewalls/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-ufw-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D9%88%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%B4%D8%A7%D8%A6%D8%B9%D8%A9-%D9%84%D9%84%D8%AC%D8%AF%D8%A7%D8%B1-%D8%A7%D9%84%D9%86%D8%A7%D8%B1%D9%8A-r121/" rel="">جدار ناري UFW</a> يحمي خادمك، ولكي تختبر خادم التطوير، ينبغي عليك السماح بالوصول إلى المنفذ الذي ستستخدمه. في هذه الحالة أنشئ استثناءً للمنفذ "8000":
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_84" style="">
<span class="pun">(</span><span class="pln">myprojectenv</span><span class="pun">)</span><span class="pln"> $ sudo ufw allow </span><span class="lit">8000</span></pre>

<p>
	أخيرًا افحص مشروعك بتشغيل خادم تطوير جانغو من خلال الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_80" style="">
<span class="pun">(</span><span class="pln">myprojectenv</span><span class="pun">)</span><span class="pln"> $ </span><span class="pun">~</span><span class="str">/myprojectdir/</span><span class="pln">manage</span><span class="pun">.</span><span class="pln">py runserver </span><span class="lit">0.0</span><span class="pun">.</span><span class="lit">0.0</span><span class="pun">:</span><span class="lit">8000</span></pre>

<p>
	في متصفح الويب استعرض اسم نطاق الخادم أو عنوان IP متبوعًا برقم المنفذ "8000:"، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_82" style="">
<span class="pln">http</span><span class="pun">:</span><span class="com">//server_domain_or_IP:8000</span></pre>

<p>
	عندئذ ستظهر لك الصفحة التالية وهي صفحة دليل جانغو الافتراضية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="114097" href="https://academy.hsoub.com/uploads/monthly_2022_12/002-django_index.png.7a961f0c559672ffe1145b8dc1e67e55.png" rel=""><img alt="صفحة دليل جانغو الافتراضية" class="ipsImage ipsImage_thumbnailed" data-fileid="114097" data-unique="dckwt01ln" src="https://academy.hsoub.com/uploads/monthly_2022_12/002-django_index.thumb.png.63875fd49f56245852ac54be60d6ed2a.png" style="width: 600px; height: auto;"></a>
</p>

<p>
	إذا ألحقت "admin/" بنهاية <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/" rel="">عنوان URL</a> في شريط العنوان، فسيُطلب منك اسم المستخدم وكلمة المرور الذين أنشأتهما بالأمر <code>createsuperuser</code>:
</p>

<p style="text-align: center;">
	<img alt="اسم المستخدم وكلمة المرور المضافين عبر بالأمر createsuperuser" class="ipsImage ipsImage_thumbnailed" data-fileid="114098" data-unique="bcmmcte4d" src="https://academy.hsoub.com/uploads/monthly_2022_12/639ac9edf1767_003-admin_login.png.f552acc02255c218d42cb7906e5fdc31.png" style="width: 380px; height: auto;"></p>

<p>
	يمكنك بعد الاستيثاق الوصول إلى واجهة جانغو الإدارية الافتراضية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="114099" href="https://academy.hsoub.com/uploads/monthly_2022_12/639ac9eeedbb4_004-admin_interface.png.279c6c5d78e2610878ef6c38f7378a8d.png" rel=""><img alt="الوصول إلى واجهة جانغو الإدارية الافتراضية" class="ipsImage ipsImage_thumbnailed" data-fileid="114099" data-unique="b685l5lni" src="https://academy.hsoub.com/uploads/monthly_2022_12/639ac9f06698b_004-admin_interface.thumb.png.9fc2d932e5fad82deba9b1bb603becb5.png" style="width: 700px; height: auto;"></a>
</p>

<p>
	بعد الانتهاء من استكشاف الواجهة الظاهرة أمامك، اضغط على المفتاحين "CTRL + C" في نافذة الطرفية لإيقاف تشغيل خادم التطوير.
</p>

<h2>
	الخطوة السادسة - اختبار قدرة غوني كورن على خدمة المشروع
</h2>

<p>
	اختبر الخادم غوني كورن قبل مغادرة البيئة الافتراضية للتأكد من أن بإمكانه أن يخدم التطبيق، وذلك من خلال الانتقال أولًا إلى داخل مجلد مشروعك:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_91" style="">
<span class="pun">(</span><span class="pln">myprojectenv</span><span class="pun">)</span><span class="pln"> $ cd </span><span class="pun">~/</span><span class="pln">myprojectdir</span></pre>

<p>
	ثم شغّل <code>gunicorn</code> ليحمّل وحدة <code>WSGI</code> للمشروع:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_93" style="">
<span class="pun">(</span><span class="pln">myprojectenv</span><span class="pun">)</span><span class="pln"> $ gunicorn </span><span class="pun">--</span><span class="pln">bind </span><span class="lit">0.0</span><span class="pun">.</span><span class="lit">0.0</span><span class="pun">:</span><span class="lit">8000</span><span class="pln"> myproject</span><span class="pun">.</span><span class="pln">wsgi</span></pre>

<p>
	سيشغل هذا الأمر خادم غوني كورن على نفس الواجهة التي كان يعمل عليها خادم تطوير جانغو. يمكنك العودة واختبار التطبيق مجددًا.
</p>

<p>
	<strong>ملاحظة:</strong> لن يكون في الواجهة الإدارية أي أنماط مُطبّقة، لأن الخادم غوني كورن لا يعرف كيف يعثر على محتوى <a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> الساكن المسؤول عن هذا الأمر.
</p>

<p>
	لنلخص ما أنُجز، فقد مرّرتَ وحدةً إلى الخادم غوني كورن بتحديد مسار المجلد النسبي إلى ملف جانغو المسمى "wsgi.py" والذي يمثّل نقطة الدخول إلى تطبيقك باستخدام بنية وحدة بايثون. يُستخدم الخادم غوني كورن مثل واجهة لتطبيقك ويترجم طلبات العملاء من نوع <a href="https://academy.hsoub.com/programming/general/%d9%85%d8%af%d8%ae%d9%84-%d8%a5%d9%84%d9%89-http-r73/" rel="">HTTP</a> إلى استدعاءات بايثون يمكن لتطبيقك معالجتها. أما داخل هذا الملف، فقد عُرّفت دالة <code>application</code>، التي تُستخدم للتواصل مع تطبيقك. وبإمكانك معرفة المزيد عن <a href="https://academy.hsoub.com/devops/deployment/%D8%AA%D8%AE%D8%AF%D9%8A%D9%85-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D9%81%D9%84%D8%A7%D8%B3%D9%83-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AE%D8%A7%D8%AF%D9%85%D9%8A-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-uwsgi-%D9%88-nginx-r649/" rel="">مواصفات WSGI</a> إذا كنت مهتمًا بهذا الموضوع.
</p>

<p>
	بعد أن تفرغ من الاختبار، اضغط على المفتاحين "CTRL + C" في نافذة الطرفية لإيقاف تشغيل الخادم غوني كورن، وبهذا تكون انتهيت من ضبط تطبيق جانغو وبإمكانك إلغاء تفعيل بيئتك الافتراضية:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_97" style="">
<span class="pun">(</span><span class="pln">myprojectenv</span><span class="pun">)</span><span class="pln"> $ deactivate</span></pre>

<p>
	سيُحذف مؤشر البيئة الافتراضية في المحثّ الظاهر أمامك.
</p>

<h2>
	الخطوة السابعة - إنشاء مقبس systemd وملفات خدمة لخادم غوني كورن
</h2>

<p>
	الآن بعد أن اختبرت وتأكدت أن بإمكان الخادم غوني كورن التفاعل مع تطبيقك المنشأ بجانغو، يجب أن تنفذ طريقةً أقوى في تشغيل وإطفاء خادم التطبيقات. ستنشئ من أجل هذا خدمة systemd وملفات مقبس.
</p>

<p>
	سينُشأ مقبس غوني كورن عند الإقلاع ويبدأ بالاستماع للاتصالات، وعندما يحدث اتصال ستشغِّل خدمة systemd تلقائيًّا عملية غوني كورن لمعالجة الاتصال.
</p>

<p>
	ابدأ بإنشاء وفتح ملف مقبس systemd لخادم غوني كورن مع صلاحيات sudo في محرر النصوص المفضل لديك:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_99" style="">
<span class="pln">$ sudo nano </span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">systemd</span><span class="pun">/</span><span class="pln">system</span><span class="pun">/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">socket</span></pre>

<p>
	أنشئ داخل الملف القسم <code>[Unit]</code> لوصف المقبس والقسم <code>[Socket]</code> لتعريف موقع المقبس والقسم <code>[Install]</code> للتأكد من أن المقبس يُنشأ في الوقت المناسب:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_104" style="">
<span class="pun">[</span><span class="typ">Unit</span><span class="pun">]</span><span class="pln">
</span><span class="typ">Description</span><span class="pun">=</span><span class="pln">gunicorn socket

</span><span class="pun">[</span><span class="typ">Socket</span><span class="pun">]</span><span class="pln">
</span><span class="typ">ListenStream</span><span class="pun">=</span><span class="str">/run/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">sock

</span><span class="pun">[</span><span class="typ">Install</span><span class="pun">]</span><span class="pln">
</span><span class="typ">WantedBy</span><span class="pun">=</span><span class="pln">sockets</span><span class="pun">.</span><span class="pln">target</span></pre>

<p>
	احفظ الملف وأغلقه عندما تنتهي، ثم أنشئ وافتح ملف خدمة systemd من أجل غوني كورن مع صلاحيات sudo في محرر النصوص المفضّل لديك، ويجب أن يطابق اسم ملف الخدمة اسم ملف المقبس باستثناء الامتداد:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_106" style="">
<span class="pln">$ sudo nano </span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">systemd</span><span class="pun">/</span><span class="pln">system</span><span class="pun">/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">service</span></pre>

<p>
	ابدأ بالقسم <code>[Unit]</code> المُستَخدم لتحديد البيانات الوصفية metadata والاعتماديات. أضف وصفًا لخدمتك هنا وأخبر نظام التهيئة "init system" أن يشغّل الخدمة فقط بعد الوصول إلى مستوى التشبيك المستهدف networking target. نظرًا لأن خدمتك تعتمد على المقبس من ملف المقبس، فستحتاج إلى تضمين الموجّه <code>Requires</code> للإشارة إلى تلك العلاقة:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_109" style="">
<span class="pun">[</span><span class="typ">Unit</span><span class="pun">]</span><span class="pln">
</span><span class="typ">Description</span><span class="pun">=</span><span class="pln">gunicorn daemon
</span><span class="typ">Requires</span><span class="pun">=</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">socket
</span><span class="typ">After</span><span class="pun">=</span><span class="pln">network</span><span class="pun">.</span><span class="pln">target</span></pre>

<p>
	ثم أضف القسم <code>[Service]</code> وحدّد المستخدم والمجموعة اللذين تريد أن تعمل العملية تحتهما. زوّد ملكيتك للعملية من خلال حساب مستخدم نظامي لأنها تمتلك كل الملفات المرتبطة، ثم زوّد ملكية مجموعتك إلى مجموعة "www-data" ليتمكن الخادم إنجن إكس من التواصل مع خادم غوني كورن.
</p>

<p>
	بعد ذلك، ارسم خطة المجلد العامل وحدّد الأمر الذي ستنفّذه لتشغيل العملية، وفي حالتنا هذه حدّد المسار الكامل للملف التنفيذي للخادم غوني كورن المثبت ضمن بيئتك الافتراضية، ثم اربط العملية بمقبس يونيكس Unix الذي أنشأته ضمن المجلد "run/" لكي تتمكن العملية من التواصل مع خادم إنجن إكس. سجّل كافة البيانات على أداة الخرج المعياري لكي تتمكن العملية <code>journald</code> من جمع سجلات الخادم غوني كورن. يمكنك أيضًا هنا تحديد أي إضافات اختيارية لخادم غوني كورن، إذ حدّدنا في مثالنا ثلاث عمليات عاملة على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_111" style="">
<span class="pun">[</span><span class="typ">Unit</span><span class="pun">]</span><span class="pln">
</span><span class="typ">Description</span><span class="pun">=</span><span class="pln">gunicorn daemon
</span><span class="typ">Requires</span><span class="pun">=</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">socket
</span><span class="typ">After</span><span class="pun">=</span><span class="pln">network</span><span class="pun">.</span><span class="pln">target

</span><span class="pun">[</span><span class="typ">Service</span><span class="pun">]</span><span class="pln">
</span><span class="typ">User</span><span class="pun">=</span><span class="pln">sammy
</span><span class="typ">Group</span><span class="pun">=</span><span class="pln">www</span><span class="pun">-</span><span class="pln">data
</span><span class="typ">WorkingDirectory</span><span class="pun">=</span><span class="str">/home/</span><span class="pln">sammy</span><span class="pun">/</span><span class="pln">myprojectdir
</span><span class="typ">ExecStart</span><span class="pun">=</span><span class="str">/home/</span><span class="pln">sammy</span><span class="pun">/</span><span class="pln">myprojectdir</span><span class="pun">/</span><span class="pln">myprojectenv</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">gunicorn \
          </span><span class="pun">--</span><span class="pln">access</span><span class="pun">-</span><span class="pln">logfile </span><span class="pun">-</span><span class="pln"> \
          </span><span class="pun">--</span><span class="pln">workers </span><span class="lit">3</span><span class="pln"> \
          </span><span class="pun">--</span><span class="pln">bind unix</span><span class="pun">:</span><span class="str">/run/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">sock \
          myproject</span><span class="pun">.</span><span class="pln">wsgi</span><span class="pun">:</span><span class="pln">application</span></pre>

<p>
	أخيرًا، أضف القسم <code>[Install]</code> الذي سيخبر systemd بماذا ستربط هذه الخدمة إذا فعّلتها للعمل عند الإقلاع، إذ أن الأفضل أن تعمل هذه الخدمة عندما يكون نظام المستخدمين المتعددين النظامي يعمل على النحو الصحيح والمطلوب:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_113" style="">
<span class="pun">[</span><span class="typ">Unit</span><span class="pun">]</span><span class="pln">
</span><span class="typ">Description</span><span class="pun">=</span><span class="pln">gunicorn daemon
</span><span class="typ">Requires</span><span class="pun">=</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">socket
</span><span class="typ">After</span><span class="pun">=</span><span class="pln">network</span><span class="pun">.</span><span class="pln">target

</span><span class="pun">[</span><span class="typ">Service</span><span class="pun">]</span><span class="pln">
</span><span class="typ">User</span><span class="pun">=</span><span class="pln">sammy
</span><span class="typ">Group</span><span class="pun">=</span><span class="pln">www</span><span class="pun">-</span><span class="pln">data
</span><span class="typ">WorkingDirectory</span><span class="pun">=</span><span class="str">/home/</span><span class="pln">sammy</span><span class="pun">/</span><span class="pln">myprojectdir
</span><span class="typ">ExecStart</span><span class="pun">=</span><span class="str">/home/</span><span class="pln">sammy</span><span class="pun">/</span><span class="pln">myprojectdir</span><span class="pun">/</span><span class="pln">myprojectenv</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">gunicorn \
          </span><span class="pun">--</span><span class="pln">access</span><span class="pun">-</span><span class="pln">logfile </span><span class="pun">-</span><span class="pln"> \
          </span><span class="pun">--</span><span class="pln">workers </span><span class="lit">3</span><span class="pln"> \
          </span><span class="pun">--</span><span class="pln">bind unix</span><span class="pun">:</span><span class="str">/run/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">sock \
          myproject</span><span class="pun">.</span><span class="pln">wsgi</span><span class="pun">:</span><span class="pln">application

</span><span class="pun">[</span><span class="typ">Install</span><span class="pun">]</span><span class="pln">
</span><span class="typ">WantedBy</span><span class="pun">=</span><span class="pln">multi</span><span class="pun">-</span><span class="pln">user</span><span class="pun">.</span><span class="pln">target</span></pre>

<p>
	وبهذا يكتمل ملف خدمة systemd، والآن احفظ الملف وأغلقه، ثم شغّل مقبس غوني كورن. سينشئ هذا ملف المقبس في المسار "run/gunicorn.sock/" الآن وكذلك عند الإقلاع:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_115" style="">
<span class="pln">$ sudo systemctl start gunicorn</span><span class="pun">.</span><span class="pln">socket</span></pre>

<p>
	ثم فعّله بحيث تشغّل systemd تلقائيًا خدمة <code>gunicorn.service</code> عندما يحدث اتصال مع ذاك المقبس لتتولى معالجته:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_118" style="">
<span class="pln">$ sudo systemctl enable gunicorn</span><span class="pun">.</span><span class="pln">socket</span></pre>

<p>
	يمكنك التحقق أن العملية نجحت من خلال التحقق من وجود ملف المقبس، وهذا موضوع الخطوة القادمة.
</p>

<h2>
	الخطوة الثامنة - التحقق من وجود ملف مقبس غوني كورن
</h2>

<p>
	افحص حالة العملية لتعرف ما إذا كانت قابلة للتشغيل:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_120" style="">
<span class="pln">$ sudo systemctl status gunicorn</span><span class="pun">.</span><span class="pln">socket</span></pre>

<p>
	وسيكون الخرج على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_122" style="">
<span class="pun">●</span><span class="pln"> gunicorn</span><span class="pun">.</span><span class="pln">socket </span><span class="pun">-</span><span class="pln"> gunicorn socket
     </span><span class="typ">Loaded</span><span class="pun">:</span><span class="pln"> loaded </span><span class="pun">(</span><span class="str">/etc/</span><span class="pln">systemd</span><span class="pun">/</span><span class="pln">system</span><span class="pun">/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">socket</span><span class="pun">;</span><span class="pln"> enabled</span><span class="pun">;</span><span class="pln"> vendor prese</span><span class="pun">&gt;</span><span class="pln">
     </span><span class="typ">Active</span><span class="pun">:</span><span class="pln"> active </span><span class="pun">(</span><span class="pln">listening</span><span class="pun">)</span><span class="pln"> since </span><span class="typ">Thu</span><span class="pln"> </span><span class="lit">2021</span><span class="pun">-</span><span class="lit">12</span><span class="pun">-</span><span class="lit">02</span><span class="pln"> </span><span class="lit">19</span><span class="pun">:</span><span class="lit">58</span><span class="pun">:</span><span class="lit">48</span><span class="pln"> UTC</span><span class="pun">;</span><span class="pln"> </span><span class="lit">14s</span><span class="pln"> ago
   </span><span class="typ">Triggers</span><span class="pun">:</span><span class="pln"> </span><span class="pun">●</span><span class="pln"> gunicorn</span><span class="pun">.</span><span class="pln">service
     </span><span class="typ">Listen</span><span class="pun">:</span><span class="pln"> </span><span class="str">/run/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">sock </span><span class="pun">(</span><span class="typ">Stream</span><span class="pun">)</span><span class="pln">
      </span><span class="typ">Tasks</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">(</span><span class="pln">limit</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1136</span><span class="pun">)</span><span class="pln">
     </span><span class="typ">Memory</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0B</span><span class="pln">
     </span><span class="typ">CGroup</span><span class="pun">:</span><span class="pln"> </span><span class="str">/system.slice/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">socket

</span><span class="typ">Dec</span><span class="pln"> </span><span class="lit">02</span><span class="pln"> </span><span class="lit">19</span><span class="pun">:</span><span class="lit">58</span><span class="pun">:</span><span class="lit">48</span><span class="pln"> gunicorn systemd</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]:</span><span class="pln"> </span><span class="typ">Listening</span><span class="pln"> on gunicorn socket</span><span class="pun">.</span></pre>

<p>
	ثم تحقق من وجود الملف "gunicorn.sock" ضمن المجلد "run/":
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_124" style="">
<span class="pln">$ file </span><span class="pun">/</span><span class="pln">run</span><span class="pun">/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">sock</span></pre>

<p>
	وسيكون الخرج على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_126" style="">
<span class="str">/run/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">sock</span><span class="pun">:</span><span class="pln"> socket</span></pre>

<p>
	إذا أشار الأمر<code>systemctl status</code> إلى حدوث خطأ، أو إذا لم تجد الملف "gunicorn.sock" في المجلد فإن هذه إشارة أننا لم ننجح في إنشاء مقبس غوني كورن. تفقّد سجلات مقبس غوني كورن بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_128" style="">
<span class="pln">$ sudo journalctl </span><span class="pun">-</span><span class="pln">u gunicorn</span><span class="pun">.</span><span class="pln">socket</span></pre>

<p>
	افحص الملف "etc/systemd/system/gunicorn.socket/" لإصلاح أي مشاكل قبل المتابعة.
</p>

<h2>
	الخطوة التاسعة - فحص تنشيط المقبس
</h2>

<p>
	إذا شغلت فقط الوحدة <code>gunicorn.socket</code>، لن تكون الخدمة <code>gunicorn.service</code> نشطةً لأن المقبس لن يكون قد استقبل أي اتصالات. لذلك افحص الحالة:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_130" style="">
<span class="pln">$ sudo systemctl status gunicorn</span></pre>

<p>
	وسيكون الخرج على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_132" style="">
<span class="pun">●</span><span class="pln"> gunicorn</span><span class="pun">.</span><span class="pln">service </span><span class="pun">-</span><span class="pln"> gunicorn daemon
   </span><span class="typ">Loaded</span><span class="pun">:</span><span class="pln"> loaded </span><span class="pun">(</span><span class="str">/etc/</span><span class="pln">systemd</span><span class="pun">/</span><span class="pln">system</span><span class="pun">/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">service</span><span class="pun">;</span><span class="pln"> disabled</span><span class="pun">;</span><span class="pln"> vendor preset</span><span class="pun">:</span><span class="pln"> enabled</span><span class="pun">)</span><span class="pln">
   </span><span class="typ">Active</span><span class="pun">:</span><span class="pln"> inactive </span><span class="pun">(</span><span class="pln">dead</span><span class="pun">)</span></pre>

<p>
	لفحص آلية تنشيط المقبس، أرسل اتصالًا إلى المقبس عبر <code>curl</code>:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_134" style="">
<span class="pln">$ curl </span><span class="pun">--</span><span class="pln">unix</span><span class="pun">-</span><span class="pln">socket </span><span class="pun">/</span><span class="pln">run</span><span class="pun">/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">sock localhost</span></pre>

<p>
	يفترض أن تتلقى خرج <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> من تطبيقك في الطرفية، وهذا يؤكد إقلاع خادم غوني كورن وأنه قادر على خدمة تطبيق جانغو الخاص بك. يمكنك التحقق من أن خدمة غوني كورن تعمل من خلال فحص الحالة مرة أخرى:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_137" style="">
<span class="pln">$ sudo systemctl status gunicorn</span></pre>

<p>
	وسيكون الخرج على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_139" style="">
<span class="pun">●</span><span class="pln">  gunicorn</span><span class="pun">.</span><span class="pln">service </span><span class="pun">-</span><span class="pln"> gunicorn daemon
   </span><span class="typ">Loaded</span><span class="pun">:</span><span class="pln"> loaded </span><span class="pun">(</span><span class="str">/etc/</span><span class="pln">systemd</span><span class="pun">/</span><span class="pln">system</span><span class="pun">/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">service</span><span class="pun">;</span><span class="pln"> disabled</span><span class="pun">;</span><span class="pln"> vendor preset
   </span><span class="typ">Active</span><span class="pun">:</span><span class="pln"> active </span><span class="pun">(</span><span class="pln">running</span><span class="pun">)</span><span class="pln"> since </span><span class="typ">Tue</span><span class="pln"> </span><span class="lit">2021</span><span class="pun">-</span><span class="lit">11</span><span class="pun">-</span><span class="lit">23</span><span class="pln"> </span><span class="lit">22</span><span class="pun">:</span><span class="lit">55</span><span class="pun">:</span><span class="lit">12</span><span class="pln"> UTC</span><span class="pun">;</span><span class="pln"> </span><span class="lit">11s</span><span class="pln"> ago
 </span><span class="typ">Main</span><span class="pln"> <abbr title="Process IDentifier | معرّف العملية أو البرنامج">PID</abbr></span><span class="pun">:</span><span class="pln"> </span><span class="lit">11002</span><span class="pln"> </span><span class="pun">(</span><span class="pln">gunicorn</span><span class="pun">)</span><span class="pln">
    </span><span class="typ">Tasks</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">(</span><span class="pln">limit</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1151</span><span class="pun">)</span><span class="pln">
   </span><span class="typ">CGroup</span><span class="pun">:</span><span class="pln"> </span><span class="str">/system.slice/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">service
           </span><span class="pun">├─</span><span class="lit">11002</span><span class="pln"> </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="pln">sammy</span><span class="pun">/</span><span class="pln">myprojectdir</span><span class="pun">/</span><span class="pln">myprojectenv</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">python </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="pln">sammy</span><span class="pun">/</span><span class="pln">
           </span><span class="pun">├─</span><span class="lit">11018</span><span class="pln"> </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="pln">sammy</span><span class="pun">/</span><span class="pln">myprojectdir</span><span class="pun">/</span><span class="pln">myprojectenv</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">python </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="pln">sammy</span><span class="pun">/</span><span class="pln">
           </span><span class="pun">├─</span><span class="lit">11020</span><span class="pln"> </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="pln">sammy</span><span class="pun">/</span><span class="pln">myprojectdir</span><span class="pun">/</span><span class="pln">myprojectenv</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">python </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="pln">sammy</span><span class="pun">/</span><span class="pln">
           </span><span class="pun">└─</span><span class="lit">11022</span><span class="pln"> </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="pln">sammy</span><span class="pun">/</span><span class="pln">myprojectdir</span><span class="pun">/</span><span class="pln">myprojectenv</span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">python </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="pln">sammy</span><span class="pun">/</span><span class="pln">
</span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span><span class="pln"> </span><span class="pun">.</span></pre>

<p>
	إذا أشار الخرج من جرّاء تنفيذ <code>curl</code> أو الخرج من <code>systemctl status</code> إلى أن مشكلةً قد وقعت، افحص سجلات التفاصيل الإضافية:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_141" style="">
<span class="pln">$ sudo journalctl </span><span class="pun">-</span><span class="pln">u gunicorn</span></pre>

<p>
	افحص الملف "etc/systemd/system/gunicorn.service/" بحثًا عن المشاكل، وإذا أجريت تغييرات على الملف "etc/systemd/system/gunicorn.service/"، فأعد تحميل العملية الخفية daemon لإعادة قراءة تعريف الخدمة:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_143" style="">
<span class="pln">$ sudo systemctl daemon</span><span class="pun">-</span><span class="pln">reload</span></pre>

<p>
	ثم أعد تشغيل خدمة غوني كورن:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_145" style="">
<span class="pln">$ sudo systemctl restart gunicorn</span></pre>

<p>
	إذا ظهرت أي مشاكل مثل هذه، فأصلحها قبل المتابعة.
</p>

<h2>
	الخطوة العاشرة - ضبط الخادم إنجن إكس لتمرير الخادم الوكيل إلى خادم غوني كورن
</h2>

<p>
	الآن بعد إعداد غوني كورن، ستضبط الخادم إنجن إكس لتمرير حركة البيانات في الشبكة إلى العملية. ابدأ بإنشاء وفتح كتلة خادم جديدة في مجلد إنجن إكس المسمى "sites-available" كما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_147" style="">
<span class="pln">$ sudo nano </span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">/</span><span class="pln">sites</span><span class="pun">-</span><span class="pln">available</span><span class="pun">/</span><span class="pln">myproject</span></pre>

<p>
	افتح داخله كتلة خادم جديدة، وابدأ بتحديد أن هذه الكتلة ينبغي أن تستمع على المنفذ الطبيعي 80 وأن تستجيب لاسم نطاق خادمك أو عنوان IP الخاص به:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_149" style="">
<span class="pln">server </span><span class="pun">{</span><span class="pln">
    listen </span><span class="lit">80</span><span class="pun">;</span><span class="pln">
    server_name server_domain_or_IP</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ثم اطلب من الخادم إنجن إكس أن يتجاهل أي مشاكل متعلقة بإيجاد الأيقونة المفضلة favicon، وأخبره أيضًا أين يجد الأصول الساكنة التي جمعتها في مجلدك المسمى "myprojectdir/static/~". تمتلك جميع هذه الملفات سابقة URI معيارية بقيمة "static/"، لذا يمكنك إنشاء كتلة موقع لمطابقة تلك الطلبات:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_152" style="">
<span class="pln">server </span><span class="pun">{</span><span class="pln">
    listen </span><span class="lit">80</span><span class="pun">;</span><span class="pln">
    server_name server_domain_or_IP</span><span class="pun">;</span><span class="pln">

    location </span><span class="pun">=</span><span class="pln"> </span><span class="pun">/</span><span class="pln">favicon</span><span class="pun">.</span><span class="pln">ico </span><span class="pun">{</span><span class="pln"> access_log off</span><span class="pun">;</span><span class="pln"> log_not_found off</span><span class="pun">;</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
    location </span><span class="pun">/</span><span class="kwd">static</span><span class="pun">/</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        root </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="pln">sammy</span><span class="pun">/</span><span class="pln">myprojectdir</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أخيرًا، أنشئ كتلة <code>location / {}‎</code> لمطابقة كافة الطلبات الأخرى، وضمّن داخلَ هذا الموقع الملفَّ المعياري "proxy_params" من تثبيت إنجن إكس، ثم حدّد حركة مرور بيانات الشبكة مباشرةً إلى مقبس غوني كورن:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_154" style="">
<span class="pln">server </span><span class="pun">{</span><span class="pln">
    listen </span><span class="lit">80</span><span class="pun">;</span><span class="pln">
    server_name server_domain_or_IP</span><span class="pun">;</span><span class="pln">

    location </span><span class="pun">=</span><span class="pln"> </span><span class="pun">/</span><span class="pln">favicon</span><span class="pun">.</span><span class="pln">ico </span><span class="pun">{</span><span class="pln"> access_log off</span><span class="pun">;</span><span class="pln"> log_not_found off</span><span class="pun">;</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
    location </span><span class="pun">/</span><span class="kwd">static</span><span class="pun">/</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        root </span><span class="pun">/</span><span class="pln">home</span><span class="pun">/</span><span class="pln">sammy</span><span class="pun">/</span><span class="pln">myprojectdir</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    location </span><span class="pun">/</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        include proxy_params</span><span class="pun">;</span><span class="pln">
        proxy_pass http</span><span class="pun">:</span><span class="com">//unix:/run/gunicorn.sock;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	احفظ الملف وأغلقه عند الانتهاء.
</p>

<p>
	يمكنك الآن تفعيل الملف بربطه مع المجلد "sites-enabled":
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_156" style="">
<span class="pln">$ sudo ln </span><span class="pun">-</span><span class="pln">s </span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">/</span><span class="pln">sites</span><span class="pun">-</span><span class="pln">available</span><span class="pun">/</span><span class="pln">myproject </span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">/</span><span class="pln">sites</span><span class="pun">-</span><span class="pln">enabled</span></pre>

<p>
	أجرِ اختبارًا لتتأكد من خلو ضبط الخادم إنجن إكس من الأخطاء الكتابية:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_158" style="">
<span class="pln">$ sudo nginx </span><span class="pun">-</span><span class="pln">t</span></pre>

<p>
	إذا لم تظهر أي أخطاء، فتابع وأعد تشغيل خادم إنجن إكس:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_161" style="">
<span class="pln">$ sudo systemctl restart nginx</span></pre>

<p>
	ونظرًا لأنك لا تحتاج بعد الآن إلى وصول إلى خادم التطوير، اضبط إعدادات الجدار الناري بحذف قاعدة المنفذ المفتوح "8000":
</p>

<pre class="ipsCode">
$ sudo ufw delete allow 8000
</pre>

<p>
	ثم اسمح لبيانات الشبكة العادية بالمرور من المنفذين "80" و"443" مما سيسمح بحدوث اتصالات HTTP و HTTPS على التوالي، وذلك باستخدام الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_163" style="">
<span class="pln">$ sudo ufw allow </span><span class="str">'Nginx Full'</span></pre>

<p>
	يُفترض أن يكون بمقدورك الآن الذهاب إلى نطاق خادمك أو عنوان IP الخاص به لمشاهدة تطبيقك.
</p>

<p>
	<strong>ملاحظة:</strong> بعد الانتهاء من ضبط إنجن إكس ستكون الخطوة التالية هي تأمين بيانات الشبكة إلى الخادم باستخدام بروتوكول <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr>/<abbr title="Transport Layer Security | بروتوكول أمن طبقة النقل">TLS</abbr>، وهذا مهم لأنه بدونه ستُرسل جميع المعلومات بما فيها كلمات المرور عبر الشبكة بصيغة نصيّةٍ صرفة plain text.
</p>

<p>
	إذا كان لديك اسم نطاق فأسرعُ طريقة للحصول على شهادة <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> لتأمين بيانات الشبكة هو استخدام Let's Encrypt. يمكنك إعداده من خلال متابعة دليلنا <a href="hhttps://academy.hsoub.com/devops/servers/%D8%AA%D9%86%D8%B5%D9%8A%D8%A8-%D8%B4%D9%87%D8%A7%D8%AF%D8%A9-ssl-%D9%85%D8%AC%D8%A7%D9%86%D9%8A%D8%A9-%D8%B9%D8%A8%D8%B1-%D8%AE%D8%AF%D9%85%D8%A9-lets-encrypt-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%88%D9%85-%D9%84%D9%8A%D9%86%D9%83%D8%B3-r151/" rel="">كيف تؤمن Let's Encrypt باستخدام إنجن إكس على نظام أبونتو 18.04</a>. اتبع الدليل باستخدام كتلة خادم إنجن إكس التي أنشأتها في هذا الدليل.
</p>

<p>
	إذا لم يكن لديك اسم نطاق، فلا يزال بإمكانك تأمين موقعك للاختبار والتعلم باستخدام <a href="https://academy.hsoub.com/devops/servers/web/apache/%D9%83%D9%8A%D9%81-%D8%AA%D9%86%D8%B4%D8%A6-%D8%B4%D9%87%D8%A7%D8%AF%D8%A9-ssl-%D9%85%D9%88%D9%91%D9%8E%D9%82%D8%B9%D8%A9-%D8%B0%D8%A7%D8%AA%D9%8A%D9%91%D9%8B%D8%A7-%D9%84%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85%D9%87%D8%A7-%D9%85%D8%B9-%D8%AE%D8%A7%D8%AF%D9%88%D9%85-%D8%A7%D9%84%D9%88%D9%90%D8%A8-apache-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1604-r325/" rel="">self-signed <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> Certificate</a>، ونشدّد على اتباع العملية باستخدام كتلة خادم إنجن إكس التي أنشأتها في هذه المقالة.
</p>

<h2>
	الخطوة الحادية عشرة - استكشاف المشاكل وإصلاحها في خادمي إنجن إكس وغوني كورن
</h2>

<p>
	إذا كنت تواجه مشكلات في تطبيقك، فقد أضفنا الأقسام التالية لتدلك على طرق إصلاح مشكلات التثبيت.
</p>

<h3>
	يظهر الخادم إنجن إكس الصفحة الافتراضية بدلا من إظهار تطبيق جانغو
</h3>

<p>
	إذا كان إنجن إكس يعرض الصفحة الافتراضية بدلًا من إحالة الخادم الوكيل إلى تطبيقك، فذلك يعني غالبًا أنك بحاجة إلى ضبط <code>server_name</code> ضمن الملف "etc/nginx/sites-available/myproject/" ليشير إلى عنوان IP لخادمك، أو اسم نطاقه.
</p>

<p>
	يستخدم إنجن إكس الموجه <code>server_name</code> ليحدد كتلة الخادم التي سيستخدمها للاستجابة للطلبات؛ فإذا كانت تظهر لك صفحة إنجن إكس الافتراضية ففي هذا دلالة على الخادم إنجن إكس لم يستطع مطابقة الطلب مع كتلة الخادم صراحةً لذا تراجع إلى الكتلة الافتراضية المعرّفة في الملف "etc/nginx/sites-available/default/".
</p>

<p>
	يجب أن يكون الموجه <code>server_name</code> في كتلة خادم المشروع أكثر تحديدًا من الموجّه المُختار في كتلة الخادم الافتراضية.
</p>

<h3>
	يعرض الخادم إنجن إكس الخطأ 502 Bad Gateway بدلا من عرضه تطبيق جانغو
</h3>

<p>
	يشير الخطأ 502 إلى أن الخادم إنجن إكس لم ينجح في إحالة الطلب مثل خادم وكيل. وهناك عدد كبير من الأخطاء التي تعبر عن نفسها بالخطأ 502، لذا ستحتاج إلى معلومات أكثر لتصل إلى الخطأ الفعلي وتصلحه.
</p>

<p>
	والمكان الأساسي الذي يجب أن تبحث فيه عن مزيد من المعلومات هو سجل أخطاء إنجن إكس؛ فهو يخبرنا عمومًا عن الظروف التي سببت الخطأ أثناء حدث الإحالة من الخادم الوكيل Proxying. تفقد سجل أخطاء الخادم إنجن إكس بالتعليمة التالية:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_165" style="">
<span class="pln">$ sudo tail </span><span class="pun">-</span><span class="pln">F </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">log</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">/</span><span class="pln">error</span><span class="pun">.</span><span class="pln">log</span></pre>

<p>
	والآن أسس طلبًا آخرًا في متصفحك لتوليد خطأ جديد (حاول إنعاش refresh الصفحة). يُفترض أن تتلقى رسالة خطأ جديدة مسجلة في السجل. إذا قرأت الرسالة وفهمتها فستضيّق نطاق المشكلة.
</p>

<p>
	ربما تتلقى رسالة تشبه ما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_167" style="">
<span class="pln"> connect</span><span class="pun">()</span><span class="pln"> to unix</span><span class="pun">:</span><span class="str">/run/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">sock failed </span><span class="pun">(</span><span class="lit">2</span><span class="pun">:</span><span class="pln"> </span><span class="typ">No</span><span class="pln"> such file </span><span class="kwd">or</span><span class="pln"> directory</span><span class="pun">)</span></pre>

<p>
	التي تشير إلى أن إنجن إكس لم يستطع العثور على الملف "gunicorn.sock" في الموقع المُعطى. ينبغي مقارنة الموقع "proxy_pass" المعرف ضمن الملف "etc/nginx/sites-available/myproject/" مع الموقع الفعلي للملف "gunicorn.sock" الذي ولدته وحدة systemd المسماة "gunicorn.socket".
</p>

<p>
	إذا لم تتمكن من العثور على الملف "gunicorn.sock" ضمن المجلد "run/"، فهذا يعني عمومًا أن ملف مقبس systemd لم يتمكن من إنشائه. عُد إلى القسم من مقالتنا هذه الذي يتكلم عن البحث عن ملف مقبس غوني كورن للسير وفق خطوات الإصلاح لمشكلات الخادم غوني كورن.
</p>

<p>
	وقد تقرأ رسالةً أخرى تشبه التالية:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_169" style="">
<span class="pln">connect</span><span class="pun">()</span><span class="pln"> to unix</span><span class="pun">:</span><span class="str">/run/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">sock failed </span><span class="pun">(</span><span class="lit">13</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Permission</span><span class="pln"> denied</span><span class="pun">)</span></pre>

<p>
	التي تشير هذه إلى أن الخادم إنجن إكس لم يتمكن من الاتصال بمقبس غوني كورن بسبب مشكلات تتعلق بالأذونات، ويُحتمل أن يحدث هذا عندما يُتبع الإجراء باستخدام المستخدم الجذر "root" بدلًا من المستخدم "sudo". وقد تدل الرسالة إلى أنه في الوقت الذي تستطيع systemd إنشاء ملف مقبس غوني كورن، لم يتمكن الخادم إنجن إكس من الوصول إليه.
</p>

<p>
	يمكن لهذا أن يحدث إذا كانت هناك محدودية في الأذونات في أي نقطة بين المجلد الجذر والملف "gunicorn.sock"، ويمكنك استعراض الأذونات وقيم الملكية لملف المقبس وكل من المجلدات الآباء له بتمرير المسار المطلق إلى ملف المقبس الخاص بك إلى الأمر <code>namei</code>:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_171" style="">
<span class="pln">$ namei </span><span class="pun">-</span><span class="pln">l </span><span class="pun">/</span><span class="pln">run</span><span class="pun">/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">sock</span></pre>

<p>
	وسيكون الخرج على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_174" style="">
<span class="pln">f</span><span class="pun">:</span><span class="pln"> </span><span class="str">/run/</span><span class="pln">gunicorn</span><span class="pun">.</span><span class="pln">sock
drwxr</span><span class="pun">-</span><span class="pln">xr</span><span class="pun">-</span><span class="pln">x root root </span><span class="pun">/</span><span class="pln">
drwxr</span><span class="pun">-</span><span class="pln">xr</span><span class="pun">-</span><span class="pln">x root root run
srw</span><span class="pun">-</span><span class="pln">rw</span><span class="pun">-</span><span class="pln">rw</span><span class="pun">-</span><span class="pln"> root root gunicorn</span><span class="pun">.</span><span class="pln">sock</span></pre>

<p>
	يعرض الخرج أذونات كل مكون من مكونات المجلد، ويمكنك تصور نوع الوصول المسموح إلى ملف المقبس باستعراض الأذونات(العمود الأول) والمالك (العمود الثاني) ومالك المجموعة(العمود الثالث).
</p>

<p>
	يملك ملف المقبس في هذا المثال وكل مجلد من المجلدات التي تؤدي إليه أذونات قراءة read وتنفيذ execute (ينتهي عمود الأذونات للمجلدات بالامتداد <code>r-x</code> بدلًا من <code>---</code>). يجب أن تكون العملية إنجن إكس قادرة على الوصول إلى المقبس بنجاح.
</p>

<p>
	إذا لم يمتلك أي من المجلدات التي تؤدي إلى المقبس إذن قراءة أو تنفيذ عامة، فلن يتمكن الخادم إنجن إكس من الوصول إلى المقبس دون السماح بأذونات قراءة أو تنفيذ عامة أو بإعطاء ملكية المجموعة إلى مجموعة ينتمي إليها الخادم إنجن إكس.
</p>

<h3>
	جانغو يعرض الرسالة could not connect to server: Connection refused
</h3>

<p>
	من الرسائل التي يمكن أن تتلقاها عند محاولة الوصول إلى أجزاء من التطبيق في متصفح الويب هي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_176" style="">
<span class="typ">OperationalError</span><span class="pln"> at </span><span class="pun">/</span><span class="pln">admin</span><span class="pun">/</span><span class="pln">login</span><span class="pun">/</span><span class="pln">
could </span><span class="kwd">not</span><span class="pln"> connect to server</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Connection</span><span class="pln"> refused
    </span><span class="typ">Is</span><span class="pln"> the server running on host </span><span class="str">"localhost"</span><span class="pln"> </span><span class="pun">(</span><span class="lit">127.0</span><span class="pun">.</span><span class="lit">0.1</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> accepting
    TCP</span><span class="pun">/</span><span class="pln">IP connections on port </span><span class="lit">5432</span><span class="pun">?</span></pre>

<p>
	التي يشير هذا إلى أن جانغو لم يتمكن من الاتصال بقاعدة بيانات Postgres. لذا تأكد أن نسخة Postgres تعمل كما يلي:
</p>

<pre class="ipsCode">
$ sudo systemctl status postgresql
</pre>

<p>
	إذا لم تكن تعمل، فيمكنك تشغيلها وضبط إمكانية تشغيلها تلقائيًا عند الإقلاع (إذا لم تكن معدةً هكذا من قبل):
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_178" style="">
<span class="pln">$ sudo systemctl start postgresql
$ sudo systemctl enable postgresql</span></pre>

<p>
	إذا استمر الخلل، فتأكد أن إعدادات قاعدة البيانات المعرفة في الملف "myprojectdir/myproject/settings.py/~" صحيحة.
</p>

<h3>
	مزيد من استكشاف الأخطاء وإصلاحها
</h3>

<p>
	إذا أردت المزيد من استكشاف الأخطاء وإصلاحها فيمكن للسجلات أن تساعدك على تضييق نطاق البحث في الأسباب الجذرية. تفقد كلًّا منها وسجّل ملاحظاتك عن أي رسائل تشير إلى منطقة مشاكل.
</p>

<p>
	قد تساعدك السجلات التالية في عملك:
</p>

<ul>
<li>
		فحص سجلات عملية إنجن إكس كما يلي:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_183" style="">
<span class="pln">sudo journalctl </span><span class="pun">-</span><span class="pln">u nginx</span></pre>

<ul>
<li>
		فحص سجلات الوصول إلى إنجن إكس كما يلي:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_181" style="">
<span class="pln">sudo less </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">log</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">/</span><span class="pln">access</span><span class="pun">.</span><span class="pln">log</span></pre>

<ul>
<li>
		فحص سجلات الخطأ لإنجن إكس كما يلي:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_185" style="">
<span class="pln">sudo less </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">log</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">/</span><span class="pln">error</span><span class="pun">.</span><span class="pln">log</span></pre>

<ul>
<li>
		فحص سجلات تطبيق غوني كورن كما يلي:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_187" style="">
<span class="pln">sudo journalctl </span><span class="pun">-</span><span class="pln">u gunicorn</span></pre>

<ul>
<li>
		فحص سجلات مقابس غوني كورن كما يلي:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_189" style="">
<span class="pln">sudo journalctl </span><span class="pun">-</span><span class="pln">u gunicorn</span><span class="pun">.</span><span class="pln">socket</span></pre>

<p>
	ستحتاج غالبًا أثناء تحديثك للتهيئة أو التطبيق إلى إعادة تشغيل العمليات لضبط تغييراتك.
</p>

<p>
	إذا حدثت تطبيق جانغو، يمكن إعادة تشغيل العملية غوني كورن لتطبيق التغييرات بتنفيذ التالي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_191" style="">
<span class="pln">$ sudo systemctl restart gunicorn</span></pre>

<p>
	إذا غيرت ملفات خدمة أو مقبس غوني كورن أعد تحميل العملية الخفية daemon وأعد تشغيل العملية بتنفيذ التعليمات التالية:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_197" style="">
<span class="pln">$ sudo systemctl daemon</span><span class="pun">-</span><span class="pln">reload
$ sudo systemctl restart gunicorn</span><span class="pun">.</span><span class="pln">socket gunicorn</span><span class="pun">.</span><span class="pln">service</span></pre>

<p>
	إذا غيرت تهيئة كتلة خادم إنجن إكس، افحص الضبط ثم إنجن إكس بتنفيذ ما يلي:
</p>

<pre class="ipsCode prettyprint lang-sql prettyprinted" id="ips_uid_5470_201" style="">
<span class="pln">$ sudo nginx </span><span class="pun">-</span><span class="pln">t </span><span class="pun">&amp;&amp;</span><span class="pln"> sudo systemctl restart nginx</span></pre>

<p>
	هذه الأوامر مفيدة جدًا لتطبيق التغييرات أثناء الضبط.
</p>

<h2>
	خاتمة
</h2>

<p>
	أعددت في هذه المقالة مشروع جانغو في بيته الافتراضية الخاصة وضبطت خادم غوني كورن لترجمة طلبات العملاء لتمكين جانغو من معالجتها. بعد ذلك، أعددت خادم إنجن إكس ليعمل مثل خادم وكيل معكوس ليتولى معالجة اتصالات العملاء ويخدم المشروع المناسب اعتمادًا على طلب العميل.
</p>

<p>
	يبسّط جانغو عملية إنشاء الكائنات والتطبيقات من خلال تزويدك بكثير من القطع المشتركة، مما يسمح لك بالتركيز على العناصر المتفردة unique. وبرفع سلسلة الأدوات العامة الموصوفة في هذه المقالة يمكنك خدمة التطبيقات التي أنشأتها من خادم وحيد.
</p>

<p>
	ترجمة - وبتصرف - للمقالة <a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-ubuntu-18-04" rel="external nofollow">How To Set Up Django with Postgres, Nginx, and Gunicorn on Ubuntu 18.04</a> لصاحبها Justin Ellingwood.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/devops/deployment/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-asgi-django-%D9%84%D9%84%D9%86%D8%B4%D8%B1-%D9%85%D8%B9-postgres-%D9%88%D8%AE%D8%A7%D8%AF%D9%85-nginx-%D9%85%D8%B9-uvicorn-r666/" rel="">إعداد تطبيق ASGI Django للنشر مع Postgres وخادم Nginx مع Uvicorn</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/deployment/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%AC%D8%A7%D9%87%D8%B2-%D9%84%D9%84%D9%86%D8%B4%D8%B1-%D9%85%D8%B9-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-%D9%88%D8%AE%D8%A7%D8%AF%D9%85-nginx-%D9%88-gunicorn-r663/" rel="">إعداد تطبيق جانغو جاهز للنشر مع قاعدة بيانات Postgres وخادم Nginx و </a><a href="https://academy.hsoub.com/devops/deployment/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D8%AC%D8%A7%D9%87%D8%B2-%D9%84%D9%84%D9%86%D8%B4%D8%B1-%D9%85%D8%B9-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-postgres-%D9%88%D8%AE%D8%A7%D8%AF%D9%85-nginx-%D9%88-gunicorn-r663/" rel="">Gunicorn</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/python/django/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%AC%D8%A7%D9%86%D8%BA%D9%88-%D9%88%D8%AA%D9%88%D8%B5%D9%8A%D9%84%D9%87-%D8%A8%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r1626/" rel="">إنشاء تطبيق جانغو وتوصيله بقاعدة بيانات</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">667</guid><pubDate>Thu, 15 Dec 2022 08:13:45 +0000</pubDate></item><item><title>&#x62A;&#x634;&#x63A;&#x64A;&#x644; &#x645;&#x648;&#x642;&#x639; &#x648;&#x648;&#x631;&#x62F;&#x628;&#x631;&#x64A;&#x633; &#x639;&#x628;&#x631; &#x62E;&#x627;&#x62F;&#x645; Nginx</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%85%D9%88%D9%82%D8%B9-%D9%88%D9%88%D8%B1%D8%AF%D8%A8%D8%B1%D9%8A%D8%B3-%D8%B9%D8%A8%D8%B1-%D8%AE%D8%A7%D8%AF%D9%85-nginx-r592/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_02/6217381c15287_-----Nginx-.png.d0d6c42d306d61901e57c531d02498af.png" /></p>

<p>
	رغم أنَّ حزمة LAMP، المكونة من <a href="https://academy.hsoub.com/devops/linux/%D9%85%D8%A7-%D9%87%D9%88-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%8A%D9%86%D9%83%D8%B3%D8%9F-r451/" rel="">لينكس Linux</a> وأباتشي Apache و<a href="https://academy.hsoub.com/devops/servers/databases/mysql/%D8%AA%D8%B9%D9%84%D9%85-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-mysql-r297/" rel="">MySQL</a> و<a href="https://wiki.hsoub.com/PHP" rel="external">PHP</a>، تحظى بشعبية كبيرة في تشغيل ووردبريس، لكن يمكن استخدام Nginx -تلفظ إنجن إكس- أيضًا إذ يدعمه ووردبريس، وهو يُشغَّل بعض مواقع ووردبريس الكبيرة، مثل WordPress.com.
</p>

<p>
	من المهم عند الحديث عن Nginx معرفة أنه توجد طرق متعددة لتطبيقه، ويمكن إعداده مثل وكيل عكسي أمام Apache، وهو إعداد قوي للغاية يسمح لك باستخدام جميع ميزات وقوة Apache مع الاستفادة من سرعة Nginx، ومعظم مواقع الويب التي تستخدم Nginx خادمًا -بناءًا على الإحصائيات التي جُمعت من ترويسات استجابة HTTP- هي في الواقع تعمل على Apache مع Nginx وكيلًا عكسيًا، حيث تعرض ترويسات استجابة HTTP إحصائيات استخدام Nginx وكيلًا عكسيًا وليس خادمًا.
</p>

<p>
	يشير هذا الدليل إلى إعداد Nginx مستقل، حيث يُستخدم خادمًا أساسيًا بدلاً من أباتشي، ويجب الإشارة إلى أنَّ Nginx ليس بديلاً تمامًا عن Apache، حيث توجد بعض الاختلافات الرئيسية التي تؤثر على تطبيق ووردبريس، والتي يجب أن تكون على دراية بها قبل المتابعة:
</p>

<ul>
<li>
		عند استخدام Nginx لا يوجد ملف تهيئة على مستوى الدليل، مثل الملف htaccess. الخاص بخادم Apache، أو ملفات web.config الخاصة بالخادم IIS، ويجب إجراء كامل التهيئة على مستوى الخادم من قبل المدير، ولا يمكن تعديل الإعدادات في ووردبريس كما هو الحال مع Apache أو IIS.
	</li>
	<li>
		تختلف الروابط الثابتة قليلاً عند تشغيل Nginx.
	</li>
	<li>
		لا يحتوي Nginx على صلاحيات من نوع htaccess.، ولا يمكن تعديل إعدادات الخادم تلقائيًا عبر ووردبريس، لذا لا يمكنه إنشاء قواعد إعادة الكتابة.
	</li>
	<li>
		سيضاف "index.php" إلى روابطك الثابتة دون تعديلات على تثبيتك الخاص، وتوجد طرق لتجاوز هذا باستخدام بعض الإضافات، أو إضافة شيفرة مخصصة إلى function.php لقالبك، أو بالطريقتين معًا.
	</li>
	<li>
		إذا أردت الحصول على بعض الإمكانيات المحدودة للملف htaccess.، فمن الممكن تقنيًا الإضافة عن طريق تثبيت <a href="http://php.net/manual/en/book.htscanner.php" rel="external nofollow">ملحق htscanner PECL لـ PHP</a>، إلا أن هذا ليس حلًا مثاليًا لذا تأكد من ذلك واختبره تمامًا قبل استخدامه المباشر على الموقع.
	</li>
</ul>
<p>
	لن يغطي هذا الدليل كيفية تثبيت Nginx وإعداداته، لذلك يفترض أنك ثبّتت Nginx، وتعلم كيفية التعامل معه وتصحيح أخطائه.
</p>

<h2>
	الدعم العام ومتعدد المواقع
</h2>

<p>
	يجب ضبط الواجهة الخلفية php-cgi حتى يعمل ووردبريس مع Nginx، والخيارات المتاحة هي fastcgi أو php-fpm، ويُستخدَم php-fpm لأنه مضمَّن في إصدار PHP 5.3 وما بعده، لذا فتثبيته مباشر.
</p>

<p>
	قُسمت إعدادت Nginx إلى خمسة ملفات مميزة، مع التعليق عليها لتسهيل فهمها، كما بذل <a href="https://wordpress.org/support/profile/bigsite" rel="external nofollow">المؤلف</a> كل جهده في محاولة اتباع "أفضل الممارسات" لإعدادات nginx.
</p>

<h2>
	ملف بدء التشغيل الرئيسي (العام)
</h2>

<p>
	يكافئ هذا /etc/nginx/nginx.conf أو /etc/nginx/conf/nginx.conf عند استخدام لينكس Arch.
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_20" style="">
<span class="com"># Generic startup file.</span><span class="pln">
user </span><span class="pun">{</span><span class="pln">user</span><span class="pun">}</span><span class="pln"> </span><span class="pun">{</span><span class="kwd">group</span><span class="pun">};</span><span class="pln">

</span><span class="com">#usually equal to number of CPUs you have. run command "grep processor /proc/cpuinfo | wc -l" to find it</span><span class="pln">
worker_processes  </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
worker_cpu_affinity </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">

error_log  </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">log</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">/</span><span class="pln">error</span><span class="pun">.</span><span class="pln">log</span><span class="pun">;</span><span class="pln">
pid        </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">run</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">.</span><span class="pln">pid</span><span class="pun">;</span><span class="pln">

</span><span class="com"># Keeps the logs free of messages about not being able to bind().</span><span class="pln">
</span><span class="com">#daemon     off;</span><span class="pln">

events </span><span class="pun">{</span><span class="pln">
    worker_connections  </span><span class="lit">1024</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

http </span><span class="pun">{</span><span class="pln">
</span><span class="com">#   rewrite_log on;</span><span class="pln">

    include mime</span><span class="pun">.</span><span class="pln">types</span><span class="pun">;</span><span class="pln">
    default_type       application</span><span class="pun">/</span><span class="pln">octet</span><span class="pun">-</span><span class="pln">stream</span><span class="pun">;</span><span class="pln">
    access_log         </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">log</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">/</span><span class="pln">access</span><span class="pun">.</span><span class="pln">log</span><span class="pun">;</span><span class="pln">
    sendfile           on</span><span class="pun">;</span><span class="pln">
</span><span class="com">#   tcp_nopush         on;</span><span class="pln">
    keepalive_timeout  </span><span class="lit">3</span><span class="pun">;</span><span class="pln">
</span><span class="com">#   tcp_nodelay        on;</span><span class="pln">
</span><span class="com">#   gzip               on;</span><span class="pln">
        </span><span class="com">#php max upload limit cannot be larger than this       </span><span class="pln">
    client_max_body_size </span><span class="lit">13m</span><span class="pun">;</span><span class="pln">
    index              index</span><span class="pun">.</span><span class="pln">php index</span><span class="pun">.</span><span class="pln">html index</span><span class="pun">.</span><span class="pln">htm</span><span class="pun">;</span><span class="pln">

    </span><span class="com"># Upstream to abstract backend connection(s) for PHP.</span><span class="pln">
    upstream php </span><span class="pun">{</span><span class="pln">
                </span><span class="com">#this should match value of "listen" directive in php-fpm pool</span><span class="pln">
        server unix</span><span class="pun">:</span><span class="str">/tmp/</span><span class="pln">php</span><span class="pun">-</span><span class="pln">fpm</span><span class="pun">.</span><span class="pln">sock</span><span class="pun">;</span><span class="pln">
</span><span class="com">#       server 127.0.0.1:9000;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    include sites</span><span class="pun">-</span><span class="pln">enabled</span><span class="com">/*;
}</span></pre>

<p>
	يختلف هذا قليلًا عن ملفات nginx.conf القياسية، ويتبع هذا الإعداد طريقة Ubuntu/Debian لجعل المواقع المفعلة بأقصى درجة مرونة، باستخدام "sites-available" لتخزين الإعدادات، ثم الربط بملف الإعدادات من "sites-enabled".
</p>

<h2>
	حسب إعدادات الموقع
</h2>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_31" style="">
<span class="com"># Redirect everything to the main site. We use a separate server statement and NOT an if statement - see http://wiki.nginx.org/IfIsEvil</span><span class="pln">

server </span><span class="pun">{</span><span class="pln">
        server_name  _</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">302</span><span class="pln"> $scheme</span><span class="pun">:</span><span class="com">//example.com$request_uri;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

server </span><span class="pun">{</span><span class="pln">
    server_name example</span><span class="pun">.</span><span class="pln">com</span><span class="pun">;</span><span class="pln">
    root </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">www</span><span class="pun">/</span><span class="pln">example</span><span class="pun">.</span><span class="pln">com</span><span class="pun">;</span><span class="pln">

    index index</span><span class="pun">.</span><span class="pln">php</span><span class="pun">;</span><span class="pln">

    include </span><span class="kwd">global</span><span class="pun">/</span><span class="pln">restrictions</span><span class="pun">.</span><span class="pln">conf</span><span class="pun">;</span><span class="pln">

    </span><span class="com"># Additional rules go here.</span><span class="pln">

    </span><span class="com"># Only include one of the files below.</span><span class="pln">
    include </span><span class="kwd">global</span><span class="pun">/</span><span class="pln">wordpress</span><span class="pun">.</span><span class="pln">conf</span><span class="pun">;</span><span class="pln">
</span><span class="com">#    include global/wordpress-ms-subdir.conf;</span><span class="pln">
</span><span class="com">#    include global/wordpress-ms-subdomain.conf;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يسمح فصل أقسام الإعدادات إلى ملفات متعددة بإعادة استخدام نفس المنطق مرارًا وتكرارًا، ويُستخدم الدليل الفرعي "global" لإضافة صلاحيات إضافية للاستخدام للأغراض العامة، /etc/nginx/conf/global/ أو /etc/nginx/global/، بناءً على كيفية إعداد تثبيت nginx.
</p>

<h2>
	ملف القيود الشامل
</h2>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_33" style="">
<span class="com"># Global restrictions configuration file.</span><span class="pln">
</span><span class="com"># Designed to be included in any server {} block.</span><span class="pln">
location </span><span class="pun">=</span><span class="pln"> </span><span class="pun">/</span><span class="pln">favicon</span><span class="pun">.</span><span class="pln">ico </span><span class="pun">{</span><span class="pln">
    log_not_found off</span><span class="pun">;</span><span class="pln">
    access_log off</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

location </span><span class="pun">=</span><span class="pln"> </span><span class="pun">/</span><span class="pln">robots</span><span class="pun">.</span><span class="pln">txt </span><span class="pun">{</span><span class="pln">
    allow all</span><span class="pun">;</span><span class="pln">
    log_not_found off</span><span class="pun">;</span><span class="pln">
    access_log off</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com"># Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).</span><span class="pln">
</span><span class="com"># Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)</span><span class="pln">
location </span><span class="pun">~</span><span class="pln"> </span><span class="pun">/</span><span class="pln">\. </span><span class="pun">{</span><span class="pln">
    deny all</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com"># Deny access to any files with a .php extension in the uploads directory</span><span class="pln">
</span><span class="com"># Works in sub-directory installs and also in multisite network</span><span class="pln">
</span><span class="com"># Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)</span><span class="pln">
location </span><span class="pun">~*</span><span class="pln"> </span><span class="pun">/(?:</span><span class="pln">uploads</span><span class="pun">|</span><span class="pln">files</span><span class="pun">)/.*</span><span class="pln">\.php$ </span><span class="pun">{</span><span class="pln">
    deny all</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	مبادئ ووردبريس العامة
</h2>

<p>
	للتثبيت في موقع مفرد إليك ملف global/wordpress.conf:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_35" style="">
<span class="com"># WordPress single site rules.</span><span class="pln">
</span><span class="com"># Designed to be included in any server {} block.</span><span class="pln">
</span><span class="com"># Upstream to abstract backend connection(s) for php</span><span class="pln">
upstream php </span><span class="pun">{</span><span class="pln">
        server unix</span><span class="pun">:</span><span class="str">/tmp/</span><span class="pln">php</span><span class="pun">-</span><span class="pln">cgi</span><span class="pun">.</span><span class="pln">socket</span><span class="pun">;</span><span class="pln">
        server </span><span class="lit">127.0</span><span class="pun">.</span><span class="lit">0.1</span><span class="pun">:</span><span class="lit">9000</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

server </span><span class="pun">{</span><span class="pln">
        </span><span class="com">## Your website name goes here.</span><span class="pln">
        server_name domain</span><span class="pun">.</span><span class="pln">tld</span><span class="pun">;</span><span class="pln">
        </span><span class="com">## Your only path reference.</span><span class="pln">
        root </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">www</span><span class="pun">/</span><span class="pln">wordpress</span><span class="pun">;</span><span class="pln">
        </span><span class="com">## This should be in your http block and if it is, it's not needed here.</span><span class="pln">
        index index</span><span class="pun">.</span><span class="pln">php</span><span class="pun">;</span><span class="pln">

        location </span><span class="pun">=</span><span class="pln"> </span><span class="pun">/</span><span class="pln">favicon</span><span class="pun">.</span><span class="pln">ico </span><span class="pun">{</span><span class="pln">
                log_not_found off</span><span class="pun">;</span><span class="pln">
                access_log off</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        location </span><span class="pun">=</span><span class="pln"> </span><span class="pun">/</span><span class="pln">robots</span><span class="pun">.</span><span class="pln">txt </span><span class="pun">{</span><span class="pln">
                allow all</span><span class="pun">;</span><span class="pln">
                log_not_found off</span><span class="pun">;</span><span class="pln">
                access_log off</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        location </span><span class="pun">/</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="com"># This is cool because no php is touched for static content.</span><span class="pln">
                </span><span class="com"># include the "?$args" part so non-default permalinks doesn't break when using query string</span><span class="pln">
                try_files $uri $uri</span><span class="pun">/</span><span class="pln"> </span><span class="pun">/</span><span class="pln">index</span><span class="pun">.</span><span class="pln">php</span><span class="pun">?</span><span class="pln">$args</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        location </span><span class="pun">~</span><span class="pln"> \.php$ </span><span class="pun">{</span><span class="pln">
                </span><span class="com">#NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini</span><span class="pln">
                include fastcgi</span><span class="pun">.</span><span class="pln">conf</span><span class="pun">;</span><span class="pln">
                fastcgi_intercept_errors on</span><span class="pun">;</span><span class="pln">
                fastcgi_pass php</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        location </span><span class="pun">~*</span><span class="pln"> \.</span><span class="pun">(</span><span class="pln">js</span><span class="pun">|</span><span class="pln">css</span><span class="pun">|</span><span class="pln">png</span><span class="pun">|</span><span class="pln">jpg</span><span class="pun">|</span><span class="pln">jpeg</span><span class="pun">|</span><span class="pln">gif</span><span class="pun">|</span><span class="pln">ico</span><span class="pun">)</span><span class="pln">$ </span><span class="pun">{</span><span class="pln">
                expires max</span><span class="pun">;</span><span class="pln">
                log_not_found off</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	<a href="https://www.nginx.com/resources/wiki/start/topics/recipes/wordpress/" rel="external nofollow">إليك مثالًا حديثًا عن Nginx</a>
</p>

<h2>
	مبادئ الدليل الفرعي لووردبريس متعدد المواقع
</h2>

<p>
	لتثبيت الدليل الفرعي متعدد المواقع إليك ملف global/wordpress.conf:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_28" style="">
<span class="com"># WordPress multisite subdirectory rules.</span><span class="pln">
</span><span class="com"># Designed to be included in any server {} block.</span><span class="pln">

map $uri $blogname</span><span class="pun">{</span><span class="pln">
    </span><span class="pun">~^(?</span><span class="pln">P</span><span class="pun">/[^</span><span class="str">/]+/</span><span class="pun">)</span><span class="pln">files</span><span class="pun">/(.*)</span><span class="pln">       $blogpath </span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

map $blogname $blogid</span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">-</span><span class="lit">999</span><span class="pun">;</span><span class="pln">

    </span><span class="com">#Ref: https://wordpress.org/extend/plugins/nginx-helper/</span><span class="pln">
    </span><span class="com">#include</span><span class="pln"> </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">www</span><span class="pun">/</span><span class="pln">wordpress</span><span class="pun">/</span><span class="pln">wp</span><span class="pun">-</span><span class="pln">content</span><span class="pun">/</span><span class="pln">plugins</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">-</span><span class="pln">helper</span><span class="pun">/</span><span class="pln">map</span><span class="pun">.</span><span class="pln">conf </span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

server </span><span class="pun">{</span><span class="pln">
    server_name example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">;</span><span class="pln">

    root </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">www</span><span class="pun">/</span><span class="pln">example</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">htdocs</span><span class="pun">;</span><span class="pln">
    index index</span><span class="pun">.</span><span class="pln">php</span><span class="pun">;</span><span class="pln">

    location </span><span class="pun">~</span><span class="pln"> </span><span class="pun">^(</span><span class="str">/[^/]+/</span><span class="pun">)?</span><span class="pln">files</span><span class="pun">/(.+)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        try_files </span><span class="pun">/</span><span class="pln">wp</span><span class="pun">-</span><span class="pln">content</span><span class="pun">/</span><span class="pln">blogs</span><span class="pun">.</span><span class="pln">dir</span><span class="pun">/</span><span class="pln">$blogid</span><span class="pun">/</span><span class="pln">files</span><span class="pun">/</span><span class="pln">$2 </span><span class="pun">/</span><span class="pln">wp</span><span class="pun">-</span><span class="pln">includes</span><span class="pun">/</span><span class="pln">ms</span><span class="pun">-</span><span class="pln">files</span><span class="pun">.</span><span class="pln">php</span><span class="pun">?</span><span class="pln">file</span><span class="pun">=</span><span class="pln">$2 </span><span class="pun">;</span><span class="pln">
        access_log off</span><span class="pun">;</span><span class="pln">     log_not_found off</span><span class="pun">;</span><span class="pln"> expires max</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="com">#avoid php readfile()</span><span class="pln">
    location </span><span class="pun">^~</span><span class="pln"> </span><span class="pun">/</span><span class="pln">blogs</span><span class="pun">.</span><span class="pln">dir </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">internal</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">alias</span><span class="pln"> </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">www</span><span class="pun">/</span><span class="pln">example</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">htdocs</span><span class="pun">/</span><span class="pln">wp</span><span class="pun">-</span><span class="pln">content</span><span class="pun">/</span><span class="pln">blogs</span><span class="pun">.</span><span class="pln">dir </span><span class="pun">;</span><span class="pln">
        access_log off</span><span class="pun">;</span><span class="pln">     log_not_found off</span><span class="pun">;</span><span class="pln"> expires max</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!-</span><span class="pln">e $request_filename</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        rewrite </span><span class="pun">/</span><span class="pln">wp</span><span class="pun">-</span><span class="pln">admin$ $scheme</span><span class="pun">:</span><span class="com">//$host$request_uri/ permanent;</span><span class="pln">
        rewrite </span><span class="pun">^(</span><span class="str">/[^/]+)?(/</span><span class="pln">wp</span><span class="pun">-.*)</span><span class="pln"> $2 </span><span class="kwd">last</span><span class="pun">;</span><span class="pln">
        rewrite </span><span class="pun">^(</span><span class="str">/[^/]+)?(/</span><span class="pun">.*</span><span class="pln">\.php</span><span class="pun">)</span><span class="pln"> $2 </span><span class="kwd">last</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    location </span><span class="pun">/</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        try_files $uri $uri</span><span class="pun">/</span><span class="pln"> </span><span class="pun">/</span><span class="pln">index</span><span class="pun">.</span><span class="pln">php</span><span class="pun">?</span><span class="pln">$args </span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    location </span><span class="pun">~</span><span class="pln"> \.php$ </span><span class="pun">{</span><span class="pln">
        try_files $uri </span><span class="pun">=</span><span class="lit">404</span><span class="pun">;</span><span class="pln">
        include fastcgi_params</span><span class="pun">;</span><span class="pln">
        fastcgi_pass php</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="com">#add some rules for static content expiry-headers here</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يوفر NGINX توجيهين خاصين هما X-Accel-Redirect و map، ويمكن للمستخدم باستخدامهما إلغاء أداء خدمة الملفات الثابتة على <a href="https://academy.hsoub.com/apps/web/wordpress/%D9%85%D8%AA%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%B4%D8%A8%D9%83%D8%A9-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D9%88%D9%88%D8%B1%D8%AF%D8%A8%D8%B1%D9%8A%D8%B3-%D9%85%D8%AA%D8%B9%D8%AF%D8%AF%D8%A9-r641/" rel="">شبكة ووردبريس متعددة المواقع</a>.
</p>

<h2>
	مبادئ النطاق الفرعي لووردبريس متعدد المواقع
</h2>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_38" style="">
<span class="pln">map $http_host $blogid </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">default</span><span class="pln">       </span><span class="pun">-</span><span class="lit">999</span><span class="pun">;</span><span class="pln">

    </span><span class="com">#Ref: https://wordpress.org/extend/plugins/nginx-helper/</span><span class="pln">
    </span><span class="com">#include</span><span class="pln"> </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">www</span><span class="pun">/</span><span class="pln">wordpress</span><span class="pun">/</span><span class="pln">wp</span><span class="pun">-</span><span class="pln">content</span><span class="pun">/</span><span class="pln">plugins</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">-</span><span class="pln">helper</span><span class="pun">/</span><span class="pln">map</span><span class="pun">.</span><span class="pln">conf </span><span class="pun">;</span><span class="pln">

</span><span class="pun">}</span><span class="pln">

server </span><span class="pun">{</span><span class="pln">
    server_name example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">*.</span><span class="pln">example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">;</span><span class="pln">

    root </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">www</span><span class="pun">/</span><span class="pln">example</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">htdocs</span><span class="pun">;</span><span class="pln">
    index index</span><span class="pun">.</span><span class="pln">php</span><span class="pun">;</span><span class="pln">

    location </span><span class="pun">/</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        try_files $uri $uri</span><span class="pun">/</span><span class="pln"> </span><span class="pun">/</span><span class="pln">index</span><span class="pun">.</span><span class="pln">php</span><span class="pun">?</span><span class="pln">$args </span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    location </span><span class="pun">~</span><span class="pln"> \.php$ </span><span class="pun">{</span><span class="pln">
        try_files $uri </span><span class="pun">=</span><span class="lit">404</span><span class="pun">;</span><span class="pln">
        include fastcgi_params</span><span class="pun">;</span><span class="pln">
        fastcgi_pass php</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="com">#WPMU Files</span><span class="pln">
        location </span><span class="pun">~</span><span class="pln"> </span><span class="pun">^</span><span class="str">/files/</span><span class="pun">(.*)</span><span class="pln">$ </span><span class="pun">{</span><span class="pln">
                try_files </span><span class="pun">/</span><span class="pln">wp</span><span class="pun">-</span><span class="pln">content</span><span class="pun">/</span><span class="pln">blogs</span><span class="pun">.</span><span class="pln">dir</span><span class="pun">/</span><span class="pln">$blogid</span><span class="pun">/</span><span class="pln">$uri </span><span class="pun">/</span><span class="pln">wp</span><span class="pun">-</span><span class="pln">includes</span><span class="pun">/</span><span class="pln">ms</span><span class="pun">-</span><span class="pln">files</span><span class="pun">.</span><span class="pln">php</span><span class="pun">?</span><span class="pln">file</span><span class="pun">=</span><span class="pln">$1 </span><span class="pun">;</span><span class="pln">
                access_log off</span><span class="pun">;</span><span class="pln"> log_not_found off</span><span class="pun">;</span><span class="pln">      expires max</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

    </span><span class="com">#WPMU x-sendfile to avoid php readfile()</span><span class="pln">
    location </span><span class="pun">^~</span><span class="pln"> </span><span class="pun">/</span><span class="pln">blogs</span><span class="pun">.</span><span class="pln">dir </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">internal</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">alias</span><span class="pln"> </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">www</span><span class="pun">/</span><span class="pln">example</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">htdocs</span><span class="pun">/</span><span class="pln">wp</span><span class="pun">-</span><span class="pln">content</span><span class="pun">/</span><span class="pln">blogs</span><span class="pun">.</span><span class="pln">dir</span><span class="pun">;</span><span class="pln">
        access_log off</span><span class="pun">;</span><span class="pln">     log_not_found off</span><span class="pun">;</span><span class="pln">      expires max</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="com">#add some rules for static content expiry-headers here</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	HTTPS في Nginx
</h2>

<p>
	يعد تفعيل HTTPS في Nginx أمرًا بسيطًا نسبيًا.
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_40" style="">
<span class="pln">server </span><span class="pun">{</span><span class="pln">
    </span><span class="com"># listens both on IPv4 and IPv6 on 443 and enables HTTPS and HTTP/2 support.</span><span class="pln">
    </span><span class="com"># HTTP/2 is available in nginx 1.9.5 and above.</span><span class="pln">
    listen </span><span class="pun">*:</span><span class="lit">443</span><span class="pln"> <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr> http2</span><span class="pun">;</span><span class="pln">
    listen </span><span class="pun">[::]:</span><span class="lit">443</span><span class="pln"> <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr> http2</span><span class="pun">;</span><span class="pln">

    </span><span class="com"># indicate locations of <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> key files.</span><span class="pln">
    ssl_certificate </span><span class="pun">/</span><span class="pln">srv</span><span class="pun">/</span><span class="pln">www</span><span class="pun">/</span><span class="pln"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></span><span class="pun">/</span><span class="pln"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></span><span class="pun">.</span><span class="pln">crt</span><span class="pun">;</span><span class="pln">
    ssl_certificate_key </span><span class="pun">/</span><span class="pln">srv</span><span class="pun">/</span><span class="pln">www</span><span class="pun">/</span><span class="pln"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></span><span class="pun">/</span><span class="pln"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></span><span class="pun">.</span><span class="pln">key</span><span class="pun">;</span><span class="pln">
    ssl_dhparam </span><span class="pun">/</span><span class="pln">srv</span><span class="pun">/</span><span class="pln">www</span><span class="pun">/</span><span class="pln">master</span><span class="pun">/</span><span class="pln"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></span><span class="pun">/</span><span class="pln">dhparam</span><span class="pun">.</span><span class="pln">pem</span><span class="pun">;</span><span class="pln">

    </span><span class="com"># indicate the server name</span><span class="pln">
    server_name example</span><span class="pun">.</span><span class="pln">com </span><span class="pun">*.</span><span class="pln">example</span><span class="pun">.</span><span class="pln">com</span><span class="pun">;</span><span class="pln">

    </span><span class="com"># Enable HSTS. This forces <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> on clients that respect it, most modern browsers. The includeSubDomains flag is optional.</span><span class="pln">
    add_header </span><span class="typ">Strict</span><span class="pun">-</span><span class="typ">Transport</span><span class="pun">-</span><span class="typ">Security</span><span class="pln"> </span><span class="str">"max-age=31536000; includeSubDomains"</span><span class="pun">;</span><span class="pln">

    </span><span class="com"># Set caches, protocols, and accepted ciphers. This config will merit an A+ <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> Labs score as of Sept 2015.</span><span class="pln">
    ssl_session_cache shared</span><span class="pun">:</span><span class="pln"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr></span><span class="pun">:</span><span class="lit">20m</span><span class="pun">;</span><span class="pln">
    ssl_session_timeout </span><span class="lit">10m</span><span class="pun">;</span><span class="pln">
    ssl_protocols </span><span class="typ">TLSv1</span><span class="pln"> </span><span class="typ">TLSv1</span><span class="pun">.</span><span class="lit">1</span><span class="pln"> </span><span class="typ">TLSv1</span><span class="pun">.</span><span class="lit">2</span><span class="pun">;</span><span class="pln">
    ssl_prefer_server_ciphers on</span><span class="pun">;</span><span class="pln">
    ssl_ciphers </span><span class="str">'ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تقدم Mozilla <a href="https://mozilla.github.io/server-side-tls/ssl-config-generator/" rel="external nofollow">أداة إنشاء تكوين <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> ممتازةً</a> أيضًا.
</p>

<h2>
	قواعد ذاكرة التخزين المؤقت الفائقة WP
</h2>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_42" style="">
<span class="com"># WP Super Cache rules.</span><span class="pln">
</span><span class="com"># Designed to be included from a 'wordpress-ms-```' configuration file.</span><span class="pln">

</span><span class="kwd">set</span><span class="pln"> $cache_uri $request_uri</span><span class="pun">;</span><span class="pln">

</span><span class="com"># POST requests and urls with a query string should always go to PHP</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$request_method </span><span class="pun">=</span><span class="pln"> POST</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">set</span><span class="pln"> $cache_uri </span><span class="str">'null cache'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$query_string </span><span class="pun">!=</span><span class="pln"> </span><span class="str">""</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">set</span><span class="pln"> $cache_uri </span><span class="str">'null cache'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">  

</span><span class="com"># Don't cache uris containing the following segments</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$request_uri </span><span class="pun">~*</span><span class="pln"> </span><span class="str">"(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">set</span><span class="pln"> $cache_uri </span><span class="str">'null cache'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">  

</span><span class="com"># Don't use the cache for logged in users or recent commenters</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$http_cookie </span><span class="pun">~*</span><span class="pln"> </span><span class="str">"comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">set</span><span class="pln"> $cache_uri </span><span class="str">'null cache'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="com"># START MOBILE</span><span class="pln">
</span><span class="com"># Mobile browsers section to server them non-cached version. COMMENTED by default as most modern wordpress themes including twenty-eleven are responsive. Uncomment config lines in this section if you want to use a plugin like WP-Touch</span><span class="pln">
</span><span class="com"># if ($http_x_wap_profile) {</span><span class="pln">
</span><span class="com">#        set $cache_uri 'null cache';</span><span class="pln">
</span><span class="com">#}</span><span class="pln">

</span><span class="com">#if ($http_profile) {</span><span class="pln">
</span><span class="com">#        set $cache_uri 'null cache';</span><span class="pln">
</span><span class="com">#}</span><span class="pln">

</span><span class="com">#if ($http_user_agent ~* (2.0\ MMP|240x320|400X240|AvantGo|BlackBerry|Blazer|Cellphone|Danger|DoCoMo|Elaine/3.0|EudoraWeb|Googlebot-Mobile|hiptop|IEMobile|KYOCERA/WX310K|LG/U990|MIDP-2.|MMEF20|MOT-V|NetFront|Newt|Nintendo\ Wii|Nitro|Nokia|Opera\ Mini|Palm|PlayStation\ Portable|portalmmm|Proxinet|ProxiNet|SHARP-TQ-GX10|SHG-i900|Small|SonyEricsson|Symbian\ OS|SymbianOS|TS21i-10|UP.Browser|UP.Link|webOS|Windows\ CE|WinWAP|YahooSeeker/M1A1-R2D2|iPhone|iPod|Android|BlackBerry9530|LG-TU915\ Obigo|LGE\ VX|webOS|Nokia5800)) {</span><span class="pln">
 </span><span class="com">#       set $cache_uri 'null cache';</span><span class="pln">
</span><span class="com">#}</span><span class="pln">

</span><span class="com">#if ($http_user_agent ~* (w3c\ |w3c-|acs-|alav|alca|amoi|audi|avan|benq|bird|blac|blaz|brew|cell|cldc|cmd-|dang|doco|eric|hipt|htc_|inno|ipaq|ipod|jigs|kddi|keji|leno|lg-c|lg-d|lg-g|lge-|lg/u|maui|maxo|midp|mits|mmef|mobi|mot-|moto|mwbp|nec-|newt|noki|palm|pana|pant|phil|play|port|prox|qwap|sage|sams|sany|sch-|sec-|send|seri|sgh-|shar|sie-|siem|smal|smar|sony|sph-|symb|t-mo|teli|tim-|tosh|tsm-|upg1|upsi|vk-v|voda|wap-|wapa|wapi|wapp|wapr|webc|winw|winw|xda\ |xda-)) {</span><span class="pln">
  </span><span class="com">#      set $cache_uri 'null cache';</span><span class="pln">
</span><span class="com">#}</span><span class="pln">
</span><span class="com">#END MOBILE</span><span class="pln">

</span><span class="com"># Use cached or actual file if they exists, otherwise pass request to WordPress</span><span class="pln">
location </span><span class="pun">/</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        try_files </span><span class="pun">/</span><span class="pln">wp</span><span class="pun">-</span><span class="pln">content</span><span class="pun">/</span><span class="pln">cache</span><span class="pun">/</span><span class="pln">supercache</span><span class="pun">/</span><span class="pln">$http_host</span><span class="pun">/</span><span class="pln">$cache_uri</span><span class="pun">/</span><span class="pln">index</span><span class="pun">.</span><span class="pln">html $uri $uri</span><span class="pun">/</span><span class="pln"> </span><span class="pun">/</span><span class="pln">index</span><span class="pun">.</span><span class="pln">php</span><span class="pun">?</span><span class="pln">$args </span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3>
	التعديلات التجريبية
</h3>

<p>
	إذا كنت تستخدم HTTPS فقد تستخدم أحدث نسخة مطورة من WP Super Cache بنية دليل مختلفةً للتمييز بين <a href="https://academy.hsoub.com/programming/general/%d9%85%d8%af%d8%ae%d9%84-%d8%a5%d9%84%d9%89-http-r73/" rel="">HTTP</a> وHTTPS، وقد يبدو سطر try_files كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_303_46" style="">
<span class="pln">location / {
        try_files /wp-content/cache/supercache/$http_host/$cache_uri/index-https.html $uri $uri/ /index.php?$args ;
}</span></pre>

<h2>
	قواعد ذاكرة التخزين المؤقتة W3 Total Cache
</h2>

<p>
	تستخدم W3 Total Cache بنية دليل مختلفةً لذاكرة التخزين المؤقت على القرص اعتمادًا على تكوين ووردبريس، وتبقى عمليات التحقق من صحة ذاكرة التخزين المؤقت كما هو موضح أدناه:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_48" style="">
<span class="com">#W3 TOTAL CACHE CHECK</span><span class="pln">
</span><span class="kwd">set</span><span class="pln"> $cache_uri $request_uri</span><span class="pun">;</span><span class="pln">

</span><span class="com"># POST requests and urls with a query string should always go to PHP</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$request_method </span><span class="pun">=</span><span class="pln"> POST</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">set</span><span class="pln"> $cache_uri </span><span class="str">'null cache'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">  
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$query_string </span><span class="pun">!=</span><span class="pln"> </span><span class="str">""</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">set</span><span class="pln"> $cache_uri </span><span class="str">'null cache'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">  

</span><span class="com"># Don't cache uris containing the following segments</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$request_uri </span><span class="pun">~*</span><span class="pln"> </span><span class="str">"(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">set</span><span class="pln"> $cache_uri </span><span class="str">'null cache'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">  

</span><span class="com"># Don't use the cache for logged in users or recent commenters</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$http_cookie </span><span class="pun">~*</span><span class="pln"> </span><span class="str">"comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">set</span><span class="pln"> $cache_uri </span><span class="str">'null cache'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">#ADD mobile rules from WP SUPER CACHE section above</span><span class="pln">

</span><span class="com">#APPEND A CODE BLOCK FROM BELOW```</span></pre>

<p>
	استخدم ما يلي لووردبريس العادي، بدون مواقع متعددة:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_50" style="">
<span class="com"># Use cached or actual file if they exists, otherwise pass request to WordPress</span><span class="pln">
location </span><span class="pun">/</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        try_files </span><span class="pun">/</span><span class="pln">wp</span><span class="pun">-</span><span class="pln">content</span><span class="pun">/</span><span class="pln">w3tc</span><span class="pun">/</span><span class="pln">pgcache</span><span class="pun">/</span><span class="pln">$cache_uri</span><span class="pun">/</span><span class="pln">_index</span><span class="pun">.</span><span class="pln">html $uri $uri</span><span class="pun">/</span><span class="pln"> </span><span class="pun">/</span><span class="pln">index</span><span class="pun">.</span><span class="pln">php</span><span class="pun">?</span><span class="pln">$args </span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وللمواقع المتعددة مع الأدلة الفرعية استخدم:
</p>

<pre class="ipsCode">
if ( $request_uri ~* "^/([_0-9a-zA-Z-]+)/.*" ){
        set $blog $1;
}

set $blog "${blog}.";

if ( $blog = "blog." ){
        set $blog "";
}

# Use cached or actual file if they exists, otherwise pass request to WordPress
location / {
        try_files /wp-content/w3tc-$blog$host/pgcache$cache_uri/_index.html $uri $uri/ /index.php?$args ;
}
</pre>

<p>
	ولمواقع متعددة مع نطاقات فرعية أو تعيين النطاق استخدم:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_52" style="">
<span class="pln">location </span><span class="pun">/</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        try_files </span><span class="pun">/</span><span class="pln">wp</span><span class="pun">-</span><span class="pln">content</span><span class="pun">/</span><span class="pln">w3tc</span><span class="pun">-</span><span class="pln">$host</span><span class="pun">/</span><span class="pln">pgcache</span><span class="pun">/</span><span class="pln">$cache_uri</span><span class="pun">/</span><span class="pln">_index</span><span class="pun">.</span><span class="pln">html $uri $uri</span><span class="pun">/</span><span class="pln"> </span><span class="pun">/</span><span class="pln">index</span><span class="pun">.</span><span class="pln">php</span><span class="pun">?</span><span class="pln">$args</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ملاحظات:
</p>

<ul>
<li>
		يمكن لـ Nginx معالجة gzip وذاكرة التخزين المؤقت للمتصفح تلقائيًا، لذا من الأفضل ترك هذا الجزء لـ nginx.
	</li>
	<li>
		ستعمل قواعد W3 Total Cache Minify مع الإعدادات أعلاه دون أي مشاكل.
	</li>
</ul>
<h2>
	Nginx fastcgi_cache
</h2>

<p>
	يمكن لـ Nginx إجراء التخزين المؤقت من جانبه لتقليل الحمل على الخادم، وعندما تريد استخدام fastcgi_cache المدمج في Nginx، يفضل تشغيل nginx باستخدام وحدة <a href="https://github.com/FRiCKLE/ngx_cache_purge" rel="external nofollow">fastcgi</a>_<a href="https://github.com/FRiCKLE/ngx_cache_purge" rel="external nofollow">cache_purge</a>، وستساعد nginx على مسح ذاكرة التخزين المؤقت لصفحة ما عند تحريرها. ومن ناحية ووردبريس، ستحتاج إلى تثبيت إضافة مثل <a href="https://wordpress.org/plugins/nginx-helper/" rel="external nofollow">مساعد Nginx</a> للاستفادة من ميزة fastcgi_cache_purge.
</p>

<p>
	ستبدو الإعدادات كما يلي:
</p>

<p>
	حدد منطقة ذاكرة التخزين المؤقت Nginx في كتلة {…}http، خارج كتلة {..}server:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_54" style="">
<span class="com">#move next 3 lines to /etc/nginx/nginx.conf if you want to use fastcgi_cache across many sites</span><span class="pln">
fastcgi_cache_path </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">run</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">-</span><span class="pln">cache levels</span><span class="pun">=</span><span class="lit">1</span><span class="pun">:</span><span class="lit">2</span><span class="pln"> keys_zone</span><span class="pun">=</span><span class="pln">WORDPRESS</span><span class="pun">:</span><span class="lit">500m</span><span class="pln"> inactive</span><span class="pun">=</span><span class="lit">60m</span><span class="pun">;</span><span class="pln">
fastcgi_cache_key </span><span class="str">"$scheme$request_method$host$request_uri"</span><span class="pun">;</span><span class="pln">
fastcgi_cache_use_stale error timeout invalid_header http_500</span><span class="pun">;</span></pre>

<p>
	بالنسبة لإعدادات موقع ووردبريس في الكتلة {..}server أضف كتلة تحقق من ذاكرة التخزين المؤقت على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_56" style="">
<span class="com">#fastcgi_cache start</span><span class="pln">
</span><span class="kwd">set</span><span class="pln"> $no_cache </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

</span><span class="com"># POST requests and urls with a query string should always go to PHP</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$request_method </span><span class="pun">=</span><span class="pln"> POST</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">set</span><span class="pln"> $no_cache </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">  
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$query_string </span><span class="pun">!=</span><span class="pln"> </span><span class="str">""</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">set</span><span class="pln"> $no_cache </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">  

</span><span class="com"># Don't cache uris containing the following segments</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$request_uri </span><span class="pun">~*</span><span class="pln"> </span><span class="str">"(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">set</span><span class="pln"> $no_cache </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">  

</span><span class="com"># Don't use the cache for logged in users or recent commenters</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">$http_cookie </span><span class="pun">~*</span><span class="pln"> </span><span class="str">"comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">set</span><span class="pln"> $no_cache </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ثم أجرِ تغييرات على كتلة معالجة PHP.
</p>

<p>
	فقط أضف هذا إلى كتلة php التالية، لاحظ السطر fastcgi_cache_valid 200 60m، الذي يخبر nginx بالتخزين المؤقت للاستجابات 200 -أي الصفحات العادية- فقط، مما يعني أن صفحات إعادة التوجيه لا تخزَّن مؤقتًا، وهذا مهم للمواقع متعددة اللغات، وإذا لم ينفَّذ فسيخزن nginx عنوان url الرئيسي في لغة واحدة، بدلًا من إعادة توجيه المستخدمين إلى المحتوى الخاص بهم وفقًا للغتهم.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_303_60" style="">
<span class="pln">fastcgi_cache_bypass $no_cache</span><span class="pun">;</span><span class="pln">
fastcgi_no_cache $no_cache</span><span class="pun">;</span><span class="pln">

fastcgi_cache WORDPRESS</span><span class="pun">;</span><span class="pln">
fastcgi_cache_valid </span><span class="lit">200</span><span class="pln"> </span><span class="lit">60m</span><span class="pun">;</span></pre>

<p>
	بحيث يصبح مثل هذا:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_64" style="">
<span class="pln">location </span><span class="pun">~</span><span class="pln"> </span><span class="pun">[^</span><span class="str">/]\.php(/</span><span class="pun">|</span><span class="pln">$</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    fastcgi_split_path_info </span><span class="pun">^(.+?</span><span class="pln">\.php</span><span class="pun">)(/.*)</span><span class="pln">$</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!-</span><span class="pln">f $document_root$fastcgi_script_name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">404</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="com"># This is a robust solution for path info security issue and works with "cgi.fix_pathinfo = 1" in /etc/php.ini (default)</span><span class="pln">

    include fastcgi</span><span class="pun">.</span><span class="pln">conf</span><span class="pun">;</span><span class="pln">
    fastcgi_index index</span><span class="pun">.</span><span class="pln">php</span><span class="pun">;</span><span class="pln">
</span><span class="com">#    fastcgi_intercept_errors on;</span><span class="pln">
    fastcgi_pass php</span><span class="pun">;</span><span class="pln">

    fastcgi_cache_bypass $no_cache</span><span class="pun">;</span><span class="pln">
    fastcgi_no_cache $no_cache</span><span class="pun">;</span><span class="pln">

    fastcgi_cache WORDPRESS</span><span class="pun">;</span><span class="pln">
    fastcgi_cache_valid </span><span class="lit">200</span><span class="pln"> </span><span class="lit">60m</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أخيرًا أضف موقعًا للمسح الشرطي:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_66" style="">
<span class="pln">location </span><span class="pun">~</span><span class="pln"> </span><span class="str">/purge(/</span><span class="pun">.*)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com"># Uncomment the following two lines to allow purge only from the webserver</span><span class="pln">
        </span><span class="com">#allow 127.0.0.1;</span><span class="pln">
    </span><span class="com">#deny all;</span><span class="pln">

        fastcgi_cache_purge WORDPRESS </span><span class="str">"$scheme$request_method$host$1"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إذا تلقيت خطأ "توجيه غير معروف fastcgicachepurge" فتحقق من أنَّ تثبيت Nginx يحتوي على وحدة fastcgicachepurge.
</p>

<h2>
	أداء أفضل للملفات الثابتة في المواقع المتعددة
</h2>

<p>
	يؤدي طلب ملف ثابت عند إعداد المواقع المتعددة إلى تشغيل php، أي الملف ms-files.php، ويمكنك الحصول على أداء أفضل بكثير باستخدام توجيه {..}Map في Nginx.
</p>

<p>
	أضف ما يلي في إعدادات Nginx لموقعك فوق الكتلة {..}server:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_303_70" style="">
<span class="pln">map $http_host $blogid </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">default</span><span class="pln">               </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

    example</span><span class="pun">.</span><span class="pln">com           </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
    site1</span><span class="pun">.</span><span class="pln">example</span><span class="pun">.</span><span class="pln">com     </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
    site1</span><span class="pun">.</span><span class="pln">com             </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إنها مجرد قائمة بأسماء المواقع ومعرفات المدونات، ويمكنك استخدام <a href="https://wordpress.org/extend/plugins/nginx-helper" rel="external nofollow">مساعد Nginx</a> للحصول على مثل هذه القائمة في أزواج تحوي أسماء المواقع ومعرفات المدونات، وستنشئ هذه الإضافة أيضًا ملف map.conf يمكنك تضمينه مباشرةً في قسم {..}map بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_72" style="">
<span class="pln">map $http_host $blogid </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">default</span><span class="pln">               </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

    include </span><span class="pun">/</span><span class="pln">path</span><span class="pun">/</span><span class="pln">to</span><span class="pun">/</span><span class="pln">map</span><span class="pun">.</span><span class="pln">conf </span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	بعد إنشاء قسم {..}map تحتاج إجراء تغيير واحد آخر في إعدادات Nginx لتعالج طلبات /files/ أولًا باستخدام {..}map في nginx:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_74" style="">
<span class="pln">location </span><span class="pun">~</span><span class="pln"> </span><span class="pun">^</span><span class="str">/files/</span><span class="pun">(.*)</span><span class="pln">$ </span><span class="pun">{</span><span class="pln">
          try_files </span><span class="pun">/</span><span class="pln">wp</span><span class="pun">-</span><span class="pln">content</span><span class="pun">/</span><span class="pln">blogs</span><span class="pun">.</span><span class="pln">dir</span><span class="pun">/</span><span class="pln">$blogid</span><span class="pun">/</span><span class="pln">$uri </span><span class="pun">/</span><span class="pln">wp</span><span class="pun">-</span><span class="pln">includes</span><span class="pun">/</span><span class="pln">ms</span><span class="pun">-</span><span class="pln">files</span><span class="pun">.</span><span class="pln">php</span><span class="pun">?</span><span class="pln">file</span><span class="pun">=</span><span class="pln">$1 </span><span class="pun">;</span><span class="pln">
          access_log off</span><span class="pun">;</span><span class="pln"> log_not_found off</span><span class="pun">;</span><span class="pln"> expires max</span><span class="pun">;</span><span class="pln">
 </span><span class="pun">}</span></pre>

<h2>
	ملاحظات
</h2>

<p>
	انتبه إلى ما يلي:
</p>

<ul>
<li>
		عند إنشاء موقع جديد أو حذفه أو تعيين نطاق إضافي لموقع موجود؛ سيحدّث مساعد Nginx ملف map.conf تلقائيًا، ولكنك ستحتاج إلى إعادة تحميل إعدادات Nginx يدويًا، ويمكنك ذلك في أي وقت لاحق، وحتى ذلك الحين ستقدَّم ملفات المواقع الجديدة فقط باستخدام php-fpm.
	</li>
	<li>
		لا تولد هذه الطريقة أي روابط رمزية symbolic links، لذلك لن تكون هناك مشكلات في عمليات الحذف العرضية أو البرامج النصية الاحتياطية التي تتبع روابط رمزية.
	</li>
	<li>
		يمكن توسيع هذا بشكل جيد للشبكات الكبيرة، وسيوجد فقط ملف map.conf واحد.
	</li>
</ul>
<p>
	وفي ملاحظة أخيرة مهمة: يفترض هذا الإعداد بأكمله أن جذر الموقع هو المدونة، وأن جميع الملفات التي نرجع إليها موجودة في المضيف، وإذا وضعت المدونة في دليل فرعي مثل blog/، فسيتعين تعديل القواعد، ويمكن للمستخدم جعل ذلك ممكنًا، فمثلًا يمكنك استخدام التوجيه التالي في كتلة "server" الرئيسية، وتطبيقه تلقائيًا على قواعد WP العامة:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_76" style="">
<span class="kwd">set</span><span class="pln"> $wp_subdir </span><span class="str">"/blog"</span><span class="pun">;</span></pre>

<p>
	انتبه هنا، إذ يمكن أن يؤدي خطأ مطبعي في <a href="https://wordpress.org/support/article/nginx/#global-restrictions-file" rel="external nofollow">Global restrictions file</a> إلى حدوث ثغرات، ولاختبار ما إذا كان دليل uploads محميًا حقًا أنشئ ملف <a href="https://academy.hsoub.com/programming/php/%D8%AA%D9%85%D9%87%D9%8A%D8%AF-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-php-r235/" rel="">PHP</a> مع بعض المحتوى، على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_303_78" style="">
<span class="pun">&lt;?</span><span class="pln">php phpinfo</span><span class="pun">();</span><span class="pln"> </span><span class="pun">?&gt;</span></pre>

<p>
	ارفعه إلى الدليل uploads، أو أحد أدلته الفرعية، ثم حاول الوصول إليه (تنفيذه) من متصفحك.
</p>

<p>
	للالطلاع أكثر، يمكنك زيارة الآتي:
</p>

<ul>
<li>
		<a href="http://wiki.nginx.org/WordPress" rel="external nofollow">صفحة توثيق Nginx في ووردبريس</a>
	</li>
	<li>
		<a href="http://wiki.nginx.org/FullExample" rel="external nofollow">مثال عن خادم Nginx</a>
	</li>
	<li>
		<a href="http://wiki.nginx.org/FullExample2" rel="external nofollow">مثال ثان عن خادم Nginx</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/web/nginx/" rel="">دروس مفصلة عن إدارة خادم الوب Nginx</a>.
	</li>
</ul>
<p>
	ترجمة -وبتصرف- للمقال <a href="https://wordpress.org/support/article/nginx/" rel="external nofollow">Nginx</a> من موقع wordpress.org.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/devops/servers/web/nginx/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%B6%D8%A8%D8%B7-%D8%AE%D8%A7%D8%AF%D9%85-nginx-r401/" rel="">تثبيت وضبط خادم Nginx</a>.
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81%D9%8A%D9%91%D8%A9-%D8%B6%D8%A8%D8%B7-nginx-%D9%84%D9%84%D8%B9%D9%85%D9%84-%D9%83%D8%AE%D8%A7%D8%AF%D9%85-%D9%88%D9%8A%D8%A8-%D9%88%D9%83%D9%88%D8%B3%D9%8A%D8%B7-%D8%B9%D9%83%D8%B3%D9%8A-%D9%84%D9%80-apache-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-ubuntu-1804-r396/" rel="">كيفيّة ضبط Nginx للعمل كخادم ويب وكوسيط عكسي لـ Apache على خادم Ubuntu 18.04</a>.
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D8%A9-%D9%85%D9%86-%D8%A7%D9%84%D8%AA%D8%AE%D8%B2%D9%8A%D9%86-%D8%A7%D9%84%D9%85%D8%A4%D9%82%D8%AA-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D9%88%D8%AD%D8%AF%D8%A9-header-%D9%81%D9%8A-%D8%AE%D8%A7%D8%AF%D9%88%D9%85-nginx-%D9%81%D9%8A-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1604-r306/" rel="">كيفية الاستفادة من التخزين المؤقت في المتصفح باستعمال وحدة header في خادوم Nginx في أوبنتو 16.04</a>.
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-nginx-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r434/" rel="">كيفية تثبيت Nginx على أوبونتو 18.04</a>.
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81-%D8%AA%D9%8F%D8%B1%D9%82%D9%91%D9%90%D9%8A-%D8%AE%D8%A7%D8%AF%D9%85-nginx-%D9%85%D9%88%D8%AC%D9%88%D8%AF-%D8%A8%D8%AF%D9%88%D9%86-%D9%82%D8%B7%D8%B9-%D8%A7%D8%AA%D8%B5%D8%A7%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r445/" rel="">كيف تُرقِّي خادم Nginx موجود بدون قطع اتصالات العميل</a>.
	</li>
</ul>
]]></description><guid isPermaLink="false">592</guid><pubDate>Thu, 24 Feb 2022 08:14:37 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641; &#x62A;&#x64F;&#x631;&#x642;&#x651;&#x650;&#x64A; &#x62E;&#x627;&#x62F;&#x645; Nginx &#x645;&#x648;&#x62C;&#x648;&#x62F; &#x628;&#x62F;&#x648;&#x646; &#x642;&#x637;&#x639; &#x627;&#x62A;&#x635;&#x627;&#x644;&#x627;&#x62A; &#x627;&#x644;&#x639;&#x645;&#x64A;&#x644;</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81-%D8%AA%D9%8F%D8%B1%D9%82%D9%91%D9%90%D9%8A-%D8%AE%D8%A7%D8%AF%D9%85-nginx-%D9%85%D9%88%D8%AC%D9%88%D8%AF-%D8%A8%D8%AF%D9%88%D9%86-%D9%82%D8%B7%D8%B9-%D8%A7%D8%AA%D8%B5%D8%A7%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D8%B9%D9%85%D9%8A%D9%84-r445/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2019_10/5d982c4868ead_Nginx.jpg.bc5d11d5288634c9da1de43d9a65d450.jpg" /></p>

<p>
	<a href="https://academy.hsoub.com/devops/servers/web/nginx/" rel="">Nginx</a> خادم ويب قوي ووكيل عكسي (reverse proxy) يُستخدم لتقديم العديد من المواقع الأكثر شهرةً في العالم. سنوضّح في هذا الدليل كيفية ترقية Nginx الموجود القابل للتنفيذ، بدون قطع اتصالات العميل.
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2019_10/5d982c4867a5a_Nginx.jpg.280f831a967bf32adfabfd4227a3074d.jpg" data-fileid="32038" rel=""><img class="ipsImage ipsImage_thumbnailed" data-fileid="32038" data-unique="0uo55y0kc" src="https://academy.hsoub.com/uploads/monthly_2019_10/5d982c487cf68_Nginx.thumb.jpg.f6760acded7c5a84bbaaa80d56c336a8.jpg" alt="كيف ترقي خادم Nginx.jpg"></a>
</p>

<h2>
	المتطلبات الأساسية
</h2>

<p>
	قبل البدء في هذا الدليل، يجب أن يكون لديك مستخدم غير جذر على خادمك، تمَّ إعداده مع صلاحيات sudo. ستحتاج أيضًا أن يكون لديك خادم Nginx مثبَّتًا.
</p>

<p>
	إذا كنت تستخدم أبنتو 14.04، يمكنك تعلّم كيفية ضبط مستخدم بصلاحيات sudo <a href="https://academy.hsoub.com/devops/linux/%D8%A7%D9%84%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%8A%D8%A9-%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r431/" rel="">هنا</a>. يمكنك تثبيت Nginx باتّباع <a href="https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-nginx-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r434/" rel="">هذا الدليل</a>.
</p>

<p>
	إذا كنت تستخدم CentOS 7، يمكنك الحصول على ضبط المستخدم بصلاحيات sudo عبر <a href="https://academy.hsoub.com/devops/linux/%D8%A7%D9%84%D8%B6%D8%A8%D8%B7-%D8%A7%D9%84%D9%85%D8%A8%D8%AF%D8%A6%D9%8A-%D9%84%D8%AE%D8%A7%D8%AF%D9%88%D9%85-centos-7-r345/" rel="">هذا الدليل</a>، متّبعًا <a href="https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-centos-7" rel="external nofollow">هذا الدليل</a> لتثبّت Nginx.
</p>

<h2>
	كيف تعمل الترقية
</h2>

<p>
	يعمل Nginx على إنشاء إجراء سيّد أو رئيسي (master process) عندما تبدأ الخدمة. ويشغّل الإجراء السيّد بدوره إجراء تابع (worker process) أو أكثر تتعامل مع اتصالات العميل الفعلية. تم تصميم Nginx لأداء إجراءات معينة عندما يتلقّى إشارات محددة من المدير. يمنحك الفرصة باستخدام هذه الإشارات لتقوم بترقيته أو ترقية إعداداته الموجودة بسهولة، بدون قطع اتصالات العميل.
</p>

<p>
	هناك سكربتات (scripts) معينة للخدمة مزوّدة من قِبل القائمين على صيانة حزمة التوزيع ستوفر القدرة على الاستخدام مع الترقيات التقليدية. لكن توفر الترقية يدويًا المزيد من المرونة في المنهجية وتسمح لك بمراجعة الترقية للتراجع بسرعة إذا كان هناك مشاكل. هذا أيضًا سيوفر خيارًا للترقية بأمان إذا قمت بتثبيت Nginx من المصدر أو باستخدام طريقة لا توفر هذه الإمكانية.
</p>

<p>
	ستُستخدم الإشارات التالية:
</p>

<ul>
<li>
		<code>USR2</code>: تولّد هذه مجموعة جديدة من إجراءات السيد/التابع بدون التأثير على المجموعة القديمة.
	</li>
	<li>
		<code>WINCH</code>: تخبر هذه الإجراء السيد لـNginx أن يوقف أغراض التابع المرتبطة بأمان.
	</li>
	<li>
		<code>HUP</code>: تخبر هذه الإجراء السيد لـNginx أن يعيد قراءة ملفات إعداداته ويستبدل إجراءات التابع بتلك المرتبطة بالإعدادات الجديدة. إذا كان هناك سيد قديم وجديد قيد التشغيل، فإنَّ إرسال هذا إلى السيد القديم سيولّد توابعًا باستخدام إعداداتهم الأصليّة.
	</li>
	<li>
		<code>QUIT</code>: توقف هذه تشغيل السيّد وتوابعه بأمان.
	</li>
	<li>
		<code>TERM</code>: تهيئ هذه إيقاف تشغيل سريع للسيّد وتوابعه.
	</li>
	<li>
		<code>KILL</code>: توقف هذه السيّد وتوابعه بدون أيّ تنظيف.
	</li>
</ul>
<h2>
	إيجاد معرّفات إجراء Nginx
</h2>

<p>
	لإرسال إشارات إلى الإجراءات المختلفة، نحتاج إلى معرفة معرّف الإجراء (<abbr title="Process IDentifier | معرّف العملية أو البرنامج">PID</abbr>) المستهدف. هناك طريقتان سهلتان لإيجاد هذا. أولًا، يمكنك استخدام الأداة <code>ps</code> وثمّ <code>grep</code> لـNginx بين النتائج. هذا بسيط ويسمح لك برؤية إجراءات السيّد والتابع:
</p>

<pre class="ipsCode">
$ ps aux | grep nginx
</pre>

<pre class="ipsCode">
output
root     10846  0.0  0.3  47564  3280 ?        S    13:26   0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx    10847  0.0  0.1  47936  1908 ?        S    13:26   0:00 nginx: worker process
user     10961  0.0  0.0 112640   964 pts/0    S+   13:53   0:00 grep --color=auto nginx
</pre>

<p>
	يحتوي العمود الثاني على معرّفات الإجراءات المُختارة. المميز هو معرّف الإجراء. يوضّح العمود الأخير أنَّ النتيجة الأولى هي الإجراء السيّد لـNginx.
</p>

<p>
	طريقة أخرى لإيجاد معرّف الإجراء السيّد لـNginx وهي طباعة محتويات ملف <code>‎/run/nginx.pid</code>:
</p>

<pre class="ipsCode">
$ cat /run/nginx.pid
</pre>

<pre class="ipsCode">
output
10846
</pre>

<p>
	إذا كان هناك إجراءين سيّد لـNginx قيد التشغيل، سينتقل الإجراء القديم إلى <code>run/nginx.pid.oldbin/</code>.
</p>

<h2>
	توليد مجموعة سيّد/توابع جديدة
</h2>

<p>
	الخطوة الأولى لتحديث ملفنا القابل للتنفيذ بأمان هي في الواقع تحديث ملفك الثنائي.قم بذلك باستخدام أيّ طريقة مناسبة لتثبيت Nginx لديك، سواء من خلال مدير الحزمة أو التثبيت المصدري.
</p>

<p>
	بعد وضع الملف الثنائي الجديد في مكانه، يمكنك توليد مجموعة ثانية من إجراءات السيّد/التابع التي تستخدم الملف الجديد القابل للتنفيذ.
</p>

<p>
	يمكنك القيام بذلك إمّا بإرسال إشارة <code>USR2</code> مباشرةً إلى رقم المعرّف الذي استعلمت عنه (تأكّد هنا من استبدال معرّف الإجراء السيّد بمعرّف الإجراء السيّد الخاص بخادمك Nginx):
</p>

<pre class="ipsCode">
$ sudo kill -s USR2 10846
</pre>

<p>
	او يمكنك قراءة واستبدال القيمة المخزّنة في ملف <abbr title="Process IDentifier | معرّف العملية أو البرنامج">PID</abbr> مباشرةً باستخدام أمر كهذا:
</p>

<pre class="ipsCode">
$ sudo kill -s USR2 `cat /run/nginx.pid` 
</pre>

<p>
	إذا تفحّصت إجراءاتك الحاليّة، ستشاهد أنّ لديك الآن مجموعتان من إجراءات السيّد/التوابع لـNginx:
</p>

<pre class="ipsCode">
$ ps aux | grep nginx
</pre>

<pre class="ipsCode">
output
root     10846  0.0  0.3  47564  3280 ?        S    13:26   0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx    10847  0.0  0.1  47936  1908 ?        S    13:26   0:00 nginx: worker process
root     11003  0.0  0.3  47564  3132 ?        S    13:56   0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx    11004  0.0  0.1  47936  1912 ?        S    13:56   0:00 nginx: worker process
user     11031  0.0  0.0 112640   960 pts/0    S+   14:01   0:00 grep --color=auto nginx
</pre>

<p>
	يمكنك أيضًا أن تشاهد أنَّ ملف <code>run/nginx.pid/</code> الأصلي قد انتقل إلى <code>run/nginx.pid.oldbin/</code> ومعرّف الإجراء السيّد الجديد كُتبَ في الملف <code>run/nginx.pid/</code>:
</p>

<pre class="ipsCode">
$ tail -n +1 /run/nginx.pid* 
</pre>

<pre class="ipsCode">
output
==&gt; /run/nginx.pid &lt;==
11003

==&gt; /run/nginx.pid.oldbin &lt;==
10846
</pre>

<p>
	يمكنك الآن إرسال إشارات إلى أيّ من الإجراءين السيّدين مستخدمًا المعرّفات الموجودة في هذه الملفات.
</p>

<p>
	عند هذه النقطة، فإن مجموعتي السيّد/التابع شغّالتين وقادرتين على تلبية طلبات العميل. تستخدم المجموعة الأولى الملف الأصلي القابل للتنفيذ والإعدادات الأصلية لـNginx وتستخدم المجموعة الثانية الإصدارات الأحدث. يمكنهم الاستمرار في العمل جنبًا إلى جنب، لكن يجب أن نبدأ في الانتقال إلى المجموعة جديدة من أجل الاتساق.
</p>

<h2>
	إيقاف تشغيل توابع السيّد الأول
</h2>

<p>
	للبدء بالانتقال إلى المجموعة الجديدة، فإنَّ أول شيء يمكننا القيام به هو إيقاف الإجراءات توابع السيّد الأصلي. سينهي التوابع الأصليين معالجة كل اتصالاتهم الحالية ثمَّ يخرجون.
</p>

<p>
	أوقف توابع المجموعة الأصلية بإصدار إشارة <code>WINCH</code> إلى إجرائهم السيّد:
</p>

<pre class="ipsCode">
$ sudo kill -s WINCH `cat /run/nginx.pid.oldbin`
</pre>

<p>
	سيتيح ذلك لتوابع السيّد الجديد أن يتعاملوا مع اتصالات العميل الجديدة بمفردهم. سيظلّ الإجراء السيّد القديم قيد التشغيل، لكن بدون توابع:
</p>

<pre class="ipsCode">
$ ps aux | grep nginx
</pre>

<pre class="ipsCode">
output
root     10846  0.0  0.3  47564  3280 ?        S    13:26   0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
root     11003  0.0  0.3  47564  3132 ?        S    13:56   0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx    11004  0.0  0.1  47936  1912 ?        S    13:56   0:00 nginx: worker process
user     11089  0.0  0.0 112640   964 pts/0    R+   14:13   0:00 grep --color=auto nginx
</pre>

<p>
	يتيح هذا لك مراجعة التوابع الجدد لأنّهم يقبلون الاتصالات بشكلٍ منفصل مع الحفاظ على قابلية العودة إلى الملف القديم القابل للتنفيذ إذا كان هناك خطأٌ ما.
</p>

<h2>
	تقييم النتيجة واتخاذ الخطوات التالية
</h2>

<p>
	عند هذه النقطة يجب اختبار النظام ومراجعته للتأكّد من عدم وجود بوادر مشاكل. يمكنك ترك الإعدادات في هذه الحالة طالما ترغب بالتأكّد من أنّ الملف الجديد القابل للتنفيذ لـNginx خالٍ من الأخطاء وقادر على التعامل مع حركة المرور الخاصة بك.
</p>

<p>
	ستعتمد خطوتك التالية تمامًا على ما إذا كنت تواجه مشاكل.
</p>

<h2>
	إذا كانت الترقية ناجحة، أكمل الانتقال
</h2>

<p>
	إذا لم تواجه أيّ مشاكل مع توابع مجموعتك الجديدة، يمكنك إيقاف تشغيل الإجراء السيّد القديم بأمان. للقيام بذلك، فقط أرسل الإشارة <code>QUIT</code> إلى السيّد القديم:
</p>

<pre class="ipsCode">
sudo kill -s QUIT `cat /run/nginx.pid.oldbin`
</pre>

<p>
	سيُغلَق الإجراء السيّد القديم بأمان، تاركًا فقط مجموعتك الجديدة من السيّد/التوابع لـNginx. عند هذه النقطة، تكون قد حدّثت الملف الثنائي الموجود لـNginx بأمان بدون مقاطعة اتصالات العميل.
</p>

<h2>
	إذا واجهت مشاكل في التوابع الجديدة، عُد إلى الملف الثنائي القديم
</h2>

<p>
	إذا لاحظت وجود مشاكل في مجموعة التوابع الجديدة، يمكنك العودة إلى الملف الثنائي والإعدادات القديمة. وهذا ممكن خلال الجلسة نفسها.
</p>

<p>
	أفضل طريقة للقيام بذلك هي إعادة تشغيل توابع السيّد القديم بإرسال إشارة <code>HUP</code> له. عادةً، عندما ترسل إشارة <code>HUP</code> للسيّد في Nginx، يعيد قراءة ملفات إعداداته ويشغّل توابعًا جديدة. لكن عندما يكون الهدف سيّد أقدم، فقط يولّد توابعًا جديدة باستخدام إعدادات العمل الأصلية:
</p>

<pre class="ipsCode">
$ sudo kill -s HUP `cat /run/nginx.pid.oldbin`
</pre>

<p>
	يجب أن تعود الآن ليكون لديك مجموعتين من إجراءات السيّد/التابع:
</p>

<pre class="ipsCode">
$ ps aux | grep nginx
</pre>

<pre class="ipsCode">
output
root     10846  0.0  0.3  47564  3280 ?        S    13:26   0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
root     11003  0.0  0.3  47564  3132 ?        S    13:56   0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx    11004  0.0  0.1  47936  1912 ?        S    13:56   0:00 nginx: worker process
nginx    19918  0.0  0.1  47936  1900 ?        S    14:47   0:00 nginx: worker process
user     19920  0.0  0.0 112640   964 pts/0    R+   14:48   0:00 grep --color=auto nginx
</pre>

<p>
	ترتبط التوابع الجديدة بالتابع القديم. عند هذه النقطة فإنَّ توابع المجموعتين سيقبلون اتصالات العميل. أوقف الآن الإجراء السيّد الجديد الذي يحوي أخطاء وتوابعه بإرسال إشارة <code>QUIT</code>:
</p>

<pre class="ipsCode">
$ sudo kill -s QUIT `cat /run/nginx.pid`
</pre>

<p>
	يجب أن تعود للسيّد والتوابع القديمين:
</p>

<pre class="ipsCode">
$ ps aux | grep nginx
</pre>

<pre class="ipsCode">
output
root     10846  0.0  0.3  47564  3280 ?        S    13:26   0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx    19918  0.0  0.1  47936  1900 ?        S    14:47   0:00 nginx: worker process
user     19935  0.0  0.0 112640   964 pts/0    R+   14:50   0:00 grep --color=auto nginx
</pre>

<p>
	سيستعيد السيّد الأصلي ملف <code>run/nginx.pid/</code> لمعرّفه.
</p>

<p>
	إذا لم يعمل ما سبق لأي سبب من الأسباب، يمكنك أن تحاول فقط إرسال إشارة <code>TERM</code> للسيّد الجديد للخادم، وهذا يجب أن تتهيأ عملية إيقاف التشغيل. ويجب أن يوقف هذا السيّد الجديد وأي تابع من توابعه أثناء البحث التلقائي عن السيّد القديم لبدء إجراءات التابع الخاص به. إذا كان هناك مشاكل خطيرة والتوابع بهم أخطاء ولم يتم إنهاؤهم، يمكنك إرسال إشارة <code>KILL</code> لكلٍّ منهم للتنظيف. يجب أن يكون هذا كحل أخير لأنّه سيؤدي إلى قطع الاتصالات.
</p>

<p>
	بعد الانتقال مرة أخرى إلى الملف الثنائي القديم، تذكّر أنّه لا يزال لديك الإصدار الجديد مثبّتًا على نظامك. يجب أن تزيل الإصدار الذي يحوي مشاكل وتعود لإصدارك السابق حتى يعمل Nginx بدون أيّة مشاكل عند إعادة التشغيل.
</p>

<h2>
	خاتمة
</h2>

<p>
	يجب أن تكون الآن قادرًا على نقل أجهزتك بسلاسة من ملف ثنائي لـNginx إلى آخر. إنَّ قدرة Nginx على التعامل مع مجموعتي سيّد/توابع مع المحافظة على معلومات علاقاتهم تتيح لنا القدرة على ترقية برنامج الخادم بدون أن يصبح جهاز الخادم في وضع عدم الاتصال.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-upgrade-nginx-in-place-without-dropping-client-connections" rel="external nofollow">How To Upgrade Nginx In-Place Without Dropping Client Connections</a> لصاحبه Justin Ellingwood
</p>
]]></description><guid isPermaLink="false">445</guid><pubDate>Sat, 05 Oct 2019 05:40:18 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x62A;&#x62B;&#x628;&#x64A;&#x62A; Nginx &#x639;&#x644;&#x649; &#x623;&#x648;&#x628;&#x648;&#x646;&#x62A;&#x648; 18.04</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-nginx-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r434/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2019_08/5d46b5a6df10b_nginx.jpg.f39adfbd8c471acdc0d42d82680a4b5f.jpg" /></p>

<p>
	<a href="https://academy.hsoub.com/devops/servers/web/nginx/" rel="">Nginx</a> هو أحد أشهر <a href="https://academy.hsoub.com/devops/servers/" rel="">خوادم الويب</a> عالميا وهو المسؤول عن استضافة بعض أكبر المواقع وأكثرها ازدحاما على الإنترنت. يُعد Nginx غالبا أفضل من <a href="https://academy.hsoub.com/devops/servers/web/apache/" rel="">Apache</a> من ناحية ملاءمته للموارد، ويمكن استخدامه كخادم ويب أو وكيل عكسي (reverse proxy). في هذا المقال سنشرح كيفية تثبيت Nginx على خادم أوبونتو 18.04.
</p>

<h2 id="-">
	المتطلبات
</h2>

<p>
	قبل البدء، تحتاج لمستخدم عادي - غير مسؤول - بصلاحيات "sudo" معد على الخادم. يمكنك معرفة كيفية إعداد خادم عادي في <a href="https://academy.hsoub.com/devops/linux/%D8%A7%D9%84%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%8A%D8%A9-%D9%84%D8%AE%D8%A7%D8%AF%D9%85-%D8%A3%D9%88%D8%A8%D9%88%D9%86%D8%AA%D9%88-1804-r431/" rel="">مقال الإعداد الأولي لِخادم أوبونتو 18.04</a>.
</p>

<p>
	إن كان لديك حساب متاح، سجل الدخول إلى المستخدم غير المسؤول للبدء.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="30946" href="https://academy.hsoub.com/uploads/monthly_2019_08/5d46b5a952efc_nginx.jpg.374b04511cff0f85186891fb94247717.jpg" rel=""><img alt="كيفية تثبيت nginx.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="30946" data-unique="673v5c3we" src="https://academy.hsoub.com/uploads/monthly_2019_08/5d46b5a967bfa_nginx.thumb.jpg.1bdbf15504c2f08fca7183683501e31a.jpg"></a>
</p>

<h2 id="-1-nginx">
	خطوة 1 - تثبيت Nginx
</h2>

<p>
	يمكنك تثبيت Nginx باستخدام مدير الحزم "<code>apt</code>" وذلك لأنه متاح في مخزن أوبونتو الافتراضي.
</p>

<p>
	ولأنها أول مرة نَستخدم فيها نظام تحزيم "<code>apt</code>"، سنُحدِث الحزمة المحلية الرئيسية كي نحصل على قائمة بأحدث الحزم. ثم ننفذ أمر تثبيت <code>nginx</code>:
</p>

<pre class="ipsCode">
 <span class="hljs-variable">$ </span>sudo apt update

 <span class="hljs-variable">$ </span>sudo apt install nginx
</pre>

<p>
	بعد الموافقة على الإجراءات سيُثبِّت <code>apt</code> Nginx وأي متعلقات يتطلبها الخادم.
</p>

<h2 id="-2-">
	خطوة 2 - إعداد جدار الحماية
</h2>

<p>
	قبل اختبار Nginx، يجب إعداد جدار الحماية كي يتيح الوصول للخدمة. يُسجل Nginx نفسه كخدمة في <code>ufw</code> أثناء التثبيت مما يجعل السماح بالدخول إلى Nginx أسهل.
</p>

<p>
	أدرج إعدادت التطبيق التي تعلم <code>ufw</code> كيف تتعامل معها باستخدام الأمر:
</p>

<pre class="ipsCode">
 $ sudo ufw <span class="hljs-keyword">app</span> <span class="hljs-keyword">list</span>
</pre>

<p>
	يجب أن تحصل على قائمة بملفات تعريف التطبيق:
</p>

<p>
	المخرجات:
</p>

<pre class="ipsCode">
Available <span class="hljs-string">applications:</span>

  Nginx Full

  Nginx HTTP

  Nginx HTTPS

  OpenSSH
</pre>

<p>
	يوجد ثلاثة ملفات تعريف ل Nginx متاحة كما ترى:
</p>

<ul>
<li>
		<strong>Nginx Full:</strong> يفتح هذا الملف كِلا المنافذ 80 (حركة مرور الويب العادية وغير المشفرة)، والمنفذ 443 (حركة المرور المشفرة <abbr title="Transport Layer Security | بروتوكول أمن طبقة النقل">TLS</abbr>/<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr>)
	</li>
	<li>
		<strong>Nginx HTTP:</strong> يفتح هذا الملف المنفذ 80 فقط (حركة مرور الويب العادية وغير المشفرة)
	</li>
	<li>
		<strong>Nginx HTTPS:</strong> يفتح هذا الملف المنفذ 443 فقط (حركة المرور المشفرة <abbr title="Transport Layer Security | بروتوكول أمن طبقة النقل">TLS</abbr>/<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr>)
	</li>
</ul>
<p>
	يستحسن تفعيل الملف الأكثر صرامة والذي لا يزال يسمح بحركة المرور التي تم إعدادها. لأننا لم نقم بإعداد <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> للخادم بعد، نحتاج لتفعيل المنفذ 80 فقط.
</p>

<p>
	يمكنك تفعيله باستخدام الأمر:
</p>

<pre class="ipsCode">
 <span class="hljs-variable">$ </span>sudo ufw allow <span class="hljs-string">'Nginx HTTP'</span>
</pre>

<p>
	للتحقق من التغييرات:
</p>

<pre class="ipsCode">
 <span class="hljs-variable">$ </span>sudo ufw status
</pre>

<p>
	يجب أن ترى أن حركة المرور باستخدام HTTP مفعلة كما في المخرجات:
</p>

<p>
	المخرجات:
</p>

<pre class="ipsCode">
<span class="hljs-attribute">Status</span>: active

<span class="lisp">To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere                  
Nginx HTTP                 ALLOW       Anywhere                  
OpenSSH (<span class="hljs-name">v6</span>)               ALLOW       Anywhere (<span class="hljs-name">v6</span>)             
Nginx HTTP (<span class="hljs-name">v6</span>)            ALLOW       Anywhere (<span class="hljs-name">v6</span>)</span>
</pre>

<h2 id="-3-">
	خطوة 3 - فحص خادم الويب
</h2>

<p>
	بعد انتهاء عملية التثبيت، سيُشغل أوبونتو Nginx. يجب أن يكون خادم الويب يعمل.
</p>

<p>
	يمكننا التحقق من ذلك باستخدام نظام التهيئة <code>systemd</code> عن طريق الأمر:
</p>

<pre class="ipsCode">
 <span class="hljs-variable">$ </span>systemctl status nginx
</pre>

<p>
	المخرجات:
</p>

<pre class="ipsCode">
● nginx.service - A high performance web server and a reverse proxy server
<span class="hljs-symbol">
   Loaded:</span> loaded (<span class="hljs-regexp">/lib/</span>systemd<span class="hljs-regexp">/system/</span>nginx.service; enabled; vendor <span class="hljs-string">preset:</span> enabled)
<span class="hljs-symbol">
   Active:</span> active (running) since Fri <span class="hljs-number">2018</span><span class="hljs-number">-04</span><span class="hljs-number">-20</span> <span class="hljs-number">16</span>:<span class="hljs-number">08</span>:<span class="hljs-number">19</span> UTC; <span class="hljs-number">3</span> days ago
<span class="hljs-symbol">
     Docs:</span> <span class="hljs-string">man:</span>nginx(<span class="hljs-number">8</span>)

 Main <span class="hljs-string"><abbr title="Process IDentifier | معرّف العملية أو البرنامج">PID</abbr>:</span> <span class="hljs-number">2369</span> (nginx)
<span class="hljs-symbol">
    Tasks:</span> <span class="hljs-number">2</span> (<span class="hljs-string">limit:</span> <span class="hljs-number">1153</span>)
<span class="hljs-symbol">
   CGroup:</span> <span class="hljs-regexp">/system.slice/</span>nginx.service

           ├─<span class="hljs-number">2369</span> <span class="hljs-string">nginx:</span> master process <span class="hljs-regexp">/usr/</span>sbin/nginx -g daemon on; master_process on;

           └─<span class="hljs-number">2380</span> <span class="hljs-string">nginx:</span> worker process
</pre>

<p>
	كما ترى في الأعلى، يظهر أن الخدمة بدأت بنجاح. لكن الطريقة المثلى لاختبار ذلك هو جلب صفحة من Nginx فعليا.
</p>

<p>
	يمكنك الوصول إلى صفحة Nginx الرئيسية لتتأكد من أن التطبيق يعمل بطريقة صحيحة عن طريق الدخول إلى عنوان بروتوكول الإنترنت (IP) الخاص بالخادم. يمكنك الحصول عليه بعدة طرق.
</p>

<p>
	جرب تنفيذ هذا الأمر على شاشة أوامر الخادم:
</p>

<pre class="ipsCode">
 $ ip addr <span class="hljs-literal">show</span> eth0 | grep inet | awk <span class="hljs-string">'{ print <span class="hljs-variable">$2</span>; }'</span> | sed <span class="hljs-string">'s/\/.*$//'</span>
</pre>

<p>
	ستحصل على بعض الأسطر التي يمكنك تجريبها سطرًا تلو الآخر على متصفح الإنترنت لتتأكد إن كانت تعمل.
</p>

<p>
	الطريقة الأخرى هي عبر تنفيذ الأمر التالي، والذي سيعطيك عنوان بروتوكول الإنترنت العام للخادم كما يُرى على المواقع الآخرى على الإنترنت:
</p>

<pre class="ipsCode">
 <span class="hljs-variable">$ </span>curl -<span class="hljs-number">4</span> icanhazip.com
</pre>

<p>
	عند حصولك على عنوان بروتوكول الإنترنت الخاص بالخادم، أدخله إلى شريط المتصفح:
</p>

<pre class="ipsCode">
<span class="hljs-symbol"> http:</span><span class="hljs-comment">//your_server_ip</span>
</pre>

<p>
	يجب أن ترى الصفحة الرئيسية ل Nginx:
</p>

<p style="text-align: center;">
	<img alt="default_page.png" class="ipsImage ipsImage_thumbnailed" data-fileid="30947" data-unique="x1zolgss2" src="https://academy.hsoub.com/uploads/monthly_2019_08/default_page.png.1f781d993f663fe0114ab88d8f8dce2c.png"></p>

<p>
	تُضمَّن هذه الصفحة مع Nginx لتأكيد أن Nginx يعمل بطريقة صحيحة.
</p>

<h2 id="-4-nginx">
	خطوة 4 - إدارة عملية Nginx
</h2>

<p>
	الآن وبما أن خادم الويب أصبح يعمل بطريقة صحيحة، لنراجع بعض أوامر التحكم الأساسية.
</p>

<p>
	لإيقاف خادم الويب نفذ الأمر:
</p>

<pre class="ipsCode">
 $ sudo systemctl <span class="hljs-built_in">stop</span> nginx
</pre>

<p>
	لِتشغيل خادم الويب عندما يكون موقفا، نفذ الأمر:
</p>

<pre class="ipsCode">
 $ sudo systemctl <span class="hljs-literal">start</span> nginx
</pre>

<p>
	لِإيقاف وإعادة تشغيل الخدمة استخدم الأمر:
</p>

<pre class="ipsCode">
 <span class="hljs-variable">$ </span>sudo systemctl restart nginx
</pre>

<p>
	إن كنت تقوم بتعديل في إعدادت Nginx، فإنه يٌعيد التحميل بدون قطع اتصالاته. للقيام بذلك نفذ الأمر:
</p>

<pre class="ipsCode">
 <span class="hljs-variable">$ </span>sudo systemctl reload nginx
</pre>

<p>
	Nginx مٌعد ليبدأ تلقائيا مع بدء تشغيل الخادم. إن كنت لا تريد ذلك؛ يمكنك إلغاء تفعيل هذه الميزة باستخدام الأمر:
</p>

<pre class="ipsCode">
 $ sudo systemctl <span class="hljs-built_in">disable</span> nginx
</pre>

<p>
	لإعادة تفعيل هذه الميزة:
</p>

<pre class="ipsCode">
 $ sudo systemctl <span class="hljs-built_in">enable</span> nginx
</pre>

<h2 id="-5-server-blocks-">
	خطوة 5 - إعداد أجزاء الخادم (Server Blocks) (إعداد مستحسن)
</h2>

<p>
	عند استخدام خادم Nginx، أجزاء الخادم (شبيهة بالمضيف الوهمي [virtual host] في Apache) تُستخدم لتغليف تفاصيل الإعدادات وتمكين استضافة أكثر من نطاق من خادم واحد. سنقوم بإعداد نطاق ونُسمية <strong>example.com</strong>، يمكنك استبدال هذا الاسم باسم النطاق الذي تريده. لدى Nginx جزء خادم مُفعَّل تلقائيا على أوبونتو ومُعَد لتشغيل الملفات في مجلد "<code>‎/var/www/html</code>". رغما من أن هذا يعمل بشكل جيد لموقع واحد؛ إلا أنه ليس عمليا إن كنت تستضيف عدة مواقع. عوضا عن التعديل على <code>‎/var/www/html</code>؛ لنقم بإنشاء بينة هيكلية في <code>‎/var/www</code> لموقع <strong>example.com</strong> ونترك <code>‎/var/www/html</code> في مكانه كَمجلد رئيسي ليعمل في حال طلب أحد العملاء صفحة لا توافق بقية المواقع.
</p>

<p>
	أنشئ مجلدا ل <strong>example.com</strong> كما يلي مستخدما <code>-p</code> لإنشاء أي مجلدات ضرورية أخرى:
</p>

<pre class="ipsCode">
 $ sudo <span class="hljs-built_in">mkdir</span> -p /<span class="hljs-built_in">var</span>/www/<span class="hljs-built_in">example</span>.com/html
</pre>

<p>
	ثم قم بمنح ملكية الجلد باستخدام متغير البيئة <code>‎$USER</code>:
</p>

<pre class="ipsCode">
 $ sudo chown -R <span class="hljs-variable">$USER</span>:<span class="hljs-variable">$USER</span> <span class="hljs-regexp">/var/</span>www<span class="hljs-regexp">/example.com/</span>html
</pre>

<p>
	يجب أن تكون صلاحيات جذور الويب صحيحة إن كنت لم تقم بتعديل قيمة <code>umask</code> يمكنك التأكد من ذلك باستخدام الأمر:
</p>

<pre class="ipsCode">
 $ sudo chmod -R <span class="hljs-number">755</span> /<span class="hljs-built_in">var</span>/www/<span class="hljs-built_in">example</span>.com
</pre>

<p>
	قم بإنشاء صفحة كعينة <code>index.html</code> باستخدام الأمر <code>nano</code> على مُحررك المفضل:
</p>

<pre class="ipsCode">
 $ nano <span class="hljs-regexp">/var/</span>www<span class="hljs-regexp">/example.com/</span>html<span class="hljs-regexp">/index.html</span>
</pre>

<p>
	بداخل هذه الصفحة، ضع عينة HTML التالية:
</p>

<pre class="ipsCode">
                <span class="hljs-regexp">/var/</span>www<span class="hljs-regexp">/example.com/</span>html<span class="hljs-regexp">/index.html</span>
</pre>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_4915_6" style="">
<span class="tag">&lt;html&gt;</span><span class="pln">
    </span><span class="tag">&lt;head&gt;</span><span class="pln">
        </span><span class="tag">&lt;title&gt;</span><span class="pln">Welcome to Example.com!</span><span class="tag">&lt;/title&gt;</span><span class="pln">
    </span><span class="tag">&lt;/head&gt;</span><span class="pln">
    </span><span class="tag">&lt;body&gt;</span><span class="pln">
        </span><span class="tag">&lt;h1&gt;</span><span class="pln">Success!  The example.com server block is working!</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
    </span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	بعد الانتهاء احفظ وأغلق الملف.
</p>

<p>
	كي يقوم Nginx بمعالجة هذا المحتوى، فمن الضروري إنشاء جزء خادم (server block) بالموجهات الصحيحة. بدلا من القيام بذلك عبر تعديل ملفالإعداد الافتراضي مباشرة، لنُنشئ ملفًا جديدًا في <code>‎/etc/nginx/sites-available/example.com</code>:
</p>

<pre class="ipsCode">
 $ sudo nano <span class="hljs-regexp">/etc/</span>nginx<span class="hljs-regexp">/sites-available/</span>example.com
</pre>

<p>
	قم بنسخ جزء الإعداد التالي الشبيه بالافتراضي لكنه محدث للمجلد واسم المجلد الجديد:
</p>

<pre class="ipsCode">
        <span class="hljs-regexp">/etc/</span>nginx<span class="hljs-regexp">/sites-available/</span>example.com
</pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4915_8" style="">
<span class="pln">server </span><span class="pun">{</span><span class="pln">
        listen </span><span class="lit">80</span><span class="pun">;</span><span class="pln">
        listen </span><span class="pun">[::]:</span><span class="lit">80</span><span class="pun">;</span><span class="pln">

        root </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">www</span><span class="pun">/</span><span class="pln">example</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">html</span><span class="pun">;</span><span class="pln">
        index index</span><span class="pun">.</span><span class="pln">html index</span><span class="pun">.</span><span class="pln">htm index</span><span class="pun">.</span><span class="pln">nginx</span><span class="pun">-</span><span class="pln">debian</span><span class="pun">.</span><span class="pln">html</span><span class="pun">;</span><span class="pln">

        server_name example</span><span class="pun">.</span><span class="pln">com www</span><span class="pun">.</span><span class="pln">example</span><span class="pun">.</span><span class="pln">com</span><span class="pun">;</span><span class="pln">

        location </span><span class="pun">/</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                try_files $uri $uri</span><span class="pun">/</span><span class="pln"> </span><span class="pun">=</span><span class="lit">404</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ أننا قمنا بتحديث إعداد <code>root</code> للمجلد الجديد و <code>server_name</code> لاسم النطاق الجديد.
</p>

<p>
	ثم نقوم بتفعيل الملف من خلال إنشاء رابط منه إلى مجلد <code>sites-enabled</code> والذي يقوم Nginx بالقراءة منه أثناء التشغيل:
</p>

<pre class="ipsCode">
 $ sudo ln -s <span class="hljs-regexp">/etc/</span>nginx<span class="hljs-regexp">/sites-available/</span>example.com <span class="hljs-regexp">/etc/</span>nginx<span class="hljs-regexp">/sites-enabled/</span>
</pre>

<p>
	الآن أصبح لدينا جزئي خادم مفعلين ومُعدين للاستجابة للطلبات وفقا لموجهي <code>listen</code> و <code>server_name</code> (يمكنك قراءة المزيد حول كيفية معالجة Nginx لهذه الموجهات في <a href="https://academy.hsoub.com/devops/servers/web/nginx/%D9%81%D9%87%D9%85-%D8%A2%D9%84%D9%8A%D8%A9-%D8%B9%D9%85%D9%84-%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D9%91%D8%A9-%D8%A7%D9%84%D8%A7%D8%AE%D8%AA%D9%8A%D9%91%D8%A7%D8%B1-%D9%81%D9%8A-%D9%83%D8%AA%D9%84%D8%A9-location-%D9%84%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF%D8%A7%D8%AA-%D8%AE%D8%A7%D8%AF%D9%88%D9%85-nginx-r68/" rel="">هذا المقال</a>
</p>

<ul>
<li>
		<code>example.com</code>: سيستجيب للطلب على <code>example.com</code> و <code>www.example.com</code>.
	</li>
	<li>
		<code>default</code>: سيستجيب لأي طلبات على المنفذ 80 والتي لا تطابق جزء آخر.
	</li>
</ul>
<p>
	لتجنب مشكلة "hash bucket memory" التي قد تطرأ من إضافة أسماء خوادم إضافية، من الضروري تعديل قيمة واحدة في ملف <code>‎/etc/nginx/nginx.conf</code>. افتح هذا الملف:
</p>

<pre class="ipsCode">
 $ sudo nano <span class="hljs-regexp">/etc/</span>nginx<span class="hljs-regexp">/nginx.conf</span>
</pre>

<p>
	ابحث عن الموجّه <code>server_names_hash_bucket_size</code> واحذف رمز <code>#</code> لإلغاء تعليق هذا السطر:
</p>

<pre class="ipsCode">
        <span class="hljs-regexp">/etc/</span>nginx<span class="hljs-regexp">/nginx.conf</span>
</pre>

<pre class="ipsCode">
...
http {
    ...
    server_names_hash_bucket_size <span class="hljs-number">64</span>;
    ...
}
...
</pre>

<p>
	ثم نتحقق من عدم وجود من أي أخطاء في جمل ملفات Nginx:
</p>

<pre class="ipsCode">
 <span class="hljs-variable">$ </span>sudo nginx -t
</pre>

<p>
	احفظ وأغلق الملف بعد انتهائك.
</p>

<p>
	إن لم يكن هناك أي أخطاء أعد تشغيل Nginx لتفعيل التغييرات:
</p>

<pre class="ipsCode">
 <span class="hljs-variable">$ </span>sudo systemctl restart nginx
</pre>

<p>
	يجب أن يقوم Nginx الآن بالاستجابة للطلبات على النطاق الجديد. للتحقق من ذلك، ادخل على <code><a href="http://example.com" ipsnoembed="false" rel="external nofollow">http://example.com</a></code>. هنا يجب أن ترى شيئا كالتالي:
</p>

<p style="text-align: center;">
	<img alt="first_block.png" class="ipsImage ipsImage_thumbnailed" data-fileid="30948" data-unique="qnmpeoi27" src="https://academy.hsoub.com/uploads/monthly_2019_08/first_block.png.a37e3fdfec6403ea41f46c0d0b9b3fd2.png"></p>

<h2 id="-6-nginx-">
	خطوة 6 - التعرف على مجلدات وملفات Nginx المهمة
</h2>

<p>
	الآن، وبعد أن أصبحت تعرف كيف تُدير خدمة Nginx. يجب أن تأخذ لمحة سريعة حول بعض المجلدات والملفات المهمة.
</p>

<h3 id="-">
	<strong>المحتوى</strong>
</h3>

<ul>
<li>
		‎<code>/var/www/html</code>: محتوى الويب الفعلي ل Nginx والذي يحتوي فقط على صفحة Nginx الافتراضية التي رأيناها سابقا. تُعرض هذه الصفحة من مجلد ‎<code>/var/www/html</code>. يمكن تغيير هذا الإعداد عن طريق ملف إعداد Nginx.
	</li>
</ul>
<h3 id="-">
	<strong>إعداد الخادم</strong>
</h3>

<ul>
<li>
		<code>‎/etc/nginx</code>: مجلد إعداد Nginx والذي يحوي جميع ملفات التكوين.
	</li>
	<li>
		<code>‎/etc/nginx/nginx.conf</code>: ملف تكوين Nginx الرئيسي. يمكن تعديل هذا الملف لتغيير الإعدادات العامة ل Nginx.
	</li>
	<li>
		<code>‎/etc/nginx/sites-available/‎</code>: المجلد الذي يتم تخزين أجزاء الخادم فيه. لن يقوم Nginx باستخدام ملفات التكوين الموجودة في هذا المجلد إلا إذا تم ربطها لمجلد <code>sites-enabled</code>. بشكل عام، يتم تخزين ملفات إعداد أجزاء الخادم في هذا المجلد ثم تُفعّل بربطها بالمجلد الآخر.
	</li>
	<li>
		<code>/etc/nginx/sites-enabled/</code>: المجلد الذي يتم تخزين أجزاء الخادم لكل موقع (per-site server blocks) فيه. تُنشئ هذه المجلدات بربط ملفات التكوين الموجودة في مجلد <code>sites-available</code>.
	</li>
	<li>
		<code>‎/etc/nginx/snippets</code>: يحتوي هذا المجلد على أجزاء التكوين التي يمكن تضمينها في أي مكان آخر في تكوين Nginx. أجزاء الإعداد المُكررة عن قصد تُعد بدائل جيدة لإعادة بناء أجزاء الأكواد البرمجية.
	</li>
</ul>
<h3 id="-">
	<strong>سجلات الخادم</strong>
</h3>

<ul>
<li>
		<code>‎/var/log/nginx/access.log</code>: يتم تخزين كل طلب يصل إلى خادم الويب في ملف السجل هذا إلا إن كان Nginx مُعد لعدم القيام بذلك.
	</li>
	<li>
		<code>‎/var/log/nginx/error.log</code>: يتم تسجيل أي خطأ في Nginx في هذا السجل.
	</li>
</ul>
<p>
	الآن وبما أن خادم الويب أصبح مُعدًا لديك، فلديك عدة خيارات للمحتوى الذي يمكن أن يعالجه الخادم والتقنيات التي يمكن أن تستخدمها لتجربة أفضل.
</p>

<h2 id="-">
	الخلاصة
</h2>

<p>
	إن كنت تريد بناء حزمة تطبيق متكاملة، اطلع على <a href="https://www.digitalocean.com/community/tutorials/how-to-install-linux-nginx-mysql-php-lemp-stack-ubuntu-18-04" rel="external nofollow">هذا المقال عن كيفية إعداد حزمة LEMP على أوبونتو 18.04</a>.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-18-04" rel="external nofollow">How To Install Nginx on Ubuntu 18.04</a> لصاحبيه Justin Ellingwood و Kathleen Juell.
</p>
]]></description><guid isPermaLink="false">434</guid><pubDate>Sun, 04 Aug 2019 10:51:11 +0000</pubDate></item><item><title>[&#x641;&#x64A;&#x62F;&#x64A;&#x648;] &#x62A;&#x62B;&#x628;&#x64A;&#x62A; &#x648;&#x636;&#x628;&#x637; &#x62E;&#x627;&#x62F;&#x645; Nginx</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%B6%D8%A8%D8%B7-%D8%AE%D8%A7%D8%AF%D9%85-nginx-r401/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2019_04/Nginx.png.f74f35f5f20e6db14333232f5570eb3e.png" /></p>

<p>
	<iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="400" src="https://www.youtube.com/embed/F9K3m9AbHCY" width="560"></iframe>
</p>

<p>
	نشرح طريقة تثبيت وإعداد خادم Nginx على توزيعة أوبنتو، وسنستعمله لتخديم صفحات HTML الخاصة بنا.
</p>

<p>
	لتثبيت خادم أباتشي راجع <a href="https://academy.hsoub.com/devops/servers/web/apache/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%B6%D8%A8%D8%B7-%D8%AE%D8%A7%D8%AF%D9%85-apache-r407/" rel="">فيديو تثبيت وضبط خادم Apache</a> في أكاديمية حسوب.
</p>

<p>
	قسم <a href="https://academy.hsoub.com/devops/servers/web/" rel="">خوادم الويب</a> في أكاديمية حسوب غني بالمقالات المفيدة للتعامل معها.
</p>
]]></description><guid isPermaLink="false">401</guid><pubDate>Tue, 09 Apr 2019 08:15:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x651;&#x629; &#x636;&#x628;&#x637; Nginx &#x644;&#x644;&#x639;&#x645;&#x644; &#x643;&#x62E;&#x627;&#x62F;&#x645; &#x648;&#x64A;&#x628; &#x648;&#x643;&#x648;&#x633;&#x64A;&#x637; &#x639;&#x643;&#x633;&#x64A; &#x644;&#x640; Apache &#x639;&#x644;&#x649; &#x62E;&#x627;&#x62F;&#x645; Ubuntu 18.04</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81%D9%8A%D9%91%D8%A9-%D8%B6%D8%A8%D8%B7-nginx-%D9%84%D9%84%D8%B9%D9%85%D9%84-%D9%83%D8%AE%D8%A7%D8%AF%D9%85-%D9%88%D9%8A%D8%A8-%D9%88%D9%83%D9%88%D8%B3%D9%8A%D8%B7-%D8%B9%D9%83%D8%B3%D9%8A-%D9%84%D9%80-apache-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-ubuntu-1804-r396/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2019_01/nginx.png.c6fecae9756dfc6d471bd83ce789f5f1.png" /></p>

<h2>
	مقدّمة
</h2>

<p>
	يُعتبر Apache و Nginx اثنين من أشهر خوادم الويب مفتوحة المصدر ويُستخدمان غالباً مع PHP. قد يكون من المفيد تشغيل كل منهما على نفس الجهاز الإفتراضي virtual machine عند استضافة مواقع ويب متعددة ذات متطلباتٍ متنوعة. إنّ الحل العام لتشغيل خوادم الويب على نظام واحد هو استخدام عناوين IP متعددة أو أرقام منافذ مختلفة.
</p>

<p>
	بالإمكان ضبط الخوادم التي تملك كلّا من عناوين IPv4 و IPv6 لخدمة مواقع Apache على أحد البروتوكولين ومواقع Nginx على البروتوكول الآخر، ولكن عمليًا هذا غير مُطبّق حاليًا، نظرًا لأن تبنّي مزودي خدمات الإنترنت لـ IPv6 لا يزال غير شائع. حيث يعدّ وجود رقم منفذ مختلف مثل 81 أو 8080 لخادم الويب الثاني حلاً آخر، ولكن مشاركة عناوين URL بأرقام المنافذ (مثل http://example.com:81) ليس منطقيًّا أو مثاليًّا دائمًا.
</p>

<p>
	سنتعلّم في هذه الدورة كيفيّة ضبط Nginx كخادم ويب وكذلك كوسيط عكسي Reverse Proxy لـ Apache - كل ذلك على خادم واحد.
</p>

<p>
	قد تكون هنالك حاجة اعتمادًا على تطبيق الويب إلى تغييرات في الشفرة ليبقى Apache مُدركًا بالوسيط العكسي، وخاصّة عند ضبط مواقع <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr>. سنتجنّب ذلك بتثبيت module وحدة Apache تسمى mod_rpaf والتي تُعيد كتابة متغيرات بيئة معيّنة بحيث يبدو أن Apache يتعامل مباشرة مع الطلبات من عملاء الويب.
</p>

<p>
	ستُضاف أربعة أسماء نِطاقات domain names على خادم واحد. وسيُخدَّم اثنين منهما بواسطة Nginx هما:example.com (المُضيف الظاهري الافتراضي) و sample.org. والاثنين المتبقيين، foobar.net و test.io، سيُخدّمان من قبل Apache. سنُعدّ أيضًا Apache لخدمة تطبيقات PHP باستخدام PHP-FPM، والذي يقدّم أداء أفضل عبر mod_php.
</p>

<h2>
	المتطلبات المُسبقة
</h2>

<p>
	ستحتاج لإكمال هذه الدورة التعليميّة إلى ما يلي:
</p>

<ul>
<li>
		خادم Ubuntu 18.04 جديد تم إعداده من خلال اتباع خطوات الإعداد الأولي للخادم في Ubuntu 18.4، مع مستخدم sudo عادي (non-root) و جدار ناري.
	</li>
	<li>
		ضبط أربعة أسماء نطاق مؤهلة بالكامل للإشارة لعنوان IP الخاص بخادمك. انظر الخطوة 3 من كيفية إعداد اسم مضيف فيDigitalOcean كمِثال لكيفية القيام بذلك. إذا كنت تستضيف DNS للنطاقات الخاصّة بك في مكان آخر، فعليك إنشاء سجلات A مناسبة هناك بدلاً من ذلك.
	</li>
</ul>
<h2>
	الخطوة 1 - تثبيت Apache و PHP-FPM
</h2>

<p>
	لنبدأ بتثبيت Apache و PHP-FPM. سنثبّت أيضًا بالإضافة إلى تثبيت Apache و PHP-FPM، وحدة PHP FastCGI Apache وهيlibapache2-mod-fastcgi، لدعم تطبيقات ويب FastCGI. أولاً، يجب تحديث قائمة الحزم package الخاصّة بك للتأكد من حصولك على أحدث الحزم.
</p>

<pre class="ipsCode">
$ sudo apt update
</pre>

<p>
	يجب بعد ذلك تثبيت حزم Apache و PHP-FPM:
</p>

<pre class="ipsCode">
$ sudo apt install apache2 php-fpm
</pre>

<p>
	يجب تنزيل وحدة FastCGI Apache من kernel.org وتثبيتها باستخدام الأمر dpkg لأنّها غير متوفرة في مستودع Ubuntu:
</p>

<pre class="ipsCode">
$ 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 
</pre>

<p>
	علينا بعد ذلك تغيير الضبط الافتراضي لخادم Apache من أجل استخدام PHP-FPM.
</p>

<h2>
	الخطوة 2 - ضبط Apache و PHP-FPM
</h2>

<p>
	سنغيّر في هذه الخطوة رقم منفذ Apache إلى 8080 وضبطه للعمل مع PHP-FPM باستخدام الوحدة mod_fastcgi. أعد تسمية ملف ضبط ports.conf لمخدم Apache:
</p>

<pre class="ipsCode">
$ sudo mv /etc/apache2/ports.conf /etc/apache2/ports.conf.default
</pre>

<p>
	أنشئ ملف ports.conf جديد مع تعيين المنفذ إلى 8080:
</p>

<pre class="ipsCode">
$ echo "Listen 8080" | sudo tee /etc/apache2/ports.conf
</pre>

<p>
	ملاحظة: تُضبط خوادم الويب بشكل عام للتنصت على المنفذ 127.0.0.1:8080 عند ضبط الوكيل العكسي، ولكن القيام بذلك سيؤدي إلى ضبط قيمة متغير بيئة (PHP (SERVER_ADDR إلى عنوان IP الاسترجاع بدلاً من عنوان الـ IP العام للخادم. هدفنا هو إعداد Apache بطريقة لا ترى مواقعه على الويب الوكيل العكسي أمامها. لذلك، سنضبطه للتنصت على المنفذ 8080 لجميع عناوين IP. سننشئ بعد ذلك ملف مضيف افتراضي لـ Apache. سيعدّ التوجيه <virtualhost> في هذا الملف ليخدّم المواقع فقط على المنفذ 8080. عطّل المضيف الظاهري الافتراضي:</virtualhost></p>

<pre class="ipsCode">
$ sudo a2dissite 000-default
</pre>

<p>
	ثم أنشئ ملف مضيف افتراضي جديد، باستخدام الموقع الافتراضي الموجود:
</p>

<pre class="ipsCode">
$ sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/001-default.conf
</pre>

<p>
	افتح الآن ملف الضبط الجديد:
</p>

<pre class="ipsCode">
$ sudo nano /etc/apache2/sites-available/001-default.conf
</pre>

<p>
	غيّرمنفذ التنصت إلى 8080: /etc/apache2/sites-available/000-default.conf
</p>

<pre class="ipsCode">
<virtualhost>
	ServerAdmin webmaster@localhost
	DocumentRoot /var/www/html
	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined
</virtualhost></pre>

<p>
	احفظ الملف وقم بتنشيط ملف الضبط الجديد:
</p>

<pre class="ipsCode">
$ sudo a2ensite 001-default
</pre>

<p>
	ثم أعد تحميل Apache:
</p>

<pre class="ipsCode">
$  sudo systemctl reload apache2
</pre>

<p>
	تحقّق من أن Apache يتنصت الآن على 8080:
</p>

<pre class="ipsCode">
$ sudo netstat -tlpn
</pre>

<p>
	يجب أن يبدو الخرج output كالمثال التالي، حيث يتنصّت apache2 على المنفذ 8080:
</p>

<pre class="ipsCode">
output 

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address 	Foreign Address  	State	<abbr title="Process IDentifier | معرّف العملية أو البرنامج">PID</abbr>/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
</pre>

<p>
	يمكنك إعداد دعم PHP و FastCGI بمجرّد التحقق من أن Apache يتنصت على المنفذ الصحيح.
</p>

<h2>
	الخطوة 3 - ضبط Apache لاستخدام mod_fastcgi
</h2>

<p>
	يخدّم Apache صفحات PHP باستخدام mod_php افتراضيًا، ولكنه يتطلب إعدادًا إضافيًّا للعمل مع PHP-FPM. ملاحظة: إذا كنت تجرّب هذا الدرس على نسخة موجودة مسبقًا من LAMP مع mod_php، عطّله أولاً باستخدام sudo a2dismod php7.2. سنضيف كتلة ضبط لوحدة mod_fastcgi التي تعتمد على mod_action. يُعطّل mod_action بشكل افتراضي، لذلك نحتاج أولاً إلى تفعيله:
</p>

<pre class="ipsCode">
$ sudo a2enmod action
</pre>

<p>
	أعد تسمية ملف ضبط FastCGI الموجود:
</p>

<pre class="ipsCode">
$ sudo mv /etc/apache2/mods-enabled/fastcgi.conf/etc/apache2/mods
-enabled/fastcgi.conf.default
</pre>

<p>
	أنشئ ملف ضبط جديد:
</p>

<pre class="ipsCode">
$ sudo nano /etc/apache2/mods-enabled/fastcgi.conf
</pre>

<p>
	أضف التوجيهات التالية إلى الملف لتمرير طلبات ملفات php. إلى مقبس PHP-FPM UNIX:
</p>

<pre class="ipsCode">
/etc/apache2/mods-enabled/fastcgi.conf
<ifmodule mod_fastcgi.c="">
  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
  <directory cgi-bin="" lib="" usr="">
	Require all granted
  </directory></ifmodule></pre>

<p>
	احفظ التغييرات واختبر الضبط:
</p>

<pre class="ipsCode">
$ sudo apachectl -t
</pre>

<p>
	إذا ظهرت عبارة Syntax OK، أعد تحميل Apache:
</p>

<pre class="ipsCode">
$ sudo systemctl reload apache2
</pre>

<p>
	إذا رأيت رسالة التحذير التالية، يمكنك تجاهلها الآن بشكل آمن. سنَضبط أسماء الخادم في وقت لاحق: 
</p>

<p>
	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.
</p>

<p>
	دعنا نتأكد الآن من أنّه بإمكاننا تخديم PHP من Apache.
</p>

<h2>
	الخطوة 4 - التحقق من عمل PHP
</h2>

<p>
	سَنتأكّد من أن PHP يعمل، وذلك من خلال إنشاء ملف ()phpinfo والوصول إليه من متصفح الويب. أنشئ الملف var/www/html/info.php/ والذي يحتوي على استدعاء للدّالة phpinfo:
</p>

<pre class="ipsCode">
$ echo "" | sudo tee /var/www/html/info.php
</pre>

<p>
	انتقل في المتصفح إلى http: // your_server_ip: 8080 / info.php لاستعراض هذا الملف. ستظهر لك قائمة إعدادات الضبط التي يستخدمها PHP. كما في الشكل التالي:
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="28756" href="https://academy.hsoub.com/uploads/monthly_2019_01/pic01.png.0c02132dfcee335367f53316aba6efab.png" rel=""><img alt="pic01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="28756" data-unique="4jf7snx0u" src="https://academy.hsoub.com/uploads/monthly_2019_01/pic01.thumb.png.2809f402bffeb493924f5022ce59c583.png"></a>
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="28757" href="https://academy.hsoub.com/uploads/monthly_2019_01/pic02.png.e4c6a3cef3bf4d8fdb31dd76631bbd04.png" rel=""><img alt="pic02.png" class="ipsImage ipsImage_thumbnailed" data-fileid="28757" data-unique="dkuxkpqzm" src="https://academy.hsoub.com/uploads/monthly_2019_01/pic02.thumb.png.5e819d7011eaa3c629b8a4cb5b4e31c0.png"></a>
</p>

<p>
	تحقّق من أن الخيار Server <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> يأخذ القيمة FPM/FastCGI وذلك في أعلى الصفحة كما في الصورة السابقة. سترى كذلك في أسفل الصفحة تقريبًا في القسم PHP Variables بأنّ قيمة SERVER_SOFTWARE هي Apache على Ubuntu. وهذا يؤكّد أنّ الوحدة mod_fastcgi مُفعّلة وأنّ Apache يستخدم PHP-FPM لمعالجة ملفات PHP.
</p>

<h2>
	الخطوة 5 - إنشاء مضيفات افتراضيّة لـ Apache
</h2>

<p>
	دعونا ننشئ ملفات المضيف الافتراضي لـ Apache للنطاقين foobar.net و test.io. سنقوم لعمل ذلك أولاً بإنشاء الأدلّة الجذر للمستند في كِلا الموقعين ووضع بعض الملفات الافتراضيّة في هذه الأدلة حتى نتمكن من اختبار الضبط لدينا بسهولة. أولاً، أنشئ الأدلّة الجذر للمستند:
</p>

<pre class="ipsCode">
$ sudo mkdir -v /var/www/foobar.net /var/www/test.io
</pre>

<p>
	أنشئ بعد ذلك ملف index لكل موقع:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_1987_6" style="">
<span class="pln">$ echo </span><span class="str">"&lt;h1 style='color: green;'&gt;Foo Bar&lt;/h1&gt;"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> sudo tee </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">www</span><span class="pun">/</span><span class="pln">foobar</span><span class="pun">.</span><span class="pln">net</span><span class="pun">/</span><span class="pln">index</span><span class="pun">.</span><span class="pln">html
$ echo </span><span class="str">"&lt;h1 style='color: red;'&gt;Test IO&lt;/h1&gt;"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> sudo tee </span><span class="pun">/</span><span class="kwd">var</span><span class="pun">/</span><span class="pln">www</span><span class="pun">/</span><span class="pln">test</span><span class="pun">.</span><span class="pln">io</span><span class="pun">/</span><span class="pln">index</span><span class="pun">.</span><span class="pln">html</span></pre>

<p>
	" | sudo tee /var/www/test.io/index.html ثم أنشئ ملف ()phpinfo لكل موقع حتى نتمكن من اختبار فيما إذا ضُبط PHP بشكل صحيح.
</p>

<pre class="ipsCode">
$ echo "" | sudo tee /var/www/foobar.net/info.php         
$ echo "" | sudo tee /var/www/test.io/info.php
</pre>

<p>
	الآن أنشئ ملف المضيف الافتراضي للنطاق foobar.net:
</p>

<pre class="ipsCode">
$ sudo nano /etc/apache2/sites-available/foobar.net.conf
</pre>

<p>
	أضف الشفرة التالية إلى الملف لتعريف المضيف:
</p>

<pre class="ipsCode">
/etc/apache2/sites-available/foobar.net.conf
	<virtualhost>
    	ServerName foobar.net
    	ServerAlias www.foobar.net
    	DocumentRoot /var/www/foobar.net
    	<directory foobar.net="" var="" www="">
        	AllowOverride All
    	</directory></virtualhost></pre>

<p>
	يتيح السطر AllowOverride All تفعيل دعم htaccess. احفظ وأغلق الملف. ثم أنشئ ملف ضبط مماثل لـ test.io. أولاً أنشئ الملف:
</p>

<pre class="ipsCode">
$ sudo nano /etc/apache2/sites-available/test.io.conf
</pre>

<p>
	ثم أضف الضبط إلى الملف:
</p>

<pre class="ipsCode">
	 /etc/apache2/sites-available/test.io.conf
 <virtualhost>
        ServerName test.io
        ServerAlias www.test.io
        DocumentRoot /var/www/test.io
        <directory test.io="" var="" www="">
            AllowOverride All
        </directory></virtualhost></pre>

<p>
	احفظ الملف وإغلاق المحرّر. والآن بعد إعداد كل من مضيفي Apache الافتراضيين، فعّل المواقع باستخدام الأمر a2ensite. والذي يُنشئ رابط رمزي لمَلف المضيف الافتراضي في الدليل sites-enabled:
</p>

<pre class="ipsCode">
$ sudo a2ensite foobar.net
$ sudo a2ensite test.io
</pre>

<p>
	تحقّق من Apache للتأكّد من وجود أخطاء في الضبط مرّة أخرى:
</p>

<pre class="ipsCode">
$ sudo apachectl –t
</pre>

<p>
	سترى عبارة Syntax OK إذا لم يكن هناك أخطاء. إذا رأيت أي شيء آخر، فتحقّق من الضبط وحاول مرّة أخرى. قم بإعادة تحميل Apache لتطبيق التغييرات بمجرّد أن يكون الضبط الخاص بك خاليًا من الأخطاء:
</p>

<pre class="ipsCode">
$ sudo systemctl reload apache2
</pre>

<p>
	افتح <a href="http://foobar.net:8080" ipsnoembed="true" rel="external nofollow">http://foobar.net:8080</a> و <a href="http://test.io:8080" ipsnoembed="true" rel="external nofollow">http://test.io:8080</a> في متصفحك للتأكّد من عمل المواقع والتحقّق من أنّ كل موقع يعرض ملف index.html الخاص به. سترى النتائج التالية:
</p>

<p>
	<img alt="pic03.png" class="ipsImage ipsImage_thumbnailed" data-fileid="28758" data-unique="1du5bc33v" src="https://academy.hsoub.com/uploads/monthly_2019_01/pic03.png.0482d06d5ab825c5fb16af893247635e.png"></p>

<p>
	<img alt="pic04.png" class="ipsImage ipsImage_thumbnailed" data-fileid="28759" data-unique="w7vygju68" src="https://academy.hsoub.com/uploads/monthly_2019_01/pic04.png.9206d724c25c2631b6835038d8e7cad4.png"></p>

<p>
	تأكّد أيضًا من أن PHP تعمل وذلك عن طريق الوصول إلى ملفات info.php لكل موقع. افتح <a href="http://foobar.net:8080/info.php" ipsnoembed="true" rel="external nofollow">http://foobar.net:8080/info.php</a> و <a href="http://test.io:8080/info.php" ipsnoembed="true" rel="external nofollow">http://test.io:8080/info.php</a> في متصفحك. سترى قائمة مواصفات ضبط PHP نفسها على كل موقع كما رأيت في الخطوة 4. لدينا الآن موقعين مُستضافين على Apache على المنفذ 8080. فلنَضبط بعد ذلك Nginx.
</p>

<h2>
	الخطوة 6 - تثبيت وضبط Nginx
</h2>

<p>
	سنقوم في هذه الخطوة بتثبيت Nginx وإعداد ضبط النطاقات example.com و sample.org كمضيفين افتراضيين لـ Nginx. ثبّت Nginx باستخدام مدير الحزم:
</p>

<pre class="ipsCode">
$ sudo apt install nginx
</pre>

<p>
	أزل الرابط الرمزي الافتراضي للمضيف الافتراضي حيث أننا لن نستخدمه بعد الآن:
</p>

<pre class="ipsCode">
$ sudo rm /etc/nginx/sites-enabled/default
</pre>

<p>
	سنُنشئ الموقع الافتراضي الخاص بنا فيما بعد (example.com). سنُنشئ الآن مضيفين افتراضيين لـ Nginx باستخدام نفس الإجرائيّة التي استخدمناها من أجل Apache. أنشئ أولاً الأدلّة للمستند الجذر لكل من موقعي الويب:
</p>

<pre class="ipsCode">
$ sudo mkdir -v /usr/share/nginx/example.com /usr/share/nginx/sample.org
</pre>

<p>
	سنحتفظ بمواقع الويب الخاصّة بـ Nginx في /usr/share/nginx، وهو المسار الافتراضي الذي سيختاره Nginx. يمكنك وضع هذه المواقع في /var/www/html مع مواقع Apache، لكن هذا الفصل بينها قد يساعدك على ربط المواقع بـ Nginx. كما فعلت مع مضيفي Apache الافتراضيين، أنشئ ملفات index و ()phpinfo من أجل الاختبار بعد اكتمال الإعداد:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_6534_10" style="">
<span class="pln">$ echo </span><span class="str">"&lt;h1 style='color: green;'&gt;Example.com&lt;/h1&gt;"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> sudo tee </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">share</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">/</span><span class="pln">example</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">index</span><span class="pun">.</span><span class="pln">html
$ echo </span><span class="str">"&lt;h1 style='color: red;'&gt;Sample.org&lt;/h1&gt;"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> sudo tee </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">share</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">/</span><span class="pln">sample</span><span class="pun">.</span><span class="pln">org</span><span class="pun">/</span><span class="pln">index</span><span class="pun">.</span><span class="pln">html
$ echo </span><span class="str">"&lt;?php phpinfo(); ?&gt;"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> sudo tee </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">share</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">/</span><span class="pln">example</span><span class="pun">.</span><span class="pln">com</span><span class="pun">/</span><span class="pln">info</span><span class="pun">.</span><span class="pln">php
$ echo </span><span class="str">"&lt;?php phpinfo(); ?&gt;"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> sudo tee </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">share</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">/</span><span class="pln">sample</span><span class="pun">.</span><span class="pln">org</span><span class="pun">/</span><span class="pln">info</span><span class="pun">.</span><span class="pln">php</span></pre>

<p>
	الآن أنشئ ملف مضيف افتراضي للنطاق example.com:
</p>

<pre class="ipsCode">
$ sudo nano /etc/nginx/sites-available/example.com
</pre>

<p>
	يستدعي Nginx كتل server {. . .} من ملف الضبط server blocks. أنشئ كتلة خادم من أجل المضيف الافتراضي الأساسي example.com. تجعل ضبط التوجيه default_server هذا المضيف كمضيف افتراضي افتراضي لمعالجة طلبات HTTP التي لا تتطابق مع أي مضيف افتراضي آخر.
</p>

<pre class="ipsCode">
/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;
	}
}
</pre>

<p>
	احفظ وأغلق الملف. أنشئ الآن ملف مضيف Nginx افتراضي للنطاق الثاني، sample.org:
</p>

<pre class="ipsCode">
$ sudo nano etc/nginx/sites-available/sample.org
</pre>

<p>
	أضف ما يلي إلى الملف:
</p>

<pre class="ipsCode">
/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;
    }
}
</pre>

<p>
	احفظ وأغلق الملف. ثم فعّل كِلا الموقعين من خلال إنشاء روابط رمزيّة للدّليل sites-enabled:
</p>

<pre class="ipsCode">
$ 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
</pre>

<p>
	اختبر بعد ذلك ضبط Nginx لضمان عدم وجود أخطاء في الضبط:
</p>

<pre class="ipsCode">
$ sudo nginx -t
</pre>

<p>
	ثم أعد تحميل Nginx إذا لم يكن هناك أخطاء:
</p>

<pre class="ipsCode">
$ sudo systemctl reload nginx
</pre>

<p>
	الآن قم بالوصول إلى ملف ()phpinfo الخاص بمُضيفي Nginx الافتراضيين من متصفح الويب من خلال زيارة <a href="http://sample.org/info.php" ipsnoembed="false" rel="external nofollow">http://sample.org/info.php</a> و <a href="http://example.com/info.php." ipsnoembed="false" rel="external nofollow">http://example.com/info.php.</a> انظر مجدّدًا إلى الصورة في الأسفل إلى قسم المتغيرات PHP Variables.
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="28762" href="https://academy.hsoub.com/uploads/monthly_2019_01/pic06.png.c963b968dcccfd77faab62a3ef4f42c4.png" rel=""><img alt="pic06.png" class="ipsImage ipsImage_thumbnailed" data-fileid="28762" data-unique="h4r66mweb" src="https://academy.hsoub.com/uploads/monthly_2019_01/pic06.thumb.png.8d2731cf85668b217e1070a0d76fbd2b.png"></a>
</p>

<p>
	يجب أن يحوي["SERVER_SOFTWARE"] على القيمة Nginx، مشيرًا إلى أنّ الملفات خُدّمت بشكل مباشر بواسطة Nginx. يجب أن يشير["DOCUMENT_ROOT"] إلى الدليل الذي أنشأته مُسبقًا في هذه الخطوة لكل موقع من مواقع Nginx. ثبّتنا في هذه المرحلة Nginx وأنشأنا مضيفين افتراضيين.سنقوم بعد ذلك بضبط Nginx على طلبات الوكيل المخصّصة للنطاقات المستضافة على Apache.
</p>

<h2>
	الخطوة 7 - ضبط Nginx لمضيفي Apache الافتراضيين
</h2>

<p>
	لنُنشئ مضيف Nginx افتراضي إضافي مع أسماء نطاقات متعددة في توجيهات server_name. سيتم توكيل طلبات هذه النطاقات إلى Apache. أنشئ ملف مضيف Nginx افتراضي جديد لإعادة توجيه الطلبات إلى Apache:
</p>

<pre class="ipsCode">
$ sudo nano /etc/nginx/sites-available/apache
</pre>

<p>
	أضف كتلة الشفرة التالية التي تحدد أسماء نطاقات كلاً من مضيفي Apache الاتراضيين وتوكل طلباتها إلى Apache. تذكّر استخدام عنوان IP العام في proxy_pass:
</p>

<pre class="ipsCode">
/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;
    }
}
</pre>

<p>
	قم بحفظ الملف وتفعيل هذا المضيف الافتراضي الجديد عن طريق إنشاء رابط رمزي:
</p>

<pre class="ipsCode">
$ sudo ln -s /etc/nginx/sites-available/apache /etc/nginx/sites-enabled/apache
</pre>

<p>
	اختبر الضبط للتأكد من عدم وجود أخطاء:
</p>

<pre class="ipsCode">
$ sudo nginx -t
</pre>

<p>
	إذا لم يكن هنالك أخطاء، أعد تحميل Nginx:
</p>

<pre class="ipsCode">
$ sudo systemctl reload nginx
</pre>

<p>
	افتح متصفحك وقم بالوصول إلى العنوان <a href="http://foobar.net/info.php." ipsnoembed="true" rel="external nofollow">http://foobar.net/info.php.</a> انتقل لأسفل إلى قسم PHP Variables وتحقق من القيم المعروضة كما في الصورة.
</p>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="28760" href="https://academy.hsoub.com/uploads/monthly_2019_01/pic05.png.eeff199b2bade0a855cc312ce5ee25fd.png" rel=""><img alt="pic05.png" class="ipsImage ipsImage_thumbnailed" data-fileid="28760" data-unique="jahwsxn7s" src="https://academy.hsoub.com/uploads/monthly_2019_01/pic05.thumb.png.399c5f61da57932ac96644b5835a1a54.png"></a>
</p>

<p>
	يؤكّد المتغيران ERVER_SOFTWARE و DOCUMENT_ROOT أنّ هذا الطلب عُولج بواسطة Apache. وأضيفت المتغيرات HTTP_X_REAL_IP و HTTP_X_FORWARDED_FOR بواسطة Nginx ويجب أن تُظهر عنوان IP العام للحاسب الذي تستخدمه للوصول إلى عنوان URL. لقد أعددنا Nginx بنجاح ليوكل بطلبات نطاقات محدّدة إلى Apache. بعد ذلك، لنقم بضبط Apache لضبط المتغير REMOTE_ADDR كما لو أنه يتعامل مع هذه الطلبات مباشرة.
</p>

<h2>
	الخطوة 8 - تثبيت وضبط mod_rpaf
</h2>

<p>
	سنُثبّت في هذه الخطوة وحدة Apache تسمى mod\_rpaf والتي تعيد كتابة قيم REMOTE_ADDR، HTTPS و HTTP_PORT استنادًا إلى القيم المقدّمة من قبل وسيط عكسي. وبدون هذه الوحدة، تتطلب بعض تطبيقات PHP تغييرات في الشفرة للعمل بسلاسة من خلفْ الخادم الوكيل. هذه الوحدة موجودة في مستودع Ubuntu باسم libapache2-mod-rpaf ولكنها قديمة ولا تدعم توجيهات ضبط معينة. سنقوم بدلاً من ذلك بتثبيتها من المصدر. تثبيت الحزم اللازمة لبناء الوحدة:
</p>

<pre class="ipsCode">
$ sudo apt install unzip build-essential apache2-dev
</pre>

<p>
	نزّل أحدث إصدار مستقر من GitHub:
</p>

<pre class="ipsCode">
$ wget https://github.com/gnif/mod_rpaf/archive/stable.zip
</pre>

<p>
	استخراج الملف الذي نزل:
</p>

<pre class="ipsCode">
$ unzip stable.zip
</pre>

<p>
	انتقل إلى المجلد الجديد الذي يحتوي على الملفات:
</p>

<pre class="ipsCode">
$ cd mod_rpaf-stable
</pre>

<p>
	ترجم Compile الوحدة ثم ثبّتها:
</p>

<pre class="ipsCode">
$ make
$ sudo make install
</pre>

<p>
	أنشئ بعد ذلك ملف في المجلد mods-available والذي سيُحمّل وحدة rpaf:
</p>

<pre class="ipsCode">
$ sudo nano /etc/apache2/mods-available/rpaf.load
</pre>

<p>
	أضف الشفرة التالية إلى الملف لتحميل الوحدة:
</p>

<pre class="ipsCode">
/etc/apache2/mods-available/rpaf.load
LoadModule rpaf_module /usr/lib/apache2/modules/mod_rpaf.so
</pre>

<p>
	احفظ الملف وأغلق المحرر. أنشئ ملف آخر في نفس الدليل وسمّه rpaf.conf والذي سوف يحتوي على توجيهات الضبط للوحدة mod_rpaf:
</p>

<pre class="ipsCode">
$ sudo nano /etc/apache2/mods-available/rpaf.conf
</pre>

<p>
	أضف كتلة الشفرة التالية لضبط mod_rpaf، مع التأكّد من تحديد عنوان IP الخاص بخادمك:
</p>

<pre class="ipsCode">
/etc/apache2/mods-available/rpaf.conf
   <ifmodule mod_rpaf.c="">
        RPAF_Enable           On
        RPAF_Header           X-Real-Ip
        RPAF_ProxyIPs         your_server_ip 
        RPAF_SetHostName      On
        RPAF_SetHTTPS         On
        RPAF_SetPort          On
    </ifmodule></pre>

<p>
	فيما يلي وصف موجز لكل توجيه. لمزيد من المعلومات، راجع ملف mod_rpaf README.
</p>

<ul>
<li>
		RPAF_Header - الترويسة المراد استخدامها لعنوان IP الحقيقي للعميل.
	</li>
	<li>
		RPAF_ProxyIPs - عنوان IP للوكيل لضبط طلبات HTTP من أجله.
	</li>
	<li>
		RPAF_SetHostName - يقوم بتحديث اسم المضيف الافتراضي بحيث يعمل كل من ServerName و ServerAlias.
	</li>
	<li>
		RPAF_SetHTTPS - يضبط متغير بيئة HTTPS استنادًا إلى القيمة الموجودة في X-Forwarded-Proto.
	</li>
	<li>
		RPAF_SetPort - يضبط متغير بيئة SERVER_PORT. يكون مفيد عندما يكون Apache يعمل خلف وكيل <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr>.
	</li>
</ul>
<p>
	احفظ الملف rpaf.conf وقم بتفعيل الوحدة:
</p>

<pre class="ipsCode">
$ sudo a2enmod rpaf
</pre>

<p>
	يؤدي هذا إلى إنشاء روابط رمزيّة من الملفات rpaf.load و rpaf.conf في الدليل mods-enabled. الآن قم بإجراء اختبار الضبط:
</p>

<pre class="ipsCode">
$ sudo apachectl -t
</pre>

<p>
	أعد تحميل Apache إذا لم يكن هنالك أخطاء:
</p>

<pre class="ipsCode">
$ sudo systemctl reload apache2
</pre>

<p>
	قم بالوصول إلى الملف ()phpinfo في الصفحات <a href="http://foobar.net/info.php" ipsnoembed="false" rel="external nofollow">http://foobar.net/info.php</a> و <a href="http://test.io/info.php" ipsnoembed="false" rel="external nofollow">http://test.io/info.php</a> من متصفحك وتحقق من قسم PHP Variables. الآن سيكون المتغير REMOTE_ADDR هو أيضًا عنوان IP العام للحاسب المحلي لديك. الآن دعنا نعد تشفير <abbr title="Transport Layer Security | بروتوكول أمن طبقة النقل">TLS</abbr> / <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> لكل موقع.
</p>

<h2>
	الخطوة 9 - إعداد مواقع HTTPS باستخدام Let's Encrypt (اختياري)
</h2>

<p>
	سنضبط في هذه الخطوة شهادات <abbr title="Transport Layer Security | بروتوكول أمن طبقة النقل">TLS</abbr> / <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> لكل من النطاقات المُستضافة على Apache. سوف نحصل على الشهادات بواسطة [Let's Encrypt](https://letsencrypt.org]. يدعم Nginx إنهاء <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr>، لذا من الممكن إعداد <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> بدون تعديل ملفات ضبط Apache. تَضمنْ الوحدة mod_rpaf أن يتم تعيين متغيرات البيئة المطلوبة على Apache لجعل التطبيقات تعمل بسلاسة خلفْ وكيل عكسي لـ <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr>. أولاً سنفصل كتل الخادم {...}server من كِلا النطاقين بحيث يمكن أن يكون لكلٍ منهما شهادات <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> خاصّة به. افتح الملف etc/nginx/sites-available/apache/ في المحرّر الخاص بك:
</p>

<pre class="ipsCode">
$ sudo nano /etc/nginx/sites-available/apache
</pre>

<p>
	عدّل الملف بحيث يبدو مثل هذا، مع foobar.net و test.io في كتل الخادم الخاصّة بهم:
</p>

<pre class="ipsCode">
/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;
        }
    }
</pre>

<p>
	سنستخدم Certbot لإنشاء شهادات <abbr title="Transport Layer Security | بروتوكول أمن طبقة النقل">TLS</abbr>/<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> الخاصّة بنا. ستتولى إضافة Nginx plugin" Nginx" مُهمة إعادة ضبط Nginx وإعادة تحميل الضبط عند الضرورة. أولاً، أضف مستودع Certbot المرخّص:
</p>

<pre class="ipsCode">
$ sudo add-apt-repository ppa:certbot/certbot
</pre>

<p>
	اضغط على ENTER عند مطالبتك بتأكيد رغبتك في إضافة المستودع الجديد. ثم قم بتحديث قائمة الحزم للحصول على معلومات حزمة المستودع الجديدة:
</p>

<pre class="ipsCode">
$ sudo apt update
</pre>

<p>
	ثم ثبّت حزمة Nginx الخاصّة بـ Certbot باستخدام apt:
</p>

<pre class="ipsCode">
$ sudo apt install python-certbot-nginx
</pre>

<p>
	وبمجرّد تثبيته، استخدم أمر certbot لإنشاء الشهادات لـ foobar.net و www.foobar.net:
</p>

<pre class="ipsCode">
$ sudo certbot --nginx -d foobar.net -d www.foobar.net
</pre>

<p>
	يخبر هذا الأمر Certbot ليستخدم ملحق nginx، وباستخدم –d لتحديد الأسماء التي نودّ أن تكون الشهادة صالحة لها. إذا كانت هذه هي المرة الأولى التي تُشغّل فيها certbot، فسَتتم مطالبتك بإدخال عنوان بريد إلكتروني والموافقة على شروط الخدمة. سيتصل بعد القيام بذلك certbot بخادم Let's Encrypt، ثم يشغّل ردّا للتحقق من أنّك تتحكم في النطاق الذي تطلب الحصول على شهادة له. سَيسألك Certbot بعد ذلك عن الطريقة التي ترغب في ضبط إعدادات HTTPS الخاصّة بك:
</p>

<pre class="ipsCode">
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):
</pre>

<p>
	حدّد خيارك، ثم اضغط على ENTER. سيتم تحديث الضبط، وإعادة تحميل Nginx لتفعيل الإعدادات الجديدة. الآن، نفّذ الأمر للنطاق الثاني:
</p>

<pre class="ipsCode">
$ sudo certbot --nginx -d test.io -d www.test.io
</pre>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="28761" href="https://academy.hsoub.com/uploads/monthly_2019_01/pic07.png.0a32ceba8c9d0e2e83929125ec95cf96.png" rel=""><img alt="pic07.png" class="ipsImage ipsImage_thumbnailed" data-fileid="28761" data-unique="bc4kidegk" src="https://academy.hsoub.com/uploads/monthly_2019_01/pic07.thumb.png.215f8ca8c9980f6965dc575403c8e1b4.png"></a>
</p>

<p>
	انظر في قسم PHP Variables. تم تعيين المتغير SERVER_PORT على القيمة 443 وضبط HTTPS على القيمة on، كما لو أنّه تم الوصول إلى Apache مباشرةً عبر HTTPS. مع ضبط هذه المتغيرات، لن تحتاج تطبيقات PHP إلى إعداد خاص للعمل خلف وسيط عكسي. سنقوم الآن بتعطيل الوصول المباشر إلى Apache.
</p>

<h2>
	الخطوة 10 - حظر الوصول المباشر إلى Apache (اختياري)
</h2>

<p>
	بما أن Apache يستمع على المنفذ 8080 على عنوان IP العام، فإنّه بإمكان الجميع الوصول إليه. ويمكن حظره من خلال عمل الأمر IPtables التالي في مجموعة قواعد الجدار الناري.
</p>

<pre class="ipsCode">
$ sudo iptables -I INPUT -p tcp --dport 8080 ! -s your_server_ip -j REJECT --reject-with tcp-reset
</pre>

<p>
	تأكّد من استخدام عنوان IP لخَادمك مكان اللون الأحمر في المثال السابق. بمجرد حظر المنفذ 8080 في الجدار الناري، اختبر عدم إمكانية الوصول إلى Apache. افتح متصفح الويب الخاص بك وحاول الوصول إلى أحد أسماء نطاقات Apache على المنفذ 8080. على سبيل المثال: <a href="http://example.com:8080" ipsnoembed="false" rel="external nofollow">http://example.com:8080</a> يجب أن يعرض المتصفح رسالة خطأ "غير قادر على الاتصال" أو "صفحة الويب غير متوفرة". وبضبط خيار IPtables tcp-reset، لن يرى أحد أي اختلاف بين المنفذ 8080 والمنفذ الذي لا يحتوي أيّ خدمةٍ عليه. ملاحظة: عند إعادة تشغيل النظام وبشكل افتراضي لن تبقى قواعد IPtables كما حدّدناها. هناك طرق متعددة للحفاظ على قواعد IPtables، ولكن أسهلها هو استخدام iptables-persistent في مستودع Ubuntu. استكشف هذه المقالة لمعرفة المزيد حول كيفيّة ضبط IPTables. لنضبط الآن Nginx لخدمة ملفات ثابتة لمواقع Apache.
</p>

<h2>
	الخطوة 11 - تخديم الملفات الثابتة باستخدام Nginx (اختياري)
</h2>

<p>
	عندما يقدم وسيط Nginx طلبات لنطاقات Apache، فإنّه يرسل كل ملف طلب لهذا النطاق إلى Apache. Nginx أسرع من Apache في خدمة الملفات الثابتة مثل الصور، وجافا سكريبت وأوراق الأنماط. لذلك دعونا نضبط ملف مضيف apache افتراضي خاص بـ Nginx لتخديم الملفات الثابتة مباشرة ولكن مع إرسال طلبات PHP إلى Apache. افتح الملف etc/nginx/sites-available/apache/ في محرّرك الخاص:
</p>

<pre class="ipsCode">
$ sudo nano /etc/nginx/sites-available/apache
</pre>

<p>
	ستحتاج إلى إضافة موضعين location إضافيين لكل كتلة خادم، بالإضافة إلى تعديل أقسام location الموجودة. بالإضافة إلى ذلك، ستحتاج إلى إخبار Nginx بمكان تواجد الملفات الثابتة لكل موقع. إذا قرّرت عدم استخدام شهادات <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> و <abbr title="Transport Layer Security | بروتوكول أمن طبقة النقل">TLS</abbr>، فعدّل ملفك بحيث يبدو كالتالي:
</p>

<pre class="ipsCode">
/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;
{
{
</pre>

<p>
	إذا كنت تريد بأن يكون HTTPS متوفرًا أيضًا، فاستخدم الضبط التالي بدلاً من ذلك:
</p>

<pre class="ipsCode">

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 <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr>;
    ssl_certificate /etc/letsencrypt/live/test.io/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/test.io/privkey.pem;
    include /etc/letsencrypt/options-<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr>-nginx.conf;
    ssl_dhparam /etc/letsencrypt/<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr>-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 <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr>;
    ssl_certificate /etc/letsencrypt/live/foobar.net/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/foobar.net/privkey.pem;
    include /etc/letsencrypt/options-<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr>-nginx.conf;
    ssl_dhparam /etc/letsencrypt/<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr>-dhparams.pem;
{

</pre>

<p>
	إنّ التوجيه try_files يجعل Nginx يبحث عن الملفات في المستند الجذر ويقدّمها مباشرةً. إذا كان الملف له امتداد php.، سيتم تمرير الطلب إلى Apache. حتى إذا لم يُعثر على الملف في المستند الجذر، يُمرّر الطلب إلى Apache لتعمل ميزات التطبيق مثل permalinks بدون أخطاء. تحذير: إنّ التوجيه location ~ /\.ht مهم جداً؛ حيث يمنع Nginx من عرض محتويات ملفات الضبط Apache مثل htaccess. و htpasswd. التي تحتوي على معلومات حساسة. احفظ الملف وقم بإجراء اختبار الضبط:
</p>

<pre class="ipsCode">
$ sudo nginx -t
</pre>

<p>
	أعد تحميل Nginx إذا نجح الاختبار:
</p>

<pre class="ipsCode">
$ sudo service nginx reload
</pre>

<p>
	يمكنك للتحقّق من أن العمل تم بشكل صحيح فحص ملفات سجل Apache في var/log/apache2/ ومشاهدة طلبات GET لملفات info.php من test.io و foobar.net. استخدم الأمر tail لمشاهدة الأسطر القليلة الأخيرة من الملف، واستخدم رمز التبديل f- لمشاهدة الملف من أجل التغييرات:
</p>

<pre class="ipsCode">
$ sudo tail -f /var/log/apache2/other_vhosts_access.log
</pre>

<p>
	قم الآن بزيارة <a href="http://test.io/info.php" ipsnoembed="false" rel="external nofollow">http://test.io/info.php</a> في مستعرض الويب الخاص بك ثم انظر إلى خرج السجل. سترى أن Apache يجيب بالفعل:
</p>

<pre class="ipsCode">
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"</pre>

<p>
	ثم قم بزيارة صفحة index.html لكل موقع ولن ترى أي إدخالات للسجّل من قبل Apache. لأن Nginx هو من يخدّمهم. عند الانتهاء من معاينة ملف السجل، اضغط على CTRL + C لإيقاف تعقبّه. باستخدام هذا الإعداد، لن يكون Apache قادرًا على تقييد الوصول إلى الملفّات الثابتة. وللتَحكم في الوصول إلى الملفّات الثابتة تحتاج إلى ضبط في ملف المضيف apache الافتراضي الخاص بـ Nginx، ولكن هذا خارج نطاق هذه الدورة التعليميّة.
</p>

<h2>
	الخلاصة
</h2>

<p>
	لديك الآن خادم Ubuntu مع Nginx يُخدّم example.com و sample.org، جنبًا إلى جنب مع Apache والذي يُخدّم foobar.net و test.io. على الرغم من أن Nginx يعمل كوكيل عكسي لـ Apache، إلا أن خدمة الوكيل في Nginx تتسم بالشفافية وتُظهر اتصالها بنطاقات Apache كما لو أنها مخدّمة مباشرةً من Apache. يمكنك استخدام هذه الطريقة لتخديم مواقع آمنة وثابتة.
</p>

<p>
	ترجمة بتصرف للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-configure-nginx-as-a-web-server-and-reverse-proxy-for-apache-on-one-ubuntu-18-04-server" rel="external nofollow">How To Configure Nginx as a Web Server and Reverse Proxy for Apache on One Ubuntu 18.04 Server</a> لصاحبه Jesin A.
</p>
]]></description><guid isPermaLink="false">396</guid><pubDate>Sat, 26 Jan 2019 17:30:39 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641; &#x62A;&#x624;&#x645;&#x651;&#x646; &#x62E;&#x627;&#x62F;&#x645; &#x648;&#x64A;&#x628; NGINX &#x639;&#x644;&#x649; &#x623;&#x648;&#x628;&#x646;&#x62A;&#x648; 16.04</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81-%D8%AA%D8%A4%D9%85%D9%91%D9%86-%D8%AE%D8%A7%D8%AF%D9%85-%D9%88%D9%8A%D8%A8-nginx-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1604-r365/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_11/18-2.png.e87241c72ad5196af4b324d5da6d2bc8.png" /></p>

<h2>
	ما هي Let’s Encrypt
</h2>

<p>
	هي هيئة شهادات مجانية تابعة لمجموعة أبحاث أمن الإنترنت-Internet Security Research Group (ISRG)، وتقدم هذه الهيئة طريقة سهلة ومؤتمتة للحصول على شهادات <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr>/<abbr title="Transport Layer Security | بروتوكول أمن طبقة النقل">TLS</abbr> مجانية لجعل الزيارات على خادم الويب مشفرة وعبر بروتوكول HTTPS. ومعظم خطوات الحصول على الشهادة وتثبيتها يمكن جعلها تتم تلقائيًا باستخدام أداة Certbot.<br>
	وهذه الأداة يمكن استخدامها حين يتسنى الاتصال بالخادم عبر <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr>، أي حين يوجد دخول من الصدفة “Shell” على الخادم. وسنرى في هذا المقال كيف نستخدم Certbot للحصول على شهادة <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> مجانية ومن ثم استخدامها مع NGINX على خادم أوبنتو 16.04
</p>

<h2 id="تثبيت-certbot">
	تثبيت Certbot
</h2>

<p>
	سنضيف مستودع Certbot أولًا، لماذا؟ لأن مطوريه يقومون على صيانة وتحديث هذا المستودع بآخر إصدار من Certbot أولًا بأول، بشكل أسرع مما تفعله أوبنتو بالبرنامج في مستودعاتها، فأوبنتو تحتاج وقتًا لمراجعة كل برنامج يدخل مستودعاتها، خاصة إن كان في إصدار LTS مثل 16.04، وبالتالي فمن الطبيعي أن يتأخر كل برنامج قليلًا حتى يدخل تلك المستودعات.<br>
	والآن، لإضافة مستودع Certbot:
</p>

<pre class="ipsCode" id="ips_uid_1537_7">
# add-apt-repository ppa:certbot/certbot</pre>

<p>
	ثم نحدّث قائمة APT
</p>

<pre class="ipsCode" id="ips_uid_1537_7">
<code class="hljs vala"><span class="hljs-preprocessor"><span class="com"># apt-get update</span></span></code></pre>

<p>
	ونثبّت البرنامج
</p>

<pre class="ipsCode" id="ips_uid_1537_7">
<code class="hljs vala"><span class="hljs-preprocessor"><span class="com"># apt-get install certbot</span></span></code></pre>

<h2 id="الحصول-على-الشهادة">
	الحصول على الشهادة
</h2>

<p>
	هناك العديد من إضافات Certbot التي يمكن الحصول على شهادة <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> من خلالها، ويقوم مدير الخادم بتثبيتها وتهيئة الخادم بعد ذلك بنفسه. وسنستخدم إضافة Webroot في هذا المقال، وهي إضافة تصلح للحالات التي يمكن فيها تعديل المحتوى، ولسنا في حاجة لإيقاف الخادم أثناء عملية تصدير الشهادة.
</p>

<h2 id="تهيئة-nginx">
	تهيئة NGINX
</h2>

<p>
	تنشئ Webroot ملفًا مؤقتًا لكل نطاق في مجلد مخفي اسمه well-known، موجود في المجلد الجذر لـweb، وفي حالتنا فإن مجلد web موجود في var/www/html/.<br>
	تأكد أن Let’s Encrypt لديها صلاحية الوصول لهذا المجلد، من خلال تعديل تهيئة NGINX. ولفعل ذلك، نفذ هذا الأمر لفتح الملف الذي سنعدّل فيه (استبدل $EDITOR بمحرر نصي من تفضيلك):
</p>

<pre class="ipsCode" id="ips_uid_1537_7">
<code class="hljs vala"><span class="hljs-preprocessor"><span class="com"># $EDITOR /etc/nginx/sites-available/default</span></span></code></pre>

<p>
	ضع هذه الأسطر في قسم server داخل الملف:
</p>

<pre class="ipsCode" id="ips_uid_1537_7">
<code class="hljs lasso"><span class="pln"> location </span><span class="pun">~</span><span class="pln"> </span><span class="hljs-subst"><span class="pun">/</span></span><span class="hljs-built_in"><span class="pun">.</span></span><span class="pln">well</span><span class="hljs-attribute"><span class="pun">-</span><span class="pln">known</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    allow </span><span class="hljs-literal"><span class="pln">all</span></span><span class="pun">;</span><span class="pln">
 </span><span class="pun">}</span></code></pre>

<p>
	احفظ الملف واخرج، ثم تفقد تهيئة NGINX عبر الأمر التالي:
</p>

<pre class="ipsCode" id="ips_uid_1537_7">
<code class="hljs vala"><span class="hljs-preprocessor"><span class="com"># nginx -t</span></span></code></pre>

<p>
	ويجب أن ترى هذين السطرين -بفرض نجاح الأمر-:
</p>

<pre class="ipsCode" id="ips_uid_1537_7">
<code class="hljs vhdl"><span class="pln">nginx</span><span class="pun">:</span><span class="pln"> the </span><span class="hljs-keyword"><span class="pln">configuration</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">file</span></span><span class="pln"> </span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">.</span><span class="pln">conf syntax </span><span class="hljs-keyword"><span class="kwd">is</span></span><span class="pln"> ok
nginx</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">configuration</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">file</span></span><span class="pln"> </span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">/</span><span class="pln">nginx</span><span class="pun">.</span><span class="pln">conf test </span><span class="hljs-keyword"><span class="kwd">is</span></span><span class="pln"> successful</span></code></pre>

<p>
	والآن أعد تشغيل NGINX:
</p>

<pre class="ipsCode" id="ips_uid_1537_7">
<code class="hljs vala"><span class="hljs-preprocessor"><span class="com"># systemctl restart nginx</span></span></code></pre>

<h3>
	الحصول على الشهادة باستخدام Certbot
</h3>

<p>
	الخطوة التالية هي الحصول على شهادة جديدة باستخدام Certbot مع إضافة Webroot. وسنؤمّن في هذا الشرح (كمثال) نطاق www.example.com عبر الأمر التالي: (لا تنسى أنك يجب أن تحدد كل نطاق تريد تأمينه بهذه الشهادة).
</p>

<pre class="ipsCode" id="ips_uid_1537_7">
<code class="hljs brainfuck"><span class="hljs-comment"><span class="com">#</span></span><span class="com"> </span><span class="hljs-comment"><span class="com">certbot</span></span><span class="com"> </span><span class="hljs-comment"><span class="com">certonly</span></span><span class="com"> </span><span class="hljs-literal"><span class="com">-</span></span><span class="hljs-literal"><span class="com">-</span></span><span class="hljs-comment"><span class="com">webroot</span></span><span class="com"> </span><span class="hljs-literal"><span class="com">-</span></span><span class="hljs-literal"><span class="com">-</span></span><span class="hljs-comment"><span class="com">webroot</span></span><span class="hljs-literal"><span class="com">-</span></span><span class="hljs-comment"><span class="com">path=/var/www/html</span></span><span class="com"> </span><span class="hljs-literal"><span class="com">-</span></span><span class="hljs-comment"><span class="com">d</span></span><span class="com"> </span><span class="hljs-comment"><span class="com">www</span></span><span class="hljs-string"><span class="com">.</span></span><span class="hljs-comment"><span class="com">example</span></span><span class="hljs-string"><span class="com">.</span></span><span class="hljs-comment"><span class="com">com</span></span></code></pre>

<p>
	سيسألك Certbot خلال العملية عن بريد إلكتروني صالح من أجل الإشعارات، وسيطلب منك مشاركته مع EFF، غير أن ذلك غير ضروري، وسيكون لديك الشهادةبعد الموافقة على شروط الخدمة.<br>
	وبعد انتهاء العملية، سيحتوى مجلد etc/letsencrypt/archive/ على الملفات التالية:
</p>

<ul>
<li>
		chain.pem: شهادة السلسلة-Chain Certificate الخاصة بـLet’s Encrypt.
	</li>
	<li>
		cert.pem: شهادة النطاق.
	</li>
	<li>
		fullchain.pem: دمج للشهادتين السابقتين.
	</li>
	<li>
		privkey.pem: المفتاح الخاص للشهادة.
	</li>
</ul>
<p>
	كما سينشئ Certbot روابط رمزية لآخر ملفات الشهادة في etc/letsencrypt/live/domain_name/، وهو المسار الذي سنستخدمه في تهيئة الخادم.
</p>

<h2 id="تهيئة-ssltls-على-nginx">
	تهيئة <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr>/<abbr title="Transport Layer Security | بروتوكول أمن طبقة النقل">TLS</abbr> على NGINX
</h2>

<p>
	الخطوة التالية هي تهيئة الخادم، أنشئ قصاصة-snippet جديدة في etc/nginx/snippets، تلك القصاصة هي جزء من ملف تهيئة يمكن إدراجه في ملفات تهيئة المضيف الوهمي-virtual host. أنشئ ملف جديد (استخدم محررك النصي بدلًا من $EDITOR)
</p>

<pre class="ipsCode" id="ips_uid_1537_7">
<code class="hljs vala"><span class="hljs-preprocessor"><span class="com"># $EDITOR /etc/nginx/snippets/secure-example.conf</span></span></code></pre>

<p>
	محتويات هذا الملف ستكون الموجّهات التي تحدد مواقع الشهادة والمفتاح، الصق المحتوى التالي في الملف:
</p>

<pre class="ipsCode" id="ips_uid_1537_7">
<code class="hljs avrasm"><span class="pln">ssl_certificate </span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">letsencrypt</span><span class="pun">/</span><span class="pln">live</span><span class="pun">/</span><span class="pln">domain_name</span><span class="pun">/</span><span class="pln">fullchain</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">pem</span></span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
ssl_certificate_key </span><span class="pun">/</span><span class="pln">etc</span><span class="pun">/</span><span class="pln">letsencrypt</span><span class="pun">/</span><span class="pln">live</span><span class="pun">/</span><span class="pln">domain_name</span><span class="pun">/</span><span class="pln">privkey</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">pem</span></span><span class="hljs-comment"><span class="pun">;</span></span></code></pre>

<p>
	في مثالنا الذي نشرحه، سيكون domain_name هو example.com.
</p>

<h3 id="تعديل-تهيئة-nginx">
	تعديل تهيئة NGINX
</h3>

<p>
	افتح الملف الافتراضي للمضيف الوهمي:
</p>

<pre class="ipsCode" id="ips_uid_1537_13">
# $EDITOR /etc/nginx/sites-available/default</pre>

<p>
	عدل محتواه كما يلي:
</p>

<pre class="ipsCode" id="ips_uid_1537_11">
server {
 listen 80 default_server;
 listen [::]:80 default_server;
 server_name www.example.com
 return 301 https://$server_name$request_uri;

 # <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> configuration
 #
 listen 443 <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr> default_server;
 listen [::]:443 <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr> default_server;
 include snippets/secure-example.conf
 #
 # Note: You should disable gzip for <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr> traffic.
 # See: https://bugs.debian.org/773332
…</pre>

<p>
	كان هذا الكود من أجل تفعيل التشفير في NGINX، احفظ الملف واخرج ثم تأكد من ملف تهيئة NGINX:
</p>

<pre class="ipsCode" id="ips_uid_1537_9">
# 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</pre>

<h2>
	خاتمة
</h2>

<p>
	<br>
	إن اتبعت الخطوات السابقة فيجب أن يكون لديك الآن خادم آمن مبني على NGINX، مع تشفير من Certbot وLet’s Encrypt. وهذه إعدادات أساسية قطعًا، فيمكنك استخدام معاملات-parameters كثيرة في NGINX لتعديل تهيئته وتخصيصه، حسب حاجة خادم الويب.
</p>

<p>
	ترجمة -بتصرف- لمقال <a href="https://www.unixmen.com/encryption-secure-nginx-web-server-ubuntu-16-04/" rel="external nofollow">Encryption: How To Secure an NGINX web server on Ubuntu 16.04</a> لصاحبه Giuseppe Molica
</p>
]]></description><guid isPermaLink="false">365</guid><pubDate>Sat, 18 Nov 2017 19:36:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x627;&#x644;&#x627;&#x633;&#x62A;&#x641;&#x627;&#x62F;&#x629; &#x645;&#x646; &#x627;&#x644;&#x62A;&#x62E;&#x632;&#x64A;&#x646; &#x627;&#x644;&#x645;&#x624;&#x642;&#x62A; &#x641;&#x64A; &#x627;&#x644;&#x645;&#x62A;&#x635;&#x641;&#x62D; &#x628;&#x627;&#x633;&#x62A;&#x639;&#x645;&#x627;&#x644; &#x648;&#x62D;&#x62F;&#x629; header &#x641;&#x64A; &#x62E;&#x627;&#x62F;&#x648;&#x645; Nginx &#x641;&#x64A; &#x623;&#x648;&#x628;&#x646;&#x62A;&#x648; 16.04</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D8%A9-%D9%85%D9%86-%D8%A7%D9%84%D8%AA%D8%AE%D8%B2%D9%8A%D9%86-%D8%A7%D9%84%D9%85%D8%A4%D9%82%D8%AA-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D9%88%D8%AD%D8%AF%D8%A9-header-%D9%81%D9%8A-%D8%AE%D8%A7%D8%AF%D9%88%D9%85-nginx-%D9%81%D9%8A-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1604-r306/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_03/main.png.f490a15caf6be503448a6ae10b146af6.png" /></p>

<h3>
	تمهيد
</h3>

<p>
	كلما كانت صفحات الموقع أسرع تحميلًا كلما ازداد احتمال بقاء الزائر متصفحًا للموقع، وعندما تمتلئ صفحات مواقع الويب بالصور والمحتوى التفاعلي الظاهر عبر سكربتات تُحمَّل في الخلفية، فلن تكون عملية فتح «صفحة» ويب أمرًا هينًا، إذ تتضمن طلب ملفاتٍ عدِّة من خادوم الويب ملفًا ملفًا، وعملية تقليل تلك الطلبيات هي إحدى سُبُل تسريع موقعك.
</p>

<p style="text-align: center;">
	<img alt="main.png" class="ipsImage ipsImage_thumbnailed" data-fileid="22170" data-unique="3ya3jp8rf" src="https://academy.hsoub.com/uploads/monthly_2017_03/main.png.da9638c9cef009335c63147cea831655.png"></p>

<p>
	يمكن فعل ذلك بطرائق عدِّة، لكن إحدى أهم الخطوات التي يجب إجراؤها هي ضبط التخزين المؤقت في المتصفح (browser caching)؛ وهذا يعني إخبار المتصفح بإمكانية استخدام نسخ محلية من الملفات التي حُمِّلَت في إحدى المرات بدلًا من طلبها من الخادوم مرارًا وتكرارًا؛ ولفعل ذلك يجب إضافة ترويسات لرد HTTP ‏(HTTP response headers) تخبر المتصفح بما عليك فعله.<br>
	هذا هو دور وحدة header (‏header module) في خادوم Nginx، التي يمكن استعمالها لإضافة الترويسات إلى رد HTTP، لكن دورها الأساسي يمكن في ضبط الترويسات المسؤولة عن التخزين المؤقت. سننظر في هذا الدرس إلى كيفية استخدام وحدة header لتطبيق الفكرة السابقة.
</p>

<h3 id="المتطلبات-المسبقة">
	المتطلبات المسبقة
</h3>

<p>
	ستحتاج قبل إكمال قراءة هذا الدرس إلى ما يلي:<br>
	خادوم أوبنتو 16.04 (أو 14.04) مضبوطٌ كما في درس «<a href="https://academy.hsoub.com/devops/servers/%D8%A7%D9%84%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A7%D9%84%D8%A7%D8%A8%D8%AA%D8%AF%D8%A7%D8%A6%D9%8A-%D9%84%D8%AE%D8%A7%D8%AF%D9%88%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r4/" rel="">الإعداد الابتدائي لخادوم أوبنتو 14.04</a>»، بما في ذلك إعداد حساب مستخدم عادي لكنه يملك امتيازات الجذر (root) عبر الأداة <code>sudo</code>.<br>
	خدمة Nginx مثبّتة على خادومك باتباعك لهذا الدرس «<a href="https://academy.hsoub.com/devops/servers/web/nginx/%D8%AA%D9%86%D8%B5%D9%8A%D8%A8%D8%8C-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D9%88%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-nginx-%D9%83%D8%AE%D8%A7%D8%AF%D9%88%D9%85-%D9%88%D9%8A%D8%A8-r1/" rel="">تنصيب، إعداد واستخدام nginx كخادوم ويب</a>».<br>
	سنحتاج بالإضافة إلى وحدة header إلى وحدة map التابعة لخادوم Nginx؛ لمزيدٍ من المعلومات حول وحدة map، فاقرأ <a href="https://www.digitalocean.com/community/tutorials/how-to-use-nginx-s-map-module-on-ubuntu-16-04" rel="external nofollow">درس كيفية استخدام وحدة map على خادوم أوبنتو 16.04</a>.
</p>

<h3 id="الخطوة-الأولى-إنشاء-ملفات-للتجربة">
	الخطوة الأولى: إنشاء ملفات للتجربة
</h3>

<p>
	سنُنشِئ في هذه الخطوة عدِّة ملفات في مجلد Nginx، إذ سنستخدم هذه الملفات لاحقًا للتحقق من سلوك خادوم Nginx الافتراضي لاختبار أنَّ التخزين المؤقت في المتصفح يعمل عملًا صحيحًا.<br>
	لتقرير ما هو نوع الملفات المُخدَّمة عبر الشبكة، فلن يُحلِّل Nginx محتويات الملف لأن ذلك يستهلك وقتًا كثيرًا؛ وإنما سينظر إلى لاحقة (أو امتداد) الملف لتحديد ما هو نوع MIME التابع له، والذي سيُصرِّح عن الهدف أو الغاية من الملف.<br>
	ونتيجةً لهذا السلوك، فلن يكون لمحتوى الملفات الاختبارية أيّة أهمية؛ إذ سنستطيع خداع خادوم Nginx بتسمية الملفات تسميةً صحيحةً، فقد يظن خادوم Nginx أنَّ ملفًا فارغًا يُمثِّل صورةً وآخر يُمثِّل سكربت JavaScript.<br>
	لنُنشِئ ملفًا باسم <code>test.html</code> في مجلد Nginx الافتراضي عبر الأداة <code>truncate</code> (يمكنك استخدام أيّة أداة أو أمر آخر وليكن <code>touch</code> مثلًا). لاحقة الملف تُشير إلى أنَّه مستند HTML:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs bash"><span class="hljs-built_in">sudo</span> truncate <span class="hljs-operator">-s</span> <span class="hljs-number">1</span>k /var/www/html/test.html</code></pre>

<p>
	لنُنشِئ المزيد من الملفات الاختبارية بنفس الطريقة السابقة: صورة <code>jpg</code> وملف <code>css</code> وسكربت <code>js</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs bash"><span class="hljs-built_in">sudo</span> truncate <span class="hljs-operator">-s</span> <span class="hljs-number">1</span>k /var/www/html/test.jpg
<span class="hljs-built_in">sudo</span> truncate <span class="hljs-operator">-s</span> <span class="hljs-number">1</span>k /var/www/html/test.css
<span class="hljs-built_in">sudo</span> truncate <span class="hljs-operator">-s</span> <span class="hljs-number">1</span>k /var/www/html/test.js</code></pre>

<p>
	الخطوة التالية هي التحقق من سلوك خادوم Nginx فيما يتعلق بإرسال ترويسات للتحكم بالتخزين المؤقت للمتصفح وذلك بتخديم الملفات التي أنشأناها أخيرًا مع الضبط الافتراضي له.
</p>

<h3 id="الخطوة-الثانية-التحقق-من-السلوك-الافتراضي-لخادوم-nginx">
	الخطوة الثانية: التحقق من السلوك الافتراضي لخادوم Nginx
</h3>

<p>
	يكون لجميع الملفات نفس سلوك التخزين المؤقت افتراضيًا. ولرؤية ذلك سنستخدم ملف HTML الذي أنشأناه في الخطوة الأولى، إلا أنَّك تستطيع إجراء هذا الاختبار على أيّ ملف من الملفات التي أنشأناها سابقًا.<br>
	لنتحقق من أنَّ الملف <code>test.html</code> يُخدَّم ومعه المعلومات التي لها علاقة بالمدة الواجب تخزين المتصفح للملف فيها مؤقتًا. سيؤدي الأمر الآتي إلى طلب الملف من خادوم Nginx المحلي ويُظهِر ترويسات رد HTTP:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs lasso">curl <span class="hljs-attribute">-I</span> http:<span class="hljs-comment">//localhost/test.html</span></code></pre>

<p>
	يجب أن ترى عدِّة ترويسات HTTP:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs http"><span class="hljs-status">HTTP/1.1 <span class="hljs-number">200</span> OK</span>
<span class="hljs-attribute">Server</span>: <span class="hljs-string">nginx/1.10.0 (Ubuntu)</span>
<span class="hljs-attribute">Date</span>: <span class="hljs-string">Sat, 10 Sep 2016 13:12:26 GMT</span>
<span class="hljs-attribute">Content-Type</span>: <span class="hljs-string">text/html</span>
<span class="hljs-attribute">Content-Length</span>: <span class="hljs-string">1024</span>
<span class="hljs-attribute">Last-Modified</span>: <span class="hljs-string">Sat, 10 Sep 2016 13:11:33 GMT</span>
<span class="hljs-attribute">Connection</span>: <span class="hljs-string">keep-alive</span>
<span class="hljs-attribute">ETag</span>: <span class="hljs-string">"57d40685-400"</span>
<span class="hljs-attribute">Accept-Ranges</span>: <span class="hljs-string">bytes</span></code></pre>

<p>
	يمكنك أن تلاحظ السطر قبل الأخير الذي يبدأ بالكلمة <code>ETag</code> الذي يتضمن مُعرِّفًا فريدًا للنسخة الحالية من الملف المطلوب. فإذا حاولت تنفيذ أمر <code>curl</code> السابق أكثر من مرة فستجد نفس قيمة <code>ETag</code>.<br>
	أما عند استخدام متصفح ويب، فستُخزَّن قيمة <code>ETag</code> ثم تُرسَل إلى الخادوم عبر ترويسة <code>If-None-Match</code> عندما يريد المتصفح أن يطلب نفس الملف مرةً أخرى (عند تحديث الصفحة على سبيل المثال).<br>
	يمكنك محاكاة ذلك في سطر الأوامر بالأمر الآتي. احرص على تغيير قيمة الترويسة <code>If-None-Match</code> في الأمر لتُطابِق قيمة <code>ETag</code> في ناتج الأمر السابق:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs lasso">curl <span class="hljs-attribute">-I</span> <span class="hljs-attribute">-H</span> <span class="hljs-string">'If-None-Match: "57d40685-400"'</span> http:<span class="hljs-comment">//localhost/test.html</span></code></pre>

<p>
	ستجد أنَّ الرد أصبح مختلفًا الآن:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs http"><span class="hljs-status">HTTP/1.1 <span class="hljs-number">304</span> Not Modified</span>
<span class="hljs-attribute">Server</span>: <span class="hljs-string">nginx/1.10.0 (Ubuntu)</span>
<span class="hljs-attribute">Date</span>: <span class="hljs-string">Sat, 10 Sep 2016 13:20:31 GMT</span>
<span class="hljs-attribute">Last-Modified</span>: <span class="hljs-string">Sat, 10 Sep 2016 13:11:33 GMT</span>
<span class="hljs-attribute">Connection</span>: <span class="hljs-string">keep-alive</span>
<span class="hljs-attribute">ETag</span>: <span class="hljs-string">"57d40685-400"</span></code></pre>

<p>
	ردّ خادوم Nginx بحالة «‎304 Not Modified»، ولن يُرسِل الملف عبر الشبكة مجددًا، وإنما يخبر المتصفح أنَّه يستطيع إعادة استخدام الملف المُخزَّن محليًا والذي نزَّله سابقًا.<br>
	ما سبق مفيدٌ لأنه يُقلِّل من التراسل الشبكي، لكنه ليس مثاليًا لتحقيق أداءٍ عالٍ نتيجةٍ للتخزين المؤقت. المشكلة مع ترويسة <code>ETag</code> أنَّ المتصفح سيرسل الطلبية إلى الخادوم دائمًا ويسأله إن كان بإمكانه استخدام الملف المُخزَّن مؤقتًا، وحتى لو ردّ الخادوم على المتصفح بالإيجاب بحالة 304 بدلًا من إعادة إرسال الملف مجددًا، إلا أنَّ إرسال الطلبية واستلام الرد سيستهلك وقتًا.<br>
	سنستخدم في الخطوة التالية وحدة headers لإضافة معلومات للتحكم بالتخزين المؤقت. وهذا سيجعل المتصفح يُخزِّن الملفات محليًا دون أخذ إذن الخادوم أولًا.
</p>

<h3 id="الخطوة-الثالثة-ضبط-ترويستي-cache-control-و-expires">
	الخطوة الثالثة: ضبط ترويستَي Cache-Control و Expires
</h3>

<p>
	إضافةً إلى ترويسة التحقق من تغيّر الملف (<code>ETag</code>)، هنالك ترويستان للتحكم بالتخزين المؤقت هما <code>Cache-Control</code> و <code>Expires</code>. ترويسة <code>Cache-Control</code> هي نسخةٌ أحدث، وفيها خياراتٌ أكثر مقارنةً بترويسة <code>Expires</code> وهي أفيد إن شئت التحكم بسلوك التخزين المؤقت تحكمًا دقيقًا.<br>
	إذا ضُبِطَت تلك الترويسات، فهي تخبر المتصفح أنَّ الملف المطلوب يمكن أن يُخزَّن محليًا لفترةٍ زمنيةٍ معيّنة (تستطيع أن تجعل صلاحيته «للأبد»!) دون طلبه مرةً أخرى. أما إن لم تُضبَط تلك الترويسات، فسيطلب المتصفحُ الملفَ دومًا من الخادوم، متوقعًا أن يحصل على الحالة «‎200 OK» أو «‎304 Not Modified».<br>
	يمكننا استخدام وحدة header لإرسال ترويسات HTTP آنفة الذكر. وحدة header هي وحدةٌ من أساس خادوم Nginx لذا لن تحتاج إلى تثبيت أيّ شيءٍ لاستخدامها.<br>
	لإضافة وحدة header، افتح ملف ضبط Nginx في محرر <code>nano</code> أو أيّ محررٍ نصيٍ تشاء:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs haskell"><span class="hljs-title">sudo</span> nano /etc/nginx/sites-available/<span class="hljs-default"><span class="hljs-keyword">default</span></span></code></pre>

<p>
	اعثر على القسم المُعَنوَنَ <code>server</code>، والذي يبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs vala">. . .
<span class="hljs-preprocessor"># Default server configuration</span>
<span class="hljs-preprocessor">#</span>

server {
    listen <span class="hljs-number">80</span> default_server;
    listen [::]:<span class="hljs-number">80</span> default_server;

. . .</code></pre>

<p>
	أضف القسمَين الآتيين: أولهما قبل قسم <code>server</code> لتعريف المدة الزمنية لتخزين مختلف أنواع الملفات مؤقتًا، وثانيهما داخل كتلة <code>server</code> الذي يضبط ترويسات التخزين المؤقت ضبطًا سليمًا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs mel">. . .
# Default server configuration
#

# Expires map
map <span class="hljs-variable">$sent_http_content_type</span> <span class="hljs-variable">$expires</span> {
    <span class="hljs-keyword">default</span>                    off;
    <span class="hljs-keyword">text</span>/html                  epoch;
    <span class="hljs-keyword">text</span>/css                   <span class="hljs-keyword">max</span>;
    application/javascript     <span class="hljs-keyword">max</span>;
    ~<span class="hljs-keyword">image</span>/                    <span class="hljs-keyword">max</span>;
}

server {
    listen <span class="hljs-number">80</span> default_server;
    listen [::]:<span class="hljs-number">80</span> default_server;

    expires <span class="hljs-variable">$expires</span>;
. . .</code></pre>

<p>
	القسم الموجود قبل قسم <code>server</code> هو قسم <code>map</code> الذي يربط بين أنواع الملفات ومدة التخزين المؤقت لهذا النوع من الملفات. استعملنا عدِّة خيارات ضبط فيه:<br>
	القيمة الافتراضية هي <code>off</code>، والتي لن تُضيف أيّة ترويسات للتحكم بالتخزين المؤقت، وهذا خيارٌ جيدٌ للمحتوى الذي لا يتطلب تخزينًا مؤقتًا.<br>
	لنوع <code>text/html</code> سنضبط القيمة إلى <code>epoch</code> وهي قيمةٌ خاصةٌ التي تعني عدم التخزين المؤقت نهائيًا، مما يجبر المتصفح على السؤال إن كانت الصفحة مُحدَّثة.<br>
	لنوع <code>text/css</code> و <code>application/javascript</code> -والتي هي ملفات الأنماط CSS وسكربتات JavaScript- سنضبط القيمة إلى <code>max</code> وهذا يعني أنَّ المتصفح سيُخزِّن هذه الملفات مؤقتًا أطول مدة يستطيعها، مما يُقلِّل عدد الطلبيات لوجود عدد كبير من هذه الملفات التي ترتبط بصفحة HTML.<br>
	آخر خيار لنوع <code>‎~image/‎</code> وهو تعبيرٌ نمطيٌ (regular expression) الذي يُطابِق جميع الملفات ذات النوع الذي يحتوي على العبارة <code>image/‎</code> فيه (مثل <code>image/jpg</code> و <code>image/png</code>). وكما في ملفات CSS و JS، تتواجد عادةً صورٌ كثير في مواقع الويب، ومن الجيد تخزينها محليًا، لذا ضبطنا القيمة إلى <code>max</code> أيضًا.<br>
	التعليمة <code>expires</code> داخل قسم <code>server</code> (التي هي جزءٌ من وحدة headers) تضبط ترويسات التحكم بالتخزين المؤقت؛ حيث تستخدم القيمة المأخوذة من المتغير <code>‎$expires</code> الذي يربط بين أنواع الملفات ومدة صلاحيتها. وبهذه الطريقة ستختلف الترويسات المُرسَلة اعتمادًا على نوع الملف.<br>
	احفظ الملف واخرج من المُحرِّر النصي، وأعد تشغيل خادوم Nginx لتفعيل الضبط الجديد:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs bash"><span class="hljs-built_in">sudo</span> systemctl restart nginx</code></pre>

<p>
	سنتحقق في الخطوة التالية من أنَّ الضبط الجديد يعمل عملًا سليمًا.
</p>

<h3 id="الخطوة-الرابعة-اختبار-التخزين-المؤقت-في-المتصفح">
	الخطوة الرابعة: اختبار التخزين المؤقت في المتصفح
</h3>

<p>
	لنُنفِّذ نفس الأمر الذي طلبنا فيه ملف HTML في القسم السابق:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs lasso">curl <span class="hljs-attribute">-I</span> http:<span class="hljs-comment">//localhost/test.html</span></code></pre>

<p>
	سيكون الرد مختلفًا هذه المرة، إذ يجب أن ترى ترويستين جديدتين:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs http"><span class="hljs-status">HTTP/1.1 <span class="hljs-number">200</span> OK</span>
<span class="hljs-attribute">Server</span>: <span class="hljs-string">nginx/1.10.0 (Ubuntu)</span>
<span class="hljs-attribute">Date</span>: <span class="hljs-string">Sat, 10 Sep 2016 13:48:53 GMT</span>
<span class="hljs-attribute">Content-Type</span>: <span class="hljs-string">text/html</span>
<span class="hljs-attribute">Content-Length</span>: <span class="hljs-string">1024</span>
<span class="hljs-attribute">Last-Modified</span>: <span class="hljs-string">Sat, 10 Sep 2016 13:11:33 GMT</span>
<span class="hljs-attribute">Connection</span>: <span class="hljs-string">keep-alive</span>
<span class="hljs-attribute">ETag</span>: <span class="hljs-string">"57d40685-400"</span>
<span class="hljs-attribute">Expires</span>: <span class="hljs-string">Thu, 01 Jan 1970 00:00:01 GMT</span>
<span class="hljs-attribute">Cache-Control</span>: <span class="hljs-string">no-cache</span>
<span class="hljs-attribute">Accept-Ranges</span>: <span class="hljs-string">bytes</span></code></pre>

<p>
	ترويسة <code>Expires</code> مرتبطة بتاريخٍ في الماضي وترويسة <code>Cache-Control</code> مضبوطةٌ إلى <code>no-cache</code>، مما يجعل المتصفح يسأل الخادوم إن توفرت نسخةٌ جديدةٌ من الملف (باستخدام ترويسة <code>ETag</code> كما سبق).<br>
	ستجد ردًا مختلفًا عندما تُجرِّب على صورة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs lasso">curl <span class="hljs-attribute">-I</span> http:<span class="hljs-comment">//localhost/test.jpg</span></code></pre>

<p>
	ناتج الأمر السابق:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6413_9">
<code class="hljs http"><span class="hljs-status">HTTP/1.1 <span class="hljs-number">200</span> OK</span>
<span class="hljs-attribute">Server</span>: <span class="hljs-string">nginx/1.10.0 (Ubuntu)</span>
<span class="hljs-attribute">Date</span>: <span class="hljs-string">Sat, 10 Sep 2016 13:50:41 GMT</span>
<span class="hljs-attribute">Content-Type</span>: <span class="hljs-string">image/jpeg</span>
<span class="hljs-attribute">Content-Length</span>: <span class="hljs-string">1024</span>
<span class="hljs-attribute">Last-Modified</span>: <span class="hljs-string">Sat, 10 Sep 2016 13:11:36 GMT</span>
<span class="hljs-attribute">Connection</span>: <span class="hljs-string">keep-alive</span>
<span class="hljs-attribute">ETag</span>: <span class="hljs-string">"57d40688-400"</span>
<span class="hljs-attribute">Expires</span>: <span class="hljs-string">Thu, 31 Dec 2037 23:55:55 GMT</span>
<span class="hljs-attribute">Cache-Control</span>: <span class="hljs-string">max-age=315360000</span>
<span class="hljs-attribute">Accept-Ranges</span>: <span class="hljs-string">bytes</span></code></pre>

<p>
	ارتبطت الترويسة <code>Expires</code> في هذه المرة بتاريخٍ في المستقبل البعيد، واحتوت ترويسة <code>Cache-Control</code> على <code>max-age</code> التي تخبر المتصفح كم ثانية يجب أن يُبقي على الملف. وهذا يُخبِر المتصفح أن يُخزِّن الصورة المُنزَّلة مؤقتًا لأطول مدة ممكنة، وبالتالي إذا ظهرت الصورة مرةً أخرى فستُستعمَل النسخة المحلية ولن تُرسَل الطلبية إلى الخادوم بتاتًا.<br>
	يجب أن تكون النتيجة مشابهةً لملفَي <code>test.js</code> و <code>test.css</code> لأنهما ملفا JavaScript و CSS ويُضبَط لهما ترويسات التخزين المؤقت أيضًا، مَثَلُهُما كَمَثل الصور.<br>
	إن ظهر عندك مثلما عرضنا في أمثلتنا، فاعلم أنَّ ترويسات التحكم بالتخزين المؤقت قد ضُبِطَت ضبطًا صحيحًا وسيستفيد موقعك من ناحية الأداء، وسيقل الحِمل على خادومك نتيجةً لتخزين المتصفح للملفات محليًا وعدم طلبها من الخادوم. عليك الآن أن تُخصِّص إعدادات التخزين المؤقت اعتمادًا على محتوى موقعك، لكن قد تجد أنَّ الضبط الذي وفرناه في هذا الدرس مناسبًا لتبدأ منه.
</p>

<h3 id="الخلاصة">
	الخلاصة
</h3>

<p>
	يمكن أن تُستعمَل وحدة headers لإضافة أي نوع من الترويسات إلى رد HTTP، لكن من أفضل تطبيقات هذه الوحدة هو ضبط ترويسات التحكم بالتخزين المؤقت. إذ سيساعد ذلك في تحسين أداء مواقع الويب المُستضافة على خادومك، خصوصًا في الشبكات ذات زمن التأخير المرتفع (نسبيًا) مثل شبكات الهواتف المحمولة. يمكن أن يؤدي ذلك إلى تحسين ظهور موقعك في محركات البحث التي تأخذ عامل سرعة الموقع بالحسبان. حيث يُعتَبَر ضبط ترويسات التخزين المؤقت من أبزر نصائح أدوات اختبار سرعة الصفحات من Google (أقصد Google PageSpeed).<br>
	لمزيدٍ من المعلومات التفصيلية عن وحدة headers، فارجع إلى <a href="http://nginx.org/en/docs/http/ngx_http_headers_module.html" rel="external nofollow">توثيق Nginx الرسمي</a>.<br>
	ترجمة -وبتصرّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-implement-browser-caching-with-nginx-s-header-module-on-ubuntu-16-04" rel="external nofollow">How to Implement Browser Caching with Nginx’s header Module on Ubuntu 16.04</a> لصاحبه Mateusz Papiernik.
</p>
]]></description><guid isPermaLink="false">306</guid><pubDate>Fri, 10 Mar 2017 14:26:45 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; HAProxy &#x643;&#x645;&#x648;&#x627;&#x632;&#x646; &#x62D;&#x645;&#x644; &#x639;&#x646; &#x637;&#x631;&#x64A;&#x642; &#x627;&#x644;&#x637;&#x628;&#x642;&#x629; 7 &#x644;&#x623;&#x62C;&#x644; &#x648;&#x648;&#x631;&#x62F;&#x628;&#x631;&#x64A;&#x633; &#x648; Nginx &#x639;&#x644;&#x649; &#x623;&#x648;&#x628;&#x646;&#x62A;&#x648;</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-haproxy-%D9%83%D9%85%D9%88%D8%A7%D8%B2%D9%86-%D8%AD%D9%85%D9%84-%D8%B9%D9%86-%D8%B7%D8%B1%D9%8A%D9%82-%D8%A7%D9%84%D8%B7%D8%A8%D9%82%D8%A9-7-%D9%84%D8%A3%D8%AC%D9%84-%D9%88%D9%88%D8%B1%D8%AF%D8%A8%D8%B1%D9%8A%D8%B3-%D9%88-nginx-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-r285/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2016_10/haproxy-load-balancing.png.706ac79667470896bcfd98a851a38ce4.png" /></p>

<p>
	سنتعلّم في هذا الدّرس كيفيّة استخدام <strong>HAProxy</strong> (والذي يرمز إلى الوسيط عالي التوفّر High Availability Proxy) كمُوازِن حمل عن طريق الطبقة السّابعة layer 7 load balancer من أجل تخديم تطبيقات متعدّدة من اسم مجال واحد Single Domain أو عنوان IP، بإمكان موازنة الحمل أن تزيد أداء، توفّر، ومرونة بيئتنا.
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="19336" data-unique="809o1vyez" src="https://academy.hsoub.com/uploads/monthly_2016_10/haproxy-load-balancing.png.b02b7aa5fbd94d5d0c6592d45eabc52b.png" alt="haproxy-load-balancing.png"></p>

<p>
	تكون موازنة الحمل والوسيط العكسي للطبقة 7 ملائمة لموقعك إن أردت أن تملك اسم نطاق واحد يقوم بتخديم تطبيقات متعدّدة، حيث يمكن تحليل طلبات http لتقرّر أي تطبيق ينبغي عليه أن يستقبل حركة مرور البيانات.
</p>

<p>
	تمّت كتابة هذا الدّرس باستخدام ووردبريس وموقع ثابت Static website كأمثلة، ولكن يمكن استخدام مفاهيمه العامّة مع تطبيقات أخرى للحصول على تأثير مماثل.
</p>

<h2>
	المتطلبات الأساسية
</h2>

<p>
	قبل متابعة هذا الدّرس ينبغي عليك أن تملك تطبيقين على الأقل يعملان على خادومين منفصلين، سنستخدم موقعًا ثابتًا مستضافًا على Nginx و ووردبريس كتطبيقين لدينا،
</p>

<p>
	وبالإضافة للبيئة الحاليّة لديك سنقوم بإنشاء الخواديم التالية:
</p>

<ul>
<li>
		<span style="font-family:Courier New,Courier,monospace;">haproxy-www</span>: وهو خادوم HAProxy لأجل موازنة الحمل والوسيط العكسي
	</li>
	<li>
		<span style="font-family:Courier New,Courier,monospace;">wordpress-2</span>: وهو خادوم الويب الثاني لووردبريس (تحتاجه فقط إن أردت موازنة حمل مكونات ووردبريس في بيئتك)
	</li>
	<li>
		<span style="font-family:Courier New,Courier,monospace;">web-2</span>: خادوم ويب Nginx الثاني (تحتاجه فقط إن أردت موازنة حمل مكونات Nginx في بيئتك)
	</li>
</ul>
<p style="text-align: center;">
	<img alt="prereq.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="19334" data-unique="ol6tswcwh" src="https://academy.hsoub.com/uploads/monthly_2016_10/prereq.jpg.722bf67a6302b7ad4eb34515886ecf1d.jpg"></p>

<p>
	إن لم يسبق لك التّعامل مع المفاهيم أو المصطلحات الأساسيّة لموازنة الحمل، مثل موازنة الحمل عن طريق الطبقة 7 أو الواجهات الخلفيّة backends أو قوائم تحكّم الوصول ACLs فهذا هو الدّرس الذي يشرح الأساسيّات: مقدّمة إلى HAProxy ومبادئ موازنة الحمل (Load Balancing).
</p>

<h2>
	هدفنا
</h2>

<p>
	بنهاية هذا الدّرس نريد أن نحصل على بيئة تبدو كما يلي:
</p>

<p style="text-align: center;">
	<img alt="layer_7_load_balancing-goal.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="19333" data-unique="2zwdy4lu3" src="https://academy.hsoub.com/uploads/monthly_2016_10/layer_7_load_balancing-goal.jpg.dd96ee336598d37193445e8150928884.jpg"></p>

<p>
	أي سيقوم المستخدمون لديك بالنفاذ لكلا تطبيقيك عبر <a href="http://example.xn--com-nwe" ipsnoembed="false" rel="external nofollow">http://example.com،</a> وسيتم تمرير كل الطلبات التي تبدأ بـ <a href="http://example.com/wordpress" ipsnoembed="false" rel="external nofollow">http://example.com/wordpress</a> إلى خواديم ووردبريس، ويتم تمرير جميع باقي الطلبات إلى خواديم Nginx الأساسيّة، لاحظ أنّه لا تحتاج بالضرورة لموازنة حمل تطبيقاتك حتى تظهر على مجال واحد، ولكن سنقوم بتغطية موازنة الحمل في هذا الدّرس.
</p>

<h2>
	تثبيت HAProxy
</h2>

<p>
	نقوم بإنشاء خادوم جديد مع الشّبكات الخاصّة، سنسمّيه في هذا الدّرس<span style="font-family:Courier New,Courier,monospace;"> haproxy-www</span>.
</p>

<p>
	نقوم بتثبيت HAProxy على الخادوم <span style="font-family:Courier New,Courier,monospace;">haproxy-www</span> باستخدام<span style="font-family:Courier New,Courier,monospace;"> apt-get</span>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_7">
<span class="pln">sudo apt-get update
sudo apt-get install haproxy</span></pre>

<p>
	نحتاج لتمكين سكريبت التهيئة init script لـ HAProxy كي يبدأ ويتوقف HAProxy مع الخادوم لدينا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_10">
<span class="pln">sudo vi /etc/default/haproxy</span></pre>

<p>
	نغيّر قيمة <span style="font-family:Courier New,Courier,monospace;">ENABLED</span> إلى 1 لتمكين سكريبت التهيئة لـ HAProxy:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_12">
<span class="pln">ENABLED=1</span></pre>

<p>
	نقوم بالحفظ والخروج، سيبدأ ويتوقف HAProxy الآن مع خادومنا، نستطيع أيضًا الآن استخدام الأمر <span style="font-family:Courier New,Courier,monospace;">service</span> للتحكّم بـ HAProxy، فلنتحقّق من أنّه قيد التشغيل:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_14">
<span class="pln">user@haproxy-www:/etc/init.d$ sudo service haproxy status
haproxy not running.</span></pre>

<p>
	نجد أنّه لا يعمل، لا مشكلة لأنّه يحتاج إلى إعداده قبل أن نتمكّن من استخدامه، فلنقم الآن بإعداد HAProxy لأجل بيئتنا.
</p>

<h2>
	إعداد HAProxy
</h2>

<p>
	يكون ملف إعدادات HAProxy مُقسّمًا إلى قسمين رئيسيين:
</p>

<ul>
<li>
		<strong>العمومي Global</strong>: يقوم بتعيين المُعامِلات parameters على نطاق العمليّة
	</li>
	<li>
		<strong>الوسطاء Proxies</strong>: يتكون من المُعامِلات الافتراضيّة defaults، الاستماع listen، الواجهة الأماميّة frontend، والواجهة الخلفيّة backend.
	</li>
</ul>
<p>
	مرّة أخرى إن لم يسبق لك أن سمعت عن مفاهيم أو المصطلحات الأساسيّة لموازنة الحمل، فقم بالرجوع إلى هذا الدّرس: <a href="https://academy.hsoub.com/devops/servers/%D9%85%D9%82%D8%AF%D9%91%D9%85%D8%A9-%D8%A5%D9%84%D9%89-haproxy-%D9%88%D9%85%D8%A8%D8%A7%D8%AF%D8%A6-%D9%85%D9%88%D8%A7%D8%B2%D9%86%D8%A9-%D8%A7%D9%84%D8%AD%D9%85%D9%84-load-balancing-r41/" rel="">مقدّمة إلى HAProxy ومبادئ موازنة الحمل (Load Balancing)</a>.
</p>

<h3>
	إعداد HAProxy: العمومي
</h3>

<p>
	يجب أن يتم ضبط إعدادات HAProxy على الخادوم<span style="font-family:Courier New,Courier,monospace;"> haproxy-www</span>.
</p>

<p>
	في البداية لنقم بعمل نسخة من الملف<span style="font-family:Courier New,Courier,monospace;"> haproxy.cfg</span> الافتراضي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_17">
<span class="pln">cd /etc/haproxy; sudo cp haproxy.cfg haproxy.cfg.orig</span></pre>

<p>
	نقوم الآن بفتح الملف<span style="font-family:Courier New,Courier,monospace;"> haproxy.cfg</span> باستخدام مُحرِّر نصوص:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_19">
<span class="pln">sudo vi /etc/haproxy/haproxy.cfg</span></pre>

<p>
	سنشاهد وجود قسمين معرّفين مسبقًا: <span style="font-family:Courier New,Courier,monospace;">global</span> و <span style="font-family:Courier New,Courier,monospace;">defaults</span>، سنلقي نظرة في البداية على بعض المعاملات القياسية <span style="font-family:Courier New,Courier,monospace;">default</span>.
</p>

<p>
	تحت القسم <span style="font-family:Courier New,Courier,monospace;">defaults</span> نبحث عن الأسطر التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_21">
<span class="pln">mode http
option httplog</span></pre>

<p>
	يقوم اختيار <span style="font-family:Courier New,Courier,monospace;">http</span> كوضع بضبط HAProxy ليعمل كموازن حمل عن طريق الطبقة 7 (أو طبقة التطبيقات)، يعني هذا أنّ موازن الحمل سينظر إلى محتوى طلبات http ويقوم بتمريرها إلى الخادوم المناسب اعتمادًا على القواعد المعرّفة في الواجهة الأماميّة frontend، إن لم يكن هذا المفهوم مألوفًا لديك فمن فضلك اقرأ <a href="https://academy.hsoub.com/devops/servers/%D9%85%D9%82%D8%AF%D9%91%D9%85%D8%A9-%D8%A5%D9%84%D9%89-haproxy-%D9%88%D9%85%D8%A8%D8%A7%D8%AF%D8%A6-%D9%85%D9%88%D8%A7%D8%B2%D9%86%D8%A9-%D8%A7%D9%84%D8%AD%D9%85%D9%84-load-balancing-r41/" rel="">قسم أنواع موازنة الحمل في درس مقدّمة إلى HAProxy</a>.
</p>

<p>
	لا تقم بإغلاق ملف الإعدادات الآن، لأنّنا سنضيف إعدادات الوسيط.
</p>

<h3>
	إعداد HAProxy: الوسطاء
</h3>

<h3>
	إعداد الواجهة الأماميّة
</h3>

<p>
	أول شيء نريد إضافته هو واجهة أماميّة frontend، ولأجل إعداد أساسي لوسيط عكسي وموازنة حمل عن طريق الطبقة 7 سنحتاج لتعريف قائمة تحكّم وصول ACL تُستخدَم لتوجيه حركة مرور بياناتنا إلى خواديم الواجهة الخلفيّة المناسبة، هنالك العديد من قوائم تحكّم الوصول التي يُمكن استخدامها في HAProxy، سنغطي فقط واحدة منها في هذا الدّرس (وهي path_beg)، ولأجل الحصول على قائمة كاملة من قوائم تحكّم الوصول في HAProxy قم بمراجعة التّوثيق الرسميّ: <a href="http://cbonte.github.io/haproxy-dconv/configuration-1.4.html#7.5.3" rel="external nofollow">HAProxy ACLs</a>.
</p>

<p>
	نضيف واجهتنا الأماميّة <span style="font-family:Courier New,Courier,monospace;">www</span> في نهاية الملف، تأكّد من أن تضع عنوان IP الخاص بخادوم <span style="font-family:Courier New,Courier,monospace;">haproxy-www</span> لديك بدلًا من <span style="font-family:Courier New,Courier,monospace;">haproxy_www_public_IP</span>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_26">
<span class="pln">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</span></pre>

<p>
	وهذا شرح لما يعنيه كل سطر من المقطع السابق المأخوذ من إعدادات الواجهة الأماميّة:
</p>

<ul>
<li>
		<strong><span style="font-family:Courier New,Courier,monospace;">frontend www</span></strong>: يُعيِّن واجهة أماميّة اسمها "www"، حيث سنستخدمها للتعامل مع حركة مرور بيانات www الواردة.
	</li>
	<li>
		<strong><span style="font-family:Courier New,Courier,monospace;">bind haproxy_www_public_IP:80</span></strong>: ضع عنوان IP خادوم<span style="font-family:Courier New,Courier,monospace;"> haproxy-www</span> لديك بدلًا من <span style="font-family:Courier New,Courier,monospace;">haproxy_www_public_IP</span>، يُخبر هذا السطر HAProxy أنّ هذه الواجهة الأماميّة ستتعامل مع حركة مرور بيانات الشبكة الواردة إلى عنوان IP هذا على هذا المنفذ.
	</li>
	<li>
		<strong><span style="font-family:Courier New,Courier,monospace;">option http-server-close</span></strong>: يقوم بتمكين وضع إغلاق اتصال HTTP على الخادوم، ويحافظ على القدرة على دعم ترويسة <span style="font-family:Courier New,Courier,monospace;">HTTP keep-alive</span> وتقنيّة HTTP pipelining على العميل (وهي تقنيّة لإرسال العديد من طلبات HTTP ضمن اتصال TCP وحيد بدون انتظار الموافقة لها)، يسمح هذا الخيار بأن يقوم HAProxy بمعالجة طلبات متعدّدة للعميل ضمن اتصال وحيد، والذي عادة ما يزيد من الأداء.
	</li>
	<li>
		<strong><span style="font-family:Courier New,Courier,monospace;">acl url_wordpress path_beg /wordpress</span></strong>: يُعيِّن قائمة تحكّم وصول ACL تُدعى <span style="font-family:Courier New,Courier,monospace;">url_wordpress</span> والتي تكون قيمتها صحيحة <span style="font-family:Courier New,Courier,monospace;">true</span> إن كان مسار الطلب يبدأ بـ "<span style="font-family:Courier New,Courier,monospace;">wordpress/</span>"، على سبيل المثال <a href="http://example.com/wordpress/hello-world." ipsnoembed="false" rel="external nofollow">http://example.com/wordpress/hello-world.</a>
	</li>
	<li>
		<strong><span style="font-family:Courier New,Courier,monospace;">use_backend wordpress-backend if url_wordpress</span></strong>: يقوم بإعادة توجيه أي حركة مرور بيانات تتوافق مع قائمة تحكّم الوصول <span style="font-family:Courier New,Courier,monospace;">url_wordpress</span> إلى<span style="font-family:Courier New,Courier,monospace;"> wordpress-backend</span>، والتي سنقوم بتعريفها قريبًا.
	</li>
	<li>
		<strong><span style="font-family:Courier New,Courier,monospace;">default_backend web-backend</span></strong>: يُحدِّد أنّه أي حركة مرور بيانات لا تتوافق مع قاعدة <span style="font-family:Courier New,Courier,monospace;">use_backend</span> سيتم تمريرها إلى <span style="font-family:Courier New,Courier,monospace;">web-backend</span>، والتي سنقوم بتعريفها في الخطوة القادمة.
	</li>
</ul>
<h3>
	إعداد الواجهة الخلفية Backend
</h3>

<p>
	بعد أن تنتهي من إعداد الواجهة الأماميّة، قم الآن إضافة واجهتك الخلفيّة الأولى عن طريق إضافة الأسطر التالية، تأكّد من أن تضع عنوان IP المناسب بدلًا من <span style="font-family:Courier New,Courier,monospace;">web_1_private_IP</span>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_58">
<span class="pln">backend web-backend
server web-1 web_1_private_IP:80 check</span></pre>

<p>
	وهذا شرح لما يعنيه كل سطر من المقطع السابق المأخوذ من إعدادات الواجهة الخلفيّة:
</p>

<ul>
<li>
		<span style="font-family:Courier New,Courier,monospace;"><strong>backend web-backend</strong></span>: يُعيِّن واجهة خلفيّة تُدعى <span style="font-family:Courier New,Courier,monospace;">web-backend</span>.
	</li>
	<li>
		<span style="font-family:Courier New,Courier,monospace;"><strong>server web-1 ...</strong></span> : يُعيِّن خادوم واجهة خلفيّة يُدعى <span style="font-family:Courier New,Courier,monospace;">web-1</span>، مع عنوان IP الخاص (وهو الذي يجب أن تستبدله) والمنفذ الذي يستمع عليه، وهو 80 في هذه الحالة، يُخبِر الخيار <span style="font-family:Courier New,Courier,monospace;">check</span> مُوازِن الحمل أن يُجري دوريًّا تحقّق من السّلامة على هذا الخادوم.
	</li>
</ul>
<p>
	بعدها أضف الواجهة الخلفيّة لتطبيق ووردبريس لديك:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_60">
<span class="pln">backend wordpress-backend
reqrep ^([^\ :]*)\ /wordpress/(.*) \1\ /\2
server wordpress-1 wordpress_1_private_IP:80 check</span></pre>

<p>
	وهذا شرح لما يعنيه كل سطر من المقطع السابق المأخوذ من إعدادات الواجهة الخلفيّة:
</p>

<ul>
<li>
		<span style="font-family:Courier New,Courier,monospace;"><strong>backend wordpress-backend</strong></span>: يُعيِّن واجهة خلفيّة تُدعى <span style="font-family:Courier New,Courier,monospace;">wordpress-backend</span>.
	</li>
	<li>
		<span style="font-family:Courier New,Courier,monospace;"><strong>reqrep ...</strong></span> : يعيد كتابة الطلبات من <span style="font-family:Courier New,Courier,monospace;">wordpress/ </span>إلى / عند تمرير حركة مرور البيانات إلى خواديم ووردبريس، وهو ليس ضروريًّا إن كان تطبيق ووردبريس مُثبّتًا على جذر root الخادوم ولكن نحتاج إليه لقابلية النفاذ عبر <span style="font-family:Courier New,Courier,monospace;">wordpress/</span> على خادوم HAProxy.
	</li>
	<li>
		<span style="font-family:Courier New,Courier,monospace;"><strong>server wordpress-1 ... </strong></span>: يُعيِّن خادوم واجهة خلفيّة يُدعى<span style="font-family:Courier New,Courier,monospace;"> wordpress-1</span>، مع عنوان IP الخاص (وهو الذي يجب أن تستبدله) والمنفذ الذي يستمع عليه، وهو 80 في هذه الحالة، يُخبِر الخيار <span style="font-family:Courier New,Courier,monospace;">check</span> مُوازِن الحمل أن يُجري دوريًّا تحقّق من السّلامة على هذا الخادوم.
	</li>
</ul>
<h3>
	إعدادات HAProxy: الإحصائيات Stats
</h3>

<p>
	إن أردت تمكين إحصائيّات HAProxy، والتي قد تكون مفيدة في تحديد كيفيّة تعامل HAProxy مع حركة مرور البيانات الواردة، ستحتاج إلى إضافة الأسطر التالية إلى إعداداتك:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_62">
<span class="pln">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</span></pre>

<p>
	وهذا شرح لما تعنيه الأسطر غير البديهيّة من المقطع السابق المأخوذ من إعدادات <span style="font-family:Courier New,Courier,monospace;">listen stats</span>:
</p>

<ul>
<li>
		<span style="font-family:Courier New,Courier,monospace;"><strong>listen stats :1936</strong></span>: يقوم بإعداد صفحة إحصائيّات HAProxy لتكون قابلة للنفاذ على المنفذ 1936 (أي http://haproxy_www_public_IP:1936).
	</li>
	<li>
		<span style="font-family:Courier New,Courier,monospace;"><strong>stats scope ... </strong></span>: يجمع الإحصائيّات على الواجهة المُحدّدة سواء كانت أماميّة أو خلفيّة.
	</li>
	<li>
		<span style="font-family:Courier New,Courier,monospace;"><strong> / stats uri</strong></span>: يُعيِّن رابط صفحة الإحصائيّات إلى / .
	</li>
	<li>
		<span style="font-family:Courier New,Courier,monospace;"><strong>stats realm Haproxy\ Statistics</strong></span>: يقوم بتمكين الإحصائيّات وتعيين اسم الاستيثاق realm Authentication (وهو استيثاق ذو نافذة منبثقة)، يُستخدَم بالترابط مع الخيار <span style="font-family:Courier New,Courier,monospace;">stats auth</span>.
	</li>
	<li>
		<span style="font-family:Courier New,Courier,monospace;"><strong>stats auth haproxy:password</strong></span>: يُعيِّن اعتمادات credentials الاستيثاق لصفحة الإحصائيّات، قم بوضع اسم المستخدم وكلمة السّر الخاصّة بك.
	</li>
</ul>
<p>
	الآن قم بالحفظ والإغلاق، عند تشغيل HAProxy تكون صفحة الإحصائيّات متوفّرة عبر الرابط http://haproxy_www_public_ip:1936/ حالما تبدأ خدمة HAProxy لديك، تكون HAProxy جاهزة الآن لتشغيلها ولكن فلنقم بتمكين التسجيل logging أولًا.
</p>

<h2>
	تمكين تسجيل HAProxy
</h2>

<p>
	إنّ تمكين التسجيل في HAProxy بسيط جدًّا، قم في البداية بتحرير الملف<span style="font-family:Courier New,Courier,monospace;"> rsyslog.conf</span>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_56">
<span class="pln">sudo vi /etc/rsyslog.conf</span></pre>

<p>
	ثم ابحث عن السطرين التاليين وأزل التعليق عنهما لتمكين استقبال UDP syslog، يجب أن تبدو كما يلي عند الفراغ منها:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_54">
<span class="pln">$ModLoad imudp
$UDPServerRun 514
$UDPServerAddress 127.0.0.1</span></pre>

<p>
	الآن أعد تشغيل <span style="font-family:Courier New,Courier,monospace;">rsyslog</span> لتمكين الإعدادات الجديدة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_52">
<span class="pln">sudo service rsyslog restart</span></pre>

<p>
	تم تمكين تسجيل HAProxy الآن، سيتم إنشاء ملف السّجل في المسار <span style="font-family:Courier New,Courier,monospace;">var/log/haproxy.log/</span> بعد أن يتم تشغيل HAProxy.
</p>

<h2>
	تحديث إعدادات ووردبريس
</h2>

<p>
	الآن وقد تم تغيير رابط تطبيق ووردبريس فيجب علينا تحديث بعض الإعدادات في ووردبريس.
</p>

<p>
	قم بتعديل الملف <span style="font-family:Courier New,Courier,monospace;">wp-config.php</span> على أي خادوم ووردبريس، هذا الملف موجود في مكان تثبيت ووردبريس (في هذا الدّرس تم تثبيته على المسار <span style="font-family:Courier New,Courier,monospace;">var/www/example.com/</span> ولكن قد يكون مختلفًا لديك):
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_50">
<span class="pln">cd /var/www/example.com; sudo vi wp-config.php</span></pre>

<p>
	ابحث عن السطر الموجود في بداية الملف الذي يحتوي على <span style="font-family:Courier New,Courier,monospace;">('define('DB_NAME', 'wordpress </span>وقم بإضافة الأسطر التالية فوقه مع استبدال <span style="font-family:Courier New,Courier,monospace;">http://haproxy_www_public_IP</span>:
</p>

<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_7627_48">
<span class="pln">define</span><span class="pun">(</span><span class="str">'WP_SITEURL'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'http://haproxy_www_public_IP'</span><span class="pun">);</span><span class="pln">
define</span><span class="pun">(</span><span class="str">'WP_HOME'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'http://haproxy_www_public_IP'</span><span class="pun">);</span></pre>

<p>
	قم بحفظ وإغلاق الملف، تمّ الآن إعداد روابط ووردبريس لتشير إلى موازن الحمل بدلًا من خادوم ووردبريس الأصلي والتي تلعب دورها عند محاولتك النفاذ إلى لوحة تحكم ووردبريس.
</p>

<h2>
	تشغيل HAProxy
</h2>

<p>
	قم بتشغيل HAProxy على الخادوم <span style="font-family:Courier New,Courier,monospace;">haproxy-www</span> ليتم تطبيق تغييرات الإعدادات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_46">
<span class="pln">sudo service haproxy restart</span></pre>

<h2>
	إتمام الوسيط العكسي Reverse Proxy
</h2>

<p>
	أصبحت الآن تطبيقاتنا قابلة للوصول إليها عبر نفس المجال، example.com، عبر الوسيط العكسي للطبقة 7، ولكن لم يتم تطبيق موازنة الحمل عليها بعد، تبدو الآن البيئة لدينا كالمخطط التالي:
</p>

<p style="text-align: center;">
	<img alt="layer_7_proxy_no_lb.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="19335" data-unique="jfokrr5ol" src="https://academy.hsoub.com/uploads/monthly_2016_10/layer_7_proxy_no_lb.jpg.01929fdd162cc559a2e3ebb340b52d52.jpg"></p>

<p>
	وفقًا للواجهة الأماميّة التي عرفناها سابقًا، هذا وصف حول كيفيّة تمرير HAProxy لحركة مرور البيانات:
</p>

<ul>
<li>
		<a href="http://example.com/wordpress:" ipsnoembed="false" rel="external nofollow">http://example.com/wordpress:</a> سيتم إرسال أي طلب يبدأ بـ wordpress/ إلى<span style="font-family:Courier New,Courier,monospace;"> wordpress-backend</span> (والذي يتكون من الخادوم <span style="font-family:Courier New,Courier,monospace;">wordpress-1</span>).
	</li>
	<li>
		<a href="http://example.com/:" ipsnoembed="false" rel="external nofollow">http://example.com/:</a> سيتم إرسال أيّة طلبات أخرى إلى<span style="font-family:Courier New,Courier,monospace;"> web-backend </span>(والذي يتكون من الخادوم <span style="font-family:Courier New,Courier,monospace;">web-1</span>).
	</li>
</ul>
<p>
	إن كان كل ما تريد فعله هو استضافة تطبيقات متعدّدة على مجال وحيد فقد أنجزت هذا بنجاح، أمّا إن أردت موازنة حمل تطبيقاتك أكمل قراءة الدّرس.
</p>

<h2>
	كيفية إضافة موازنة الحمل
</h2>

<h3>
	موازنة حمل الخادوم web-1
</h3>

<p>
	لموازنة حمل خادوم ويب أساسي، كل ما تحتاج إليه هو إنشاء خادوم ويب جديد يمتلك إعدادات ومحتوى مطابق لخادوم الأصلي، سندعو هذا الخادوم الجديد:<span style="font-family:Courier New,Courier,monospace;"> web-2</span>.
</p>

<p>
	لديك خياران عند إنشاء الخادوم الجديد:
</p>

<ol>
<li>
		إن كنت تملك خيار إنشاء خادوم جديد انطلاقًا من صورة <span style="font-family:Courier New,Courier,monospace;">web-1</span>، فهذه هي الطريقة الأبسط لإنشاء <span style="font-family:Courier New,Courier,monospace;">web-2</span>.
	</li>
	<li>
		إنشاؤه من الصفر، تثبيت نفس البرمجيّات، إعداده بشكل مماثل، ومن ثمّ نسخ محتوى جذر خادوم Nginx من <span style="font-family:Courier New,Courier,monospace;">web-1</span> إلى <span style="font-family:Courier New,Courier,monospace;">web-2</span> باستخدام <span style="font-family:Courier New,Courier,monospace;">rsync</span> (اقرأ درس <a href="https://academy.hsoub.com/devops/linux/%D9%83%D9%8A%D9%81-%D8%AA%D8%B3%D8%AA%D8%AE%D8%AF%D9%90%D9%85-rsync-%D9%84%D9%85%D8%B2%D8%A7%D9%85%D9%86%D8%A9-%D9%85%D8%AC%D9%84%D9%91%D8%AF%D8%A7%D8%AA-%D8%A8%D9%8A%D9%86-%D8%A7%D9%84%D8%AC%D9%87%D8%A7%D8%B2-%D8%A7%D9%84%D9%85%D8%AD%D9%84%D9%91%D9%8A-%D9%88%D8%A7%D9%84%D8%AE%D8%A7%D8%AF%D9%88%D9%85-r50/" rel="">كيف تستخدِم Rsync لمزامنة مجلّدات بين الجهاز المحلّي والخادوم</a>).
	</li>
</ol>
<p>
	<strong>ملاحظة</strong>: إن كل من الطريقتين السابقتين تقوم بإنشاء نسخة لمحتويات جذر الخادوم مرّة وحيدة، لذلك إن قمت بتحديث أي من الملفّات على أحد خواديمك، <span style="font-family:Courier New,Courier,monospace;">web-1</span> أو <span style="font-family:Courier New,Courier,monospace;">web-2</span>، فتأكّد من مزامنة الملفّات مرّة أخرى.
</p>

<p>
	بعد أن يتم إعداد خادوم ويب المماثل لديك، قم بإضافته إلى<span style="font-family:Courier New,Courier,monospace;"> web-backend</span> ضمن إعدادات HAProxy.
</p>

<p>
	على الخادوم <span style="font-family:Courier New,Courier,monospace;">haproxy-www </span>قم بتحرير الملف <span style="font-family:Courier New,Courier,monospace;">haproxy.cfg</span>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_43">
<span class="pln">sudo vi /etc/haproxy/haproxy.cfg</span></pre>

<p>
	ابحث عن القسم<span style="font-family:Courier New,Courier,monospace;"> web-backend </span>من الإعدادات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_41">
<span class="pln">backend web-backend
server web-1 web_1_private_IP:80 check</span></pre>

<p>
	وبعدها أضف الخادوم <span style="font-family:Courier New,Courier,monospace;">web-2 </span>في السطر التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_39">
<span class="pln">server web-2 web_2_private_IP:80 check</span></pre>

<p>
	قم بحفظ وإغلاق الملف، وأعد تحميل HAProxy لتطبيق التغييرات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_37">
<span class="pln">sudo service haproxy reload</span></pre>

<p>
	يمتلك <span style="font-family:Courier New,Courier,monospace;">web-backend </span>الآن خادومين يتعاملان مع حركة مرور البيانات غير المرتبطة بووردبريس، أي تمّ إعداد موازنة الحمل عليه بنجاح.
</p>

<h3>
	موازنة حمل الخادوم wordpress-1
</h3>

<p>
	إنّ موازنة حمل تطبيق مثل ووردبريس أكثر تعقيدًا بقليل من موازنة حمل خادوم ثابت، لأنّه يجب عليك الاهتمام بأشياء مثل مزامنة الملفّات المُحمّلة ومستخدمي قواعد البيانات الإضافيّين.
</p>

<p>
	أكمل الخطوات الثلاث التالية لإنشاء خادوم ووردبريس الثاني <span style="font-family:Courier New,Courier,monospace;">wordpress-2</span>:
</p>

<ol>
<li>
		إنشاء خادوم تطبيق ويب الثاني.
	</li>
	<li>
		مزامنة ملفّات تطبيق الويب.
	</li>
	<li>
		إنشاء مستخدم قاعدة بيانات جديد.
	</li>
</ol>
<p>
	بعد أن تقوم بإنشاء الخادوم <span style="font-family:Courier New,Courier,monospace;">wordpress-2</span> مع إعداد قاعدة البيانات بشكل صحيح فكل ما تبقى عليك فعله هو إضافته إلى<span style="font-family:Courier New,Courier,monospace;"> wordpress-backend</span> ضمن إعدادات HAProxy.
</p>

<p>
	على الخادوم<span style="font-family:Courier New,Courier,monospace;"> haproxy-www</span> قم بتحرير الملف <span style="font-family:Courier New,Courier,monospace;">haproxy.cfg</span>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_35">
<span class="pln">sudo vi /etc/haproxy/haproxy.cfg</span></pre>

<p>
	ابحث عن القسم <span style="font-family:Courier New,Courier,monospace;">wordpress-backend </span>من الإعدادات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_33">
<span class="pln">backend wordpress-backend
server wordpress-1 wordpress_1_private_IP:80 check</span></pre>

<p>
	وبعدها أضف الخادوم <span style="font-family:Courier New,Courier,monospace;">wordpress-2</span> في السطر التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_31">
<span class="pln">server wordpress-2 wordpress_2_private_IP:80 check</span></pre>

<p>
	قم بحفظ وإغلاق الملف، وأعد تحميل HAProxy لتطبيق التغييرات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_7627_29">
<span class="pln">sudo service haproxy reload</span></pre>

<p>
	يمتلك<span style="font-family:Courier New,Courier,monospace;"> web-backend</span> الآن خادومين يتعاملان مع حركة مرور البيانات غير المرتبطة بووردبريس، أي تمّ إعداد موازنة الحمل عليه بنجاح.
</p>

<h2>
	الخاتمة
</h2>

<p>
	بعد أن أتممت الآن هذا الدّرس يجب أن تكون قادرًا على توسيع موازنة الحمل والوسيط العكسي لإضافة المزيد من التطبيقات والخواديم لبيئتك لجعلها تتوافق بشكل أفضل مع احتياجاتك، تذكّر أنّه لا توجد حدود لطرق إعداد بيئتك، وربّما تحتاج إلى البحث في توثيق HAProxy إن أردت متطلبات أكثر تعقيدًا.
</p>

<p>
	ترجمة -وبتصرّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-choose-an-effective-backup-strategy-for-your-vps" rel="external nofollow">How To Use HAProxy As A Layer 7 Load Balancer For WordPress and Nginx On Ubuntu 14.04</a> لصاحبه Mitchell Anicas.
</p>
]]></description><guid isPermaLink="false">285</guid><pubDate>Sun, 09 Oct 2016 14:33:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x62A;&#x62B;&#x628;&#x64A;&#x62A; &#x648;&#x625;&#x639;&#x62F;&#x627;&#x62F; Nginx &#x645;&#x639; &#x62F;&#x639;&#x645; HTTP/2 &#x639;&#x644;&#x649; &#x646;&#x638;&#x627;&#x645; &#x623;&#x648;&#x628;&#x646;&#x62A;&#x648; 14.04</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%88%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-nginx-%D9%85%D8%B9-%D8%AF%D8%B9%D9%85-http2-%D8%B9%D9%84%D9%89-%D9%86%D8%B8%D8%A7%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r261/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2016_05/nginx-http2.png.68c36cbce0632d834b7b4b35e7789a25.png" /></p>

<p>
	يُعدّ Nginx خادوم ويب مفتوح المصدر يتسّم بالسرعة والاعتمادية، كسب شعبيّته نتيجة حجم الذاكرة القليل الذي يستهلكه، وقابليته الكبيرة للتوسعة، وسهولة إعداده، ودعمه لمعظم البروتوكولات المختلفة.
</p>

<p>
	ويعتبر بروتوكول HTTP/2 الجديد نسبيًا أحد البروتوكولات التي يدعمها خادوم Nginx، الأمر الذي تم منذ أقل من عام مضى، وتعتبر الميّزة الرئيسية في HTTP/2 هي سرعة نقله العالية للمحتويات الغنيّة بالمعلومات في مواقع الويب.
</p>

<p>
	سيساعد المقال على تثبيت وإعداد خادوم Nginx سريع وآمن مع دعم لبروتوكول HTTP/2.
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="17015" data-unique="s485z2p2j" src="https://academy.hsoub.com/uploads/monthly_2016_05/nginx-http2.png.c933b327ac9f3e38ac802f58f377ee41.png" alt="nginx-http2.png"></p>

<h2>
	المتطلبات الأولية
</h2>

<p>
	قبل أن نبدأ، سنحتاج للأمور التالية:
</p>

<ul>
<li>
		نظام تشغيل Ubuntu 14.04،
	</li>
	<li>
		مستخدم عادي بدون صلاحيات مدير نظام، لكنّه يملك صلاحية تنفيذ أمر sudo. يمكن مراجعة <a href="https://academy.hsoub.com/devops/servers/%D8%A7%D9%84%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A7%D9%84%D8%A7%D8%A8%D8%AA%D8%AF%D8%A7%D8%A6%D9%8A-%D9%84%D8%AE%D8%A7%D8%AF%D9%88%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r4/PB2xwrGrXyTZQcvybxcxw" rel="">الإعداد الابتدائي لخادوم أوبونتو 14.04</a> لمزيد من المعلومات،
	</li>
	<li>
		نطاق موقع، ويمكن شراء واحد من موقع <a href="https://namecheap.com/" rel="external nofollow">Namecheap</a> أو الحصول على واحد مجانًا من موقع <a href="http://www.freenom.com/en/index.html" rel="external nofollow">Freenom</a>،
	</li>
	<li>
		تأكّد من أنّ النطاق يشير إلى عنوان نظام التشغيل الذي ستستخدمه عبر الإنترنت، وستساعدك مقالة <a href="https://academy.hsoub.com/devops/servers/%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A7%D8%B3%D9%85-%D9%85%D8%B6%D9%8A%D9%81-%D9%85%D8%B9-digitalocean-r175/" rel="">إعداد اسم مضيف مع DigitalOcean</a> إن احتجت لمساعدة،
	</li>
	<li>
		شهادة <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr></abbr> رقميّة، ويمكن <a href="https://academy.hsoub.com/devops/web-servers/nginx/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%B4%D9%87%D8%A7%D8%AF%D8%A9-ssl-%D9%84%D8%AE%D8%A7%D8%AF%D9%88%D9%85-nginx-%D8%B9%D9%84%D9%89-ubuntu-1404-r105/" rel="">إنشاء واحدة بشكل يدوي</a>، أو <a href="https://academy.hsoub.com/devops/servers/%D8%AA%D9%86%D8%B5%D9%8A%D8%A8-%D8%B4%D9%87%D8%A7%D8%AF%D8%A9-ssl-%D9%85%D8%AC%D8%A7%D9%86%D9%8A%D8%A9-%D8%B9%D8%A8%D8%B1-%D8%AE%D8%AF%D9%85%D8%A9-lets-encrypt-%D8%B9%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%88%D9%85-%D9%84%D9%8A%D9%86%D9%83%D8%B3-r151/" rel="">الحصول على واحدة مجانًا من Let’s Encrypt</a>، أو <a href="https://academy.hsoub.com/devops/servers/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%B4%D9%87%D8%A7%D8%AF%D8%A9-ssl-%D9%85%D9%86-%D8%B3%D9%84%D8%B7%D8%A9-%D8%B4%D9%87%D8%A7%D8%AF%D8%A7%D8%AA-%D8%AA%D8%AC%D8%A7%D8%B1%D9%8A%D8%A9-%D8%A7%D9%84%D8%AD%D8%B5%D9%88%D9%84-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%B4%D9%87%D8%A7%D8%AF%D8%A9-%D9%88%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA%D9%87%D8%A7-r148/" rel="">شراء واحدة من مزوّد آخر</a>.
	</li>
</ul>
<p>
	هذا كل شيء، فإن كانت لديك جميع المتطلبات المذكورة، فأنت جاهز للبدء.
</p>

<h2>
	الفرق ما بين HTTP 1.1 و HTTP/2
</h2>

<p>
	إن HTTP/2 هو الإصدار الجديد من بروتوكول نقل النصوص الفائقة HTTP، الذي يستخدم على الشبكة العنكبوتية لإيصال محتويات صفحات الويب من الخوادم إلى المتصفّحات، وهو أول تحديث ضخم طرأ على HTTPمنذ حوالي عقدين، حيث تم إطلاق الإصدار HTTP 1.1 عام 1999 حينما كانت الصفحات عبارة عن ملف HTML مستقل مع أنماط CSS ضمنيّة (أي مكتوبة ضمن مستند HTML وليست مستوردة من ملف خارجي).
</p>

<p>
	لقد تغيّرت شبكة الإنترنت بشكل متسارع في السنوات الستة عشر الأخيرة، وأصبحنا الآن نواجه صعوبة مع المحدودية التي يفرضها HTTP 1.1، حيث يَحُدّ البروتوكول من سرعة النقل الممكنة لمعظم مواقع الويب الحديثة لأنه يقوم بتحميل أجزاء الصفحة وفق مبدأ الطابور queue (بمعنى أنه يجب أن ينتهي تحميل كل جزء قبل أن يبدأ تحميل الجزء التالي له)، ويحتاج موقع ويب حديث وسطيًّا حوالي 100 طلب ليتم تحميل الصفحة(كل طلب يمثّل صورة، ملف js، ملف css، إلخ).
</p>

<p>
	يقوم بروتوكول HTTP/2 بحل هذه المشكلة لأنّه يقوم بتقديم تغييرات جذرية تتمثل في:
</p>

<ul>
<li>
		تحميل جميع الطلبات على التوازي، وليس على التسلسل كما في مبدأ الطابور،
	</li>
	<li>
		ضغط ترويسة HTTP،
	</li>
	<li>
		نقل الصفحات عبر الشبكة بصيغة ثنائية binary، وليس كنصوص text، وهذا أكثر فعالية،
	</li>
	<li>
		قدرة الخادوم الآن على "دفع" البيانات قبل أن يطلبها المستخدم، مما سيحسّن من السرعة للمستخدمين الذين يعانون من بطء في الإرسال.
	</li>
</ul>
<p>
	وعلى الرغم من أن بروتوكول HTTP/2 لا يتطلب التشفير، إلا أن مطوّري أشهر متصفّحين، Google Chrome و Mozilla Firefox، صرّحوا بأنه -لدواع أمنيّة- سيتم دعم بروتوكول HTTP/2 في اتصالات HTTPS الآمنة فقط، ولهذا السبب إن قررت تثبيت خواديم تدعم HTTP/2 فيجب عليك الانتقال إلى استخدام HTTPS.
</p>

<h2>
	الخطوة الأولى: تثبيت الإصدار الأخير من Nginx
</h2>

<p>
	تم طرح دعم HTTP/2 في إصدار Nginx 1.9.5، ولسوء الحظ فإنّ المستودع الافتراضي في نظام Ubuntu متأخر عن إدراج آخر إصدار ويقوم حاليًّا بتوفير الإصدار 1.4.6.
</p>

<p>
	لكن لحسن الحظ فإن مطوّري Nginx لديهم مستودع apt خاص على نظام Ubuntu، حيث بالإمكان الحصول دومًا على آخر إصدار متوفّر.
</p>

<p>
	لإضافة المستودع الخاص إلى قائمة مستودعات apt لدينا، نحتاج أولًا للحصول على مفتاح التوقيع الرقمي الخاص بالمستودع، وهذا إجراء أمني يضمن بأن الحزم البرمجية التي سنحصل عليها من هذا المستودع صادرة عن المطوّرين الحقيقين وموقّعة منهم. سنقوم بتنفيذ الأمر التالي في سطر الأوامر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_15">
<span class="pln">$ wget -qO - http://nginx.org/keys/nginx_signing.key | sudo apt-key add -</span></pre>

<p>
	بعد ذلك، سنقوم بإضافة المستودع إلى قائمة مصادر الحزم البرمجية، بتنفيذ الأمر التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_17">
<span class="pln">$ 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</span></pre>

<p>
	الآن وبعد أن أصبح نظام الحزم (الذي يدعى apt في نظامي Ubuntu و Debian) يعلم عن توفّر المستودع الجديد، سنقوم بتحديث قائمة الحزم البرمجية المتوفّرة وأخيرًا سنقوم بتثبيت الإصدار الأخير من Nginx:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_19">
<span class="pln">$ sudo apt-get update
$ sudo apt-get install nginx</span></pre>

<p>
	ويمكن التحقق من رقم الإصدار بتنفيذ الأمر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_21">
<span class="pln">$ sudo nginx -v</span></pre>

<p>
	حيث ينبغي أن يكون الخرج مشابهًا لـ <strong>nginx version: nginx/1.9.x</strong>.
</p>

<p>
	سنقوم في الخطوات التالية بتغيير الإعدادات الافتراضية في Nginx ليقوم بتخديم موقع الويب الخاص بنا.
</p>

<h2>
	الخطوة الثانية: تغيير منفذ التنصّت الافتراضي
</h2>

<p>
	سنقوم أولًا بتغيير رقم المنفذ من 80 إلى 443، وذلك بفتح ملف الإعدادات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_23">
<span class="pln">$ sudo nano /etc/nginx/conf.d/default.conf</span></pre>

<p>
	<strong>ملاحظة</strong>: في حال ظهر خطأ يخبرك بأنه لم يتم التعرّف على الأمر <span style="font-family:courier new,courier,monospace;">nano</span>، فتأكّد من تثبيت محرر النصوص <span style="font-family:courier new,courier,monospace;">nano</span> وحاول مجدّدًا.
</p>

<p>
	ينبغي أن نخبر Nginx برقم المنفذ الذي يجب عليه تلقّي الاتصالات عبره، وهو المنفذ 80 افتراضيًا، المنفذ القياسي في بروتوكول HTTP. سنبحث في ملف الإعدادات عن السطر التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_25">
<span class="pln">listen 80;</span></pre>

<p>
	سنقوم بتغيير المنفذ إلى 443 لأن HTTP/2 لن يعمل مع معظم المستخدمين إذا بقي يقوم بإرسال البيانات عبر المنفذ 80، كما أشرنا سابقًا إلى أنه مدعوم فقط عبر المنفذ 443 على متصفحات Chrome و Firefox.سنستبدل السطر السابق بـ:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_27">
<span class="pln">listen 443 <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></abbr> http2;</span></pre>

<p>
	لاحظ أننا أضفنا كلمة <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></abbr> و http2 في نهاية السطر، وتخبر هذه المتغيّرات Nginx بأن يستخدم بروتوكول HTTP/2 مع المتصفحات التي تدعم البروتوكول الجديد.
</p>

<h2>
	الخطوة الثالثة: تغيير اسم الخادوم
</h2>

<p>
	يأتي اسم الخادوم<span style="font-family:courier new,courier,monospace;"> server_name </span>بعد السطر السابق الذي يحوي على listen، وسنقوم بإعلام Nginx أيّ نطاق سيرتبط مع ملف الإعدادات. سنستبدل الاسم الافتراضي localhost الذي يعني بأن ملف الإعدادات مسؤول عن جميع الطلبات الواردة، وسنضع مكانه اسم النطاق الحقيقي، كـ example.com على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_29">
<span class="pln">server_name example.com;</span></pre>

<p>
	سنقوم الآن بحفظ التغييرات بالضغط على <span style="font-family:courier new,courier,monospace;">CTRL+O</span> ومن ثم نضغط <span style="font-family:courier new,courier,monospace;">CTRL+X</span> للخروج من محرر <span style="font-family:courier new,courier,monospace;">nano</span>.
</p>

<h2>
	الخطوة الرابعة: إضافة المسار إلى شهادات <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr></abbr> الأمنية
</h2>

<p>
	سنقوم بإعداد Nginx الآن ليستخدم الشهادات الأمنية اللازمة لـ HTTPS، وإن لم تكن تعلم ما هي الشهادة الأمنية أو لم تكن تملك واحدة فيرجى مراجعة المقالات المذكورة في قسم المتطلبّات الأولية في بداية المقال.
</p>

<p>
	لنقم أولًا بإنشاء مجلّد لحفظ الشهادات الأمنية فيه داخل مجلد إعدادات Nginx:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_31">
<span class="pln">$ sudo mkdir /etc/nginx/<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></abbr></span></pre>

<p>
	سنقوم الآن بنسخ ملف الشهادة وملف المفتاح الخاص private key إلى داخل المجلد الجديد، وبعد ذلك سنقوم بتغيير أسماء الملفات لتظهر بوضوح أي نطاق ترتبط معه (تساعد هذه الخطوة في المستقبل على توفير الوقت والجهد إن امتلكت أكثر من نطاق واحد). لا تنسى استبدال example.com باسم النطاق الخاص بك.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_33">
<span class="pln">$ sudo cp /path/to/your/certificate.crt /etc/nginx/<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></abbr>/example.com.crt
$ sudo cp /path/to/your/private.key /etc/nginx/<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></abbr>/example.com.key</span></pre>

<p>
	سنقوم بإضافة سطر جديد الآن إلى ملف الإعدادات ضمن كتلة server لتعريف مسارات الشهادة الرقمية مع مفتاحها الخاص
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_35">
<span class="pln">ssl_certificate /etc/nginx/<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></abbr>/example.com.crt;
ssl_certificate_key /etc/nginx/<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></abbr>/example.com.key;</span></pre>

<h2>
	الخطوة الخامسة: تحويل جميع طلبات HTTP إلى HTTPS
</h2>

<p>
	ينبغي الآن أن نخبر Nginx بأننا نرغب بتوفير المحتوى عبر HTTPS فقط إن استلم طلب HTTP عوضًا عن ذلك.
</p>

<p>
	سنقوم في نهاية ملف الإعدادات بإنشاء كتلة server جديدة لتحويل جميع طلبات HTTP إلى HTTPS، ومرة أخرى لا تنس استبدال النطاق باسم النطاق الخاص بك، ستكون الكتلة الجديدة على الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_37">
<span class="pln">server {
       listen         80;
       listen    [::]:80;
       server_name    example.com;
       return         301 https://$server_name$request_uri;
}</span></pre>

<p>
	لاحظ في الكتلة السابقة كيف أنّ Nginx عند استلامه لطلبات HTTP تخص النطاق example.com عبر المنفذ 80، فإنّه سيقوم بتحويل الطلب إلى HTTPS على نفس المسار المطلوب، مستخدمّا التحويل من النمط301 (moved permanently).
</p>

<p>
	سيصبح شكل ملف الإعدادات (إن تجاهلنا الأسطر الخاصة بالتعليقات) على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_39">
<span class="pln">server {
        listen 443 <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></abbr> http2 default_server;
        listen [::]:443 <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></abbr> 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/<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></abbr>/example.com.crt;
        ssl_certificate_key /etc/nginx/<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></abbr>/example.com.key;
        ssl_dhparam /etc/nginx/<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></abbr>/dhparam.pem;
}


server {
       listen         80;
       listen    [::]:80;
       server_name    example.com;
       return         301 https://$server_name$request_uri;
}</span></pre>

<p>
	سنقوم الآن بحفظ ملف الإعدادات بالضغط على <span style="font-family:courier new,courier,monospace;">CTRL+O </span>ومن ثم الخروج من محرر <span style="font-family:courier new,courier,monospace;">nano</span> بالضغط على <span style="font-family:courier new,courier,monospace;">CTRL+X</span>.
</p>

<h2>
	الخطوة السادسة: تحميل ملف الإعدادات الجديد في ذاكرة Nginx
</h2>

<p>
	لتطبيق التغييرات التي قمنا بها، سنحتاج لإعادة تشغيل خادوم Nginx:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_41">
<span class="pln">$ sudo service nginx restart</span></pre>

<p>
	وللتحقق من أن كل شيء سار على ما يرام، سنقوم بفتح المتصفح واستعراض النطاق الذي أعددناه مع Nginx، فإن كانت الإعدادات صحيحة، يجب أن يتم تحويل الطلب إلى HTTPS بشكل تلقائي، وللتأكد مما إذا تم استخدام البروتوكول الجديد فسنقوم بفتح أدوات المطوّر (في متصفح كروم يمكن فتحها من خلال قائمة <strong>View &gt; Developer &gt; Developer Tools</strong>)، ومن ثم نعيد تحميل الصفحة من جديد (<strong>View &gt; Reload This Page</strong>)، ثم من خلال لسان Network، سنضغط بالزر الأيمن للفأرة على سطر رأس الجدول ونختار Protocol. يجب الآن أن يظهر عمود جديد عنوانه Protocol ستتمكن من خلاله من رؤية أن البروتوكول المستخدم هو h2 (الذي يرمز إلى بروتوكول HTTP/2) في حال تم الإعداد بشكل صحيح.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="17014" href="https://academy.hsoub.com/uploads/monthly_2016_05/001-http2_check.png.c92bb1f5a8fba35c5cf509e3c7eddfc7.png" rel="external"><img alt="001-http2_check.png" class="ipsImage ipsImage_thumbnailed" data-fileid="17014" data-unique="5ntu6qjld" src="https://academy.hsoub.com/uploads/monthly_2016_05/001-http2_check.thumb.png.695b21cf6ae2a90d8677e474ad5bcc7f.png"></a>
</p>

<p>
	إلى هنا سيكون Nginx قد أصبح قادرًا على تخديم المحتوى باستخدام بروتوكول HTTP/2، ولكن تبقى هناك بعض الأمور التي ينبغي إعدادها قبل استخدام الخادوم في بيئة التشغيل.
</p>

<h2>
	الخطوة السابعة: تحسين Nginx لتقديم أداء أفضل
</h2>

<p>
	سنقوم الآن بفتح ملف الإعدادات مجدّدًا لضبط إعدادات Nginx لتقديم أفضل أداء وحماية.
</p>

<h3>
	تفعيل Connection Credentials Caching
</h3>

<p>
	بالمقارنة مع HTTP، فإن HTTPS يتطلب وقتًا أطول نسبيًا لإنشاء اتصال ما بين الخادوم والمستخدم، ولتقليل الفرق في سرعة تحميل الصفحة، سنقوم بتفعيل ميّزة Connection Credentials Caching وهذا يعني بأنه عوضًا عن إنشاء جلسة عمل جديدة عند طلب كل صفحة، سيقوم الخادوم باستخدام نسخة خبء cache لمعلومات المصادقة.
</p>

<p>
	لتفعيل الميّزة، سنقوم بإضافة السطرين التاليين إلى نهاية كتلة http في ملف الإعدادات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_43">
<span class="pln">ssl_session_cache shared:<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr></abbr>:5m;
ssl_session_timeout 1h;</span></pre>

<p>
	يقوم المتغيّر<span style="font-family:courier new,courier,monospace;"> ssl_session_cache</span> بتحديد حجم الخبء الذي سيحتوي على معلومات الجلسة، حيث يمكن لـ 1MB أن يقوم بتخزين معلومات 4000 جلسة عمل، وبالتالي ستكون القيمة الافتراضية 5MB أكثر من كافية لمعظم الحالات، ولكن إن كنت تتوقع أن يكون هناك حركة مرور كثيفة على الموقع، فيمكنك زيادة القيمة وفقًا لذلك.
</p>

<p>
	يحدّد المتغير <span style="font-family:courier new,courier,monospace;">ssl_session_timeout </span>من الوقت الذي تكون ضمنه جلسة العمل فعّالة داخل الخبء، ولا ينبغي أن تكون هذه القيمة كبيرة (أكثر من ساعة)، وإلى جانب ذلك فإن تخفيضها كثيرًا سيخفض من الفائدة المرجوّة أيضًا.
</p>

<h3>
	تحسين باقات التشفير Cipher Suites
</h3>

<p>
	باقات التشفير هي مجموعة من خوارزميات التشفير التي تصف كيف ينبغي أن يتم تشفير البيانات المنقولة. يملك بروتوكول HTTP/2 قائمة كبيرة من خوارزميات التشفير القديمة وغير الآمنة التي يجب تجنّب استخدامها.
</p>

<p>
	سنقوم باستخدام مجموعة تشفير معتمدة من قبل جهات عملاقة مثل CloudFlare. لا تسمح هذه المجموعات باستخدام خوارزمية MD5 في التشفير (التي تم إثبات أنها غير آمنة في عام 1996، وبالرغم من ذلك، فما تزال منتشرة حتى يومنا هذا).
</p>

<p>
	سنقوم بإضافة السطرين التاليين بعد<span style="font-family:courier new,courier,monospace;"> ssl_session_timeout</span>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_45">
<span class="pln">ssl_prefer_server_ciphers on;
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;</span></pre>

<h3>
	تفعيل ميزة (Strict Transport Security (HSTS
</h3>

<p>
	على الرغم من أنّا قمنا بتحويل جميع طلبات HTTP إلى HTTPS في إعدادات Nginx، فينبغي علينا أيضًا أن نقوم بتفعيل ميّزة Strict Transport Security لتجنّب الحاجة لإخبار Nginx بعملية التحويل بأنفسنا أساسًا.
</p>

<p>
	عندما يصادف المتصفح ترويسة HSTS، فلن يحاول الاتصال بالخادوم عبر HTTP التقليدي مجدّدًا قبل مضي فترة من الوقت، ومهما حصل، سيعمل على تبادل البيانات عبر اتصالات HTTPS مشفّرة. تساعد هذه الترويسة على حمايتنا من هجمات تخفيض البروتوكول.
</p>

<p>
	كل ما نحتاجه هو إضافة السطر التالي في ملف الإعدادات:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_47">
<span class="pln">add_header Strict-Transport-Security "max-age=15768000" always;</span></pre>

<p>
	يحدّد المتغير <span style="font-family:courier new,courier,monospace;">max-age</span> القيمة التي يجب على المتصفح خلالها ألا يحاول التواصل مع الخادوم إلا عبر بروتوكول HTTPS، وهذه القيمة ممثّلة بالثواني وبالتالي فإن القيمة 15768000 تساوي 6 أشهر.
</p>

<p>
	وبشكل افتراضي فإن هذه الترويسة لن يتم إضافتها إلى الطلبات الموجّهة للنطاقات الفرعية، فإن كنت تملك نطاقات فرعية وترغب أن يتم تطبيق HSTS عليها جميعًا فيجب إضافة المتغير <span style="font-family:courier new,courier,monospace;">includeSubDomains</span> حينها إلى نهاية السطر على الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_49">
<span class="pln">add_header Strict-Transport-Security "max-age=15768000; includeSubDomains: always;";</span></pre>

<p>
	لا تنس حفظ الملف الآن بالضغط على<span style="font-family:courier new,courier,monospace;"> CTRL+O</span> ومن ثم إغلاقه بالضغط على <span style="font-family:courier new,courier,monospace;">CTRL+X </span>إن كنت تستخدم محرر <span style="font-family:courier new,courier,monospace;">nano</span>.
</p>

<h2>
	الخطوة الثامنة: رفع حماية تبادل المفاتيح الأمنية
</h2>

<p>
	إن الخطوة الأولى في إنشاء اتصال آمن هو تبادل المفاتيح الخاصة بين الخادوم والعميل، وتكمن المشكلة في هذه العملية في أنّه حتى تلك اللحظة فالاتصال غير مشفّر بينهما وبالتالي فالبيانات المتبادلة يمكن التنصّت عليها من طرف ثالث. لهذا السبب، سنحتاج لاستخدام خوارزمية Diffie-Hellman-Merkle في تبادل المفاتيح.
</p>

<p>
	يستخدم Nginx بشكل افتراضي مفتاح DHE) Ephemeral Diffie-Hellman) بطول 1024 بت، والذي يمكن فك تشفيره بسهولة نسبيًا، وللحصول على أمان أعلى فينبغي علينا إنشاء مفتاح DHE خاص أكثر أمنًا.
</p>

<p>
	للقيام بذلك سنقوم بتنفيذ الأمر التالي في سطر الأوامر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_51">
<span class="pln">$ sudo openssl dhparam -out /etc/nginx/<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></abbr>/dhparam.pem 2048</span></pre>

<p>
	<strong>تنبيه</strong>: يجب أن يتم إنشاء مُعاملات DH في المجلد الذي قمنا بتخزين الشهادات الأمنية فيه، وفي المقال قمنا بتخزين الشهادات في المسار <span style="font-family:courier new,courier,monospace;">/etc/nginx/<abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">ssl</abbr></abbr>/</span>. إن السبب وراء هذا هو أن Nginx يقوم دومًا بالبحث عن مفتاح DHE الخاص بالمستخدم في مجلد الشهادات الأمنية ويستخدمه إن وُجد.
</p>

<p>
	تحدّد القيمة 2048 في الأمر السابق طول المفتاح الذي نرغب بإنشائه، حيث سيكون مفتاح بطول 2048 بت أكثر أمنًا وينصح به من قبل مؤسسة موزيلّا، ولكن إن كنت تسعى خلف أقصى درجة أمان، فيمكنك استخدام مفتاح بطول 4096 بت.
</p>

<p>
	ستأخذ عملية إنشاء المفتاح حوالي 5 دقائق، ويمكنك أثناء ذلك الاسترخاء وارتشاف بعض القهوة.
</p>

<p>
	لتطبيق التغييرات التي قمنا بها على ملف الإعدادات، لا تنسى أن تقوم بإيقاف وإعادة تشغيل خادوم Nginx:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_1394_53">
<span class="pln">$ sudo service nginx restart</span></pre>

<h2>
	الخلاصة
</h2>

<p>
	أصبح اتصال <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr></abbr> الخاص بك أكثر أمنًا وقابلًا للاستخدام لنقل المعلومات الحساسة، ولكن إن أردت اختبار قوته الأمنية فقم بزيارة <a href="https://www.ssllabs.com/ssltest/" rel="external nofollow">Qualys <abbr title="Secure Socket Layer | طبقة المنافذ الآمنة"><abbr title="Secure Socket Layer | طبقة المنافذ الآمنة">SSL</abbr></abbr> Lab</a> وبتشغيل اختبار على خادومك، حيث ينبغي أن تحصل على نتيجة A+إن كان كلّ شيء معدّ بشكل صحيح.
</p>

<p>
	هذا كلّ شيء، أصبح خادوم Nginx الخاص بك جاهزًا للاستخدام، وكما ترى فإن بروتوكول HTTP/2 هو حل رائع لتحسين سرعات نقل البيانات ومن السهل استخدامه كما أظهرنا في المقال.
</p>

<p>
	ترجمة -وبتصرّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-nginx-with-http-2-support-on-ubuntu-14-04" rel="external nofollow">How To Set Up Nginx with HTTP/2 Support on Ubuntu 14.04</a> لصاحبه Sergey Zhukaev.
</p>
]]></description><guid isPermaLink="false">261</guid><pubDate>Mon, 30 May 2016 22:30:00 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x636;&#x63A;&#x637; gzip &#x641;&#x64A; Nginx &#x639;&#x644;&#x649; &#x646;&#x638;&#x627;&#x645; &#x623;&#x648;&#x628;&#x646;&#x62A;&#x648;&#xA0;14.04</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B6%D8%BA%D8%B7-gzip-%D9%81%D9%8A-nginx-%D8%B9%D9%84%D9%89-%D9%86%D8%B8%D8%A7%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88%C2%A01404-r259/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2016_05/nginx-gzip-compression.png.633db69b46df354c809411b42f626fea.png" /></p>

<p dir="rtl">
	تعتمد سرعة عرض صفحة ويب على حجم جميع الملفات المرتبطة بالصفحة والتي يجب تحميلها من قبل المتصفح، وبالتالي فتخفيف حجم الملفات المطلوبة يمكن أن يسرّع من عرض صفحة الويب، ويوفّر الكثير من المال على الأشخاص الذين يدفعون مقابل عرض الحزمة bandwidth المستهلكة.
</p>

<p dir="rtl">
	يعدّ gzip من البرامج المشهورة المستخدمة في ضغط البيانات، وبالإمكان إعداد خادوم Nginx لاستخدام gzip لضغط الملفات التي يتم تخديمها من قبل الخادوم قبل إرسالها للمتصفحات والتي ستقوم بدورها بفك الضغط عن الملفّات (تدعم جميع المتصفحات المشهورة فك ضغط gzip ويفترض أن تدعم -معظم- المتصفحات عمومًا هذه العملية) دون أي خسارة في دقة البيانات بعد فك الضغط، مستفيدة بذلك من تخفيف حجم البيانات المتبادلة ما بين خادوم الويب والمتصفح.
</p>

<p dir="rtl" style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="16701" data-unique="n9n1k51z3" src="https://academy.hsoub.com/uploads/monthly_2016_05/nginx-gzip-compression.png.176948201b6a4f4f432e1e666f47593b.png" alt="nginx-gzip-compression.png"></p>

<p dir="rtl">
	ونظرًا لاختلاف الطرق التي تعمل بها خوارزميات الضغط عمومًا، وآلية عمل خوارزمية gzip خصوصًا، فإنّ بعض الملفات يمكن ضغطها بنسبة أكبر من بعضها الآخر. فعلى سبيل المثال، يتم ضغط الملفات النصيّة text بصورة جيّدة جدًا حيث قد تكون نتيجة الضغط أصغر بحوالي مرّتين من الحجم الأصلي. ومن ناحية أخرى، فالصور من نوع JPEG و PNG تأتي مضغوطة سلفًا بطبيعة الخوارزمية المنتجة لها وبالتالي لن نحصل على الكثير من الفائدة بعد تطبيق ضغط gzip عليها، وعلى اعتبار أن ضغط الملفّات يستهلك الكثير من مصادر الخادوم، فمن الأفضل أن يتم ضغط الملفّات التي تملك نسبة ضغط عالية.
</p>

<p dir="rtl">
	سنناقش في المقال كيفية إعداد خادوم Nginx المثبت على نظام تشغيل Ubuntu 14.04 ليستخدم gzip في الضغط لتخفيف حجم المحتوى المرسل إلى متصفّحي الموقع.
</p>

<h2 dir="rtl">
	المتطلبات الأولية
</h2>

<p dir="rtl">
	نحتاج الأمور التالية قبل المتابعة:
</p>

<ul dir="rtl">
<li>
		نظام تشغيل Ubuntu 14.04،
	</li>
	<li>
		مستخدم عادي بدون صلاحيات مدير نظام، لكنّه يملك صلاحية تنفيذ أمر sudo، يمكن مراجعة <a href="https://academy.hsoub.com/devops/servers/%D8%A7%D9%84%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A7%D9%84%D8%A7%D8%A8%D8%AA%D8%AF%D8%A7%D8%A6%D9%8A-%D9%84%D8%AE%D8%A7%D8%AF%D9%88%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r4/PB2xwrGrXyTZQcvybxcxw" rel="">الإعداد الابتدائي لخادوم أوبونتو </a><a href="https://academy.hsoub.com/devops/servers/%D8%A7%D9%84%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A7%D9%84%D8%A7%D8%A8%D8%AA%D8%AF%D8%A7%D8%A6%D9%8A-%D9%84%D8%AE%D8%A7%D8%AF%D9%88%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r4/PB2xwrGrXyTZQcvybxcxw" rel="">14.04</a> لمزيد من المعلومات،
	</li>
	<li>
		نسخة Nginx مثبّته على النظام، ويمكنك اتباع <a href="https://academy.hsoub.com/devops/web-servers/nginx/%D8%AA%D9%86%D8%B5%D9%8A%D8%A8%D8%8C-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D9%88%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-nginx-%D9%83%D8%AE%D8%A7%D8%AF%D9%88%D9%85-%D9%88%D9%8A%D8%A8-r1/" rel="">هذا المقال لتثبيت Nginx</a> للقيام بذلك.
	</li>
</ul>
<h2 dir="rtl">
	الخطوة الأولى: إنشاء ملفات تجريبية
</h2>

<p dir="rtl">
	سنقوم في هذه الخطوة بإنشاء عدّة ملفات تجريبية في الجذر الافتراضي للمواقع المدارة من Nginx لاختبار ضغط gzip.
</p>

<p dir="rtl">
	ولتحديد الملف الذي سيتم تخديمه عبر الشبكة، يكتفي Nginx بالاعتماد على لاحقة الملف لتحديد نمط MIME الخاص به، عوضًا عن القيام بقراءة ترويسته وذلك بغية تنفيذ العملية بأسرع وقت ممكن. ونتيجة لهذا التصرّف فإن محتوى الملف لا يعود مهمًّا ويصبح من الممكن خداع Nginx بجعله يعتقد أن ملفًا فارغًا عبارة عن صورة، وملفًا آخر عبارة عن مستند css.
</p>

<p dir="rtl">
	في إعداداتنا التالية، لن يقوم Nginx بضغط الملفّات الصغيرة جدًا، لذا سنقوم بإنشاء ملفّات تجريبية يبلغ حجمها 1 كيلوبايت تمامًا. سيسمح هذا السيناريو بالتحقق فيما إذا كان Nginx يقوم بضغط الملفات التي من المفترض به القيام بضغطها.
</p>

<p dir="rtl">
	لنقم بإنشاء ملف بحجم 1 كيلوبايت وتسميته test.html في الجذر الرئيسي الافتراضي للمواقع المدارة من Nginx وذلك باستخدام أمر <span style="font-family:courier new,courier,monospace;">truncate</span> عبر سطر الأوامر، كما في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3207_8">
<span class="pln">$ sudo truncate -s 1k /usr/share/nginx/html/test.html</span></pre>

<p dir="rtl">
	لنقم بإنشاء المزيد من الملفّات التجريبية بنفس الطريقة: ملف صورة jpg، ملف css، وملف js.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3207_10">
<span class="pln">$ 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</span></pre>

<h2 dir="rtl">
	الخطوة الثانية: التحقق من التصرّف الافتراضي لـ Nginx
</h2>

<p dir="rtl">
	سنقوم الآن بالتحقق من كيفية تصرّف Nginx عند ضغط الملفات التي قمنا بإنشائها توًّا.
</p>

<p dir="rtl">
	لنتحقق مما إذا سيتم تخديم ملف<span style="font-family:courier new,courier,monospace;"> test.html</span> بعد الضغط، سنقوم في الأمر التالي بطلب الملف من خادوم Nginx، ونخبره بأنّه لا مشكلة لدينا في الحصول على محتوى مضغوط باستخدام gzip وذلك بتمرير ترويسة HTTP مناسبة (<span style="font-family:courier new,courier,monospace;">Accept-Encoding: gzip</span>).
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3207_12">
<span class="pln">$ curl -H "Accept-Encoding: gzip" -I http://localhost/test.html</span></pre>

<p dir="rtl">
	سنحصل في جواب الخادوم على ما يشبه النص التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3207_14">
<span class="pln">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</span></pre>

<p dir="rtl">
	ويمكن في السطر الأخير ملاحظة وجود ترويسة (<span style="font-family:courier new,courier,monospace;">Content-Encoding: gzip</span>) والتي تخبرنا بأن المحتوى الذي حصلنا عليه قد تم ضغطه باستخدام gzip، ولكن كيف حصل ذلك دون أن نقوم بتفعيل gzip أولًا في Nginx؟ إنّ السبب خلف هذا هو أن الضغط باستخدام gzip مفعّل بشكل تلقائي في نسخة Nginx على نظام Ubuntu 14.04 بإعداداته الافتراضية.
</p>

<p dir="rtl">
	على الرغم من ذلك، فإن Nginx لن يقوم إلا بضغط ملفات HTML فقط، بينما يتم تخديم باقي أنواع الملفّات بدون ضغط، ويمكن التحقق من ذلك بطلب صورة بنفس الطريقة السابقة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3207_16">
<span class="pln">$ curl -H "Accept-Encoding: gzip" -I http://localhost/test.jpg</span></pre>

<p dir="rtl">
	وسنحصل على رد مختلف قليلًا عن السابق:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3207_18">
<span class="pln">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</span></pre>

<p dir="rtl">
	حيث نلاحظ عدم وجود ترويسة (<span style="font-family:courier new,courier,monospace;">Content-Encoding: gzip</span>) وهذا يعني أن الملف تم إرساله لنا بدون ضغط.
</p>

<p dir="rtl">
	يمكن تنفيذ الاختبار ذاته مجدّدًا مع ملف <span style="font-family:courier new,courier,monospace;">test.css </span>ومرّة أخرى سنحصل على الملف بدون ضغط.
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3207_22">
<span class="pln">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</span></pre>

<h2 dir="rtl">
	الخطوة الثالثة: تغيير إعدادات ضغط gzip في خادوم Nginx
</h2>

<p dir="rtl">
	سنقوم الآن بتغيّير إعدادات Nginx ليتم ضغط ملفّات من أنواع أخرى عدا عن HTML، والتي من الممكن الاستفادة من نسبة الضغط المطبّقة عليها.
</p>

<p dir="rtl">
	سنقوم بفتح ملف إعدادات Nginx باستخدام محرر <span style="font-family:courier new,courier,monospace;">nano</span> أو أي محرر آخر تفضّل استخدامه:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3207_24">
<span class="pln">$ sudo nano /etc/nginx/nginx.conf</span></pre>

<p dir="rtl">
	ومن ثم سنبحث عن كتلة إعدادات gzip التي ستبدو كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3207_26">
<span class="pln">. . .
##
# `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;
. . .</span></pre>

<p dir="rtl">
	نلاحظ في الإعدادات السابقة أن الضغط بواسطة gzip مفعّل بشكل افتراضي بواسطة توجيه<span style="font-family:courier new,courier,monospace;"> gzip on</span>، بينما معظم الإعدادات الإضافية تم تعطيلها بإشارة التعليقات # في بداية السطر. سنقوم بإجراء بعض التعديلات على هذه الإعدادات مثل:
</p>

<ul dir="rtl">
<li>
		تفعيل الإعدادات الإضافية من خلال حذف إشارة التعليقات # في بداية الأسطر،
	</li>
	<li>
		إضافة توجيه <span style="font-family:courier new,courier,monospace;">gzip_min_length 256</span>; الذي يخبر Nginx ألّا يقوم بضغط الملفات التي يصغر حجمها عن 256 بايت، فهذا الحجم الصغير جدًا لن يحقق الفائدة المرجوّة بعد الضغط،
	</li>
	<li>
		▪ إضافة توجيه<span style="font-family:courier new,courier,monospace;"> gzip_types</span> مع المزيد من أنماط الملفّات كخطوط الويب، الأيقونات والصور من نوع SVG.
	</li>
</ul>
<p dir="rtl">
	بعد إجراء التعديلات المذكورة سيبدو مقطع الإعدادات الجديد على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6258_7">
<span class="pln">. . .
##
# `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;
. . .</span></pre>

<p dir="rtl">
	قم بحفظ الملف وإغلاقه وتطبيق التعديلات من خلال إعادة تشغيل خادوم Nginx باستخدام الأمر:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6258_9">
<span class="pln">$ sudo service nginx restart</span></pre>

<h2 dir="rtl">
	الخطوة الرابعة: التحقق من الإعدادات الجديدة
</h2>

<p dir="rtl">
	سنقوم الآن بالتحقق من أنّ الإعدادات التي قمنا بتغييرها وإضافتها تعمل على النحو المطلوب، ويمكن القيام بذلك من خلال إعادة تنفيذ الاختبارات المذكورة في الخطوة الثانية عبر استخدام أمر <span style="font-family:courier new,courier,monospace;">curl</span> على كلّ من الملفّات التجريبية والتحقق من وجود ترويسة <span style="font-family:courier new,courier,monospace;">Content-Encoding: gzip </span>في الخرج:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6258_11">
<span class="pln">$ 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</span></pre>

<p dir="rtl">
	من المفترض الآن أن تكون جميع الملفّات مضغوطة وتظهر ترويسة <span style="font-family:courier new,courier,monospace;">Content-Encoding: gzip </span>في الخرج، عدا ملف الصورة <span style="font-family:courier new,courier,monospace;">test.jpg</span>، وتكون الإعدادات المطبّقة صحيحة والاختبار ناجحًا إن تحقق هذا.
</p>

<h2 dir="rtl">
	الخلاصة
</h2>

<p dir="rtl">
	إن تغيّير إعدادات Nginx لاستخدام ضغط gzip عملية سهلة جدًا لكن الفوائد المحقّقة ستكون كبيرة، فستوفّر الكثير على الزوّار الذين يملكون اتصالات محدودة بعرض الحزمة، وبالإضافة إلى ذلك ستحصل على تقييم أفضل في محرّكات البحث مثل Google من خلال تحقيق سرعة عرض أعلى للصفحة، حيث أن عامل سرعة عرض الصفحة بدأ يأخذ حيّزًا مهمًا من عملية التقييم في المواقع الحديثة وخوارزمية الضغط gzip هي خطوة كبيرة باتجاه تحسين النتيجة.
</p>

<p dir="rtl">
	ترجمة -وبتصرّف- للمقال <a href="https://www.digitalocean.com/community/tutorials/how-to-add-the-gzip-module-to-nginx-on-ubuntu-14-04" rel="external nofollow">How To Add the gzip Module to Nginx on Ubuntu 14.04</a> لصاحبه Mateusz Papiernik.
</p>
]]></description><guid isPermaLink="false">259</guid><pubDate>Sun, 22 May 2016 10:30:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641; &#x62A;&#x633;&#x62A;&#x636;&#x64A;&#x641; &#x645;&#x62C;&#x645;&#x648;&#x639;&#x629; &#x645;&#x648;&#x627;&#x642;&#x639; &#x628;&#x634;&#x643;&#x644; &#x622;&#x645;&#x646; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Nginx &#x648; Php-fpm &#x639;&#x644;&#x649; &#x623;&#x648;&#x628;&#x646;&#x62A;&#x648; 14.04</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81-%D8%AA%D8%B3%D8%AA%D8%B6%D9%8A%D9%81-%D9%85%D8%AC%D9%85%D9%88%D8%B9%D8%A9-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D8%A8%D8%B4%D9%83%D9%84-%D8%A2%D9%85%D9%86-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-nginx-%D9%88-php-fpm-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r251/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2016_04/host-multiple-websites-nginx-php-fpm.png.1e13ef7a73c38a79f6cf024d317b9f89.png" /></p>

<div id="wmd-preview-section-10">
	<p>
		من المعروف أن <a href="https://academy.hsoub.com/devops/servers/%D9%83%D9%8A%D9%81-%D8%AA%D8%AB%D8%A8%D8%AA-%D8%AD%D8%B2%D9%85-mysql-%D8%8Cnginx-%D8%8Clinux-lemp-%D9%88php-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r29/" rel="">حزمة LEMP</a> (والتي هي اختصار لـ Linux, Nginx, MySQL, PHP) توفر سرعة وموثوقية عالية لتشغيل مواقع PHP، إلّا أنها تملك مزايا أخرى غير مشهورة كالأمن والعزل.
	</p>
</div>

<div id="wmd-preview-section-11">
	<p>
		في هذا المثال، سنعرض لك مزايا أمن وعزل المواقع على LEMP مع مستخدمين مُختلفين، وهذا عن طريق إنشاء أحواض pools خاصّة بـ php-fpm لكل جزء من خادوم nginx (سواء كان موقعًا أو مستضيفًا افتراضيًا virtual host).
	</p>

	<p style="text-align: center;">
		<img class="ipsImage ipsImage_thumbnailed" data-fileid="15717" data-unique="w4zuk7593" src="https://academy.hsoub.com/uploads/monthly_2016_04/host-multiple-websites-nginx-php-fpm.png.91de19745ca65c5679760633f3f96d4e.png" alt="host-multiple-websites-nginx-php-fpm.png"></p>
</div>

<div id="wmd-preview-section-12">
	<h2 id="المتطلبات-الأساسية">
		المتطلبات الأساسية
	</h2>

	<p>
		تمت تجربة هذا الدرس على أوبنتو 14.04 وعلى الرغم من ذلك فإن طريقة التثبيت والإعداد ستكون مشابهة لها على بقية الأنظمة والإصدارات، لكن قد تختلف الأوامر وأماكن ملفات الإعداد بين الأنظمة.
	</p>

	<p>
		كما أننا نفترض أنك قد ثبتت <span style="font-family:courier new,courier,monospace;">nginx</span> و <span style="font-family:courier new,courier,monospace;">php-fpm</span>، وبخلاف ذلك أنصحك بإتباع الخطوة الأولى والثالثة من هذا المقال: <a href="https://academy.hsoub.com/devops/servers/%D9%83%D9%8A%D9%81-%D8%AA%D8%AB%D8%A8%D8%AA-%D8%AD%D8%B2%D9%85-mysql-%D8%8Cnginx-%D8%8Clinux-lemp-%D9%88php-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r29/" rel="">كيف تثبت حزم MySQL ،nginx ،Linux :LEMP وPHP على أوبنتو 14.04</a>.
	</p>

	<p>
		يجب تنفيذ جميع الأوامر في هذا الدرس التعليمي بمستخدم غير الجذر (non-root)، وإن إحتجنا لصلاحياته فسنستخدم <span style="font-family:courier new,courier,monospace;">sudo</span>، وإذا لم تُعدّ بعد هذا المستخدم فأنصحك بإتباع هذا الدرس: <a href="https://academy.hsoub.com/devops/servers/%D8%A7%D9%84%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A7%D9%84%D8%A7%D8%A8%D8%AA%D8%AF%D8%A7%D8%A6%D9%8A-%D9%84%D8%AE%D8%A7%D8%AF%D9%88%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r4/" rel="">الإعداد الابتدائي لخادوم أوبنتو 14.04</a>.
	</p>

	<p>
		ستحتاج أيضا إلى اسم نطاق مؤهل بالكامل (fully qualified domain name (fqdn الذي يربط على خادوم أو خادوم للتجربة بالإضافة إلى localhost الافتراضي، وإذا لم يكن لديك واحد، يمكنك استخدام <span style="font-family:courier new,courier,monospace;">site1.example.org</span>، وذلك عن طريق تعديل ملف <span style="font-family:courier new,courier,monospace;">etc/hosts/</span> باستخدام محررك المفضل كهذا<span style="font-family:courier new,courier,monospace;"> sudo vim /etc/hosts</span> وأضف هذا السطر (استبدل site1.example.org بـ <span style="font-family:courier new,courier,monospace;">fqdn</span> الخاص بك إذا كنت تستخدمه):
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3987_8">
<span class="pln">...
127.0.0.1 site1.example.org
... </span></pre>

	<h2>
		أسباب لزيادة تأمين LEMP
	</h2>
</div>

<div id="wmd-preview-section-13">
	<p>
		عند إعداد LEMP مشترك سيكون هنالك حوض pool php-fpm واحد فقط والذي سيشغل جميع سكربتات PHP لجميع المواقع باستخدام نفس المستخدم، وهذا يطرح مشكلتين كبيرتين:
	</p>

	<ul>
<li>
			إذا تعرض تطبيق ويب على أحد أجزاء خادوم nginx -على سبيل المثال عنوان فرعي أو موقع ما- إلى خطر أو هجوم فستتعرض جميع مواقع الموجودة على هذا الخادوم أيضا، فالمهاجم سيتمكن من قراءة ملفات الإعداد (configuration files) بما في ذلك تفاصيل قواعد بيانات لمواقع أخرى أو حتى تغيير ملفاتها.
		</li>
		<li>
			إذا أردت إعطاء مستخدم صلاحيات للدخول إلى الخادوم الخاص بك، فسوف تعطيه صلاحيات الوصول إلى جميع المواقع، فعلى سبيل المثال، إذا كان مطورك يحتاج إلى العمل على بيئة الإدراج (staging environment)، فحتى مع صلاحيات صارمة جدا على الملفات، فستبقى له إمكانية وصوله إلى جميع المواقع بما في ذلك موقعك الرئيسي على نفس الخادوم.
		</li>
	</ul>
<p>
		المشاكل أعلاه تم حلها في php-fpm بإنشاء أحواض مختلفة والتي تشتغل تحت مستخدم مختلف لكل موقع.
	</p>
</div>

<div id="wmd-preview-section-14">
	<h2 id="الخطوة-1-إعداد-php-fpm">
		الخطوة الأولى - إعداد php-fpm
	</h2>

	<p>
		إذا غطيت المتطلبات الأساسية فسيكون لديك في الوقت الحالي موقع ويب يعمل على خادوم.
	</p>

	<p>
		سننشئ الآن موقعًا ثانيًا (<span style="font-family:courier new,courier,monospace;">site1.example.org</span>) مع حوض php-fpm ومستخدم لينكس مخصصين له.
	</p>

	<p>
		لنبدأ بإنشاء المستخدم الضروري، ولأفضل عملية فصل يجب أن يحصل المستخدم الجديد على مجموعته الخاصة لذلك سننشئ أولا مجموعة المستخدم <span style="font-family:courier new,courier,monospace;">site1</span>:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3987_24">
<span class="pln">sudo groupadd site1</span></pre>

	<p>
		وبعد ذلك سننشئ مستخدم <span style="font-family:courier new,courier,monospace;">site1</span> ينتمي إلى هذه المجموعة:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3987_26">
<span class="pln">sudo useradd -g site1 site1</span></pre>

	<p>
		حتى الآن لا يملك هذا المستخدم الجديد كلمة مرور ولا يمكنك تسجيل دخوله في خادوم، إذا أردت توفير صلاحيات وصول إلى هذه الملفات من الموقع لشخص معين، فيجب عليك في هذه الحالة إنشاء كلمة مرور لهذا المستخدم عن طريق الأمر:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3987_28">
<span class="pln"> sudo passwd site1 </span></pre>

	<p>
		ومع تركيبة اسم المستخدم/كلمة المرور سيتمكن المستخدم من تسجيل دخوله عن بعد باستخدام <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة"><abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">ssh</abbr></abbr></abbr></abbr></abbr> أو sftp.
	</p>

	<p>
		بعد ذلك، أنشئ حوض php-fpm جديد لـ <span style="font-family:courier new,courier,monospace;">site1</span>، فالحوض مهم للغاية وهو عبارة عن عملية (process) لينكس عادية والتي تعمل تحت مستخدم/مجموعة محددة وتستمع لـ Linux socket وقد تستمع أيضا لتركيبة IP:Port لكن سيتطلب هذا إلى المزيد من موارد الخادوم وهذه الطريقة ليست جيدة.
	</p>

	<p>
		بشكل افتراضي في نظام أبنتو 14.04، كل حوض php-fpm يجب أن يتم إعداده في ملف داخل مجلد<span style="font-family:courier new,courier,monospace;"> etc/php5/fpm/pool.d/</span>.
	</p>

	<p>
		كل ملف مع امتداد<span style="font-family:courier new,courier,monospace;"> conf.</span> في هذا المجلد سيتم تحميله تلقائيا في الإعداد العام لـ php-fpm.
	</p>

	<p>
		لذلك سننشئ ملف <span style="font-family:courier new,courier,monospace;">etc/php5/fpm/pool.d/site1.conf/</span> لموقعنا، يمكنك فعل ذلك مع محررك المفضل كالتالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3987_30">
<span class="pln">sudo vim /etc/php5/fpm/pool.d/site1.conf</span></pre>

	<p>
		يجب أن يحتوي هذا الملف على:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3987_32">
<span class="pln">[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 = /</span></pre>

	<p>
		في الإعدادات أعلاه، لاحظ هذه الخيارات:
	</p>

	<ul>
<li>
			إن<strong> <span style="font-family:courier new,courier,monospace;">[site1]</span> </strong>هو اسم الحوض، فلكل حوض اسم خاص به.
		</li>
		<li>
			يشير كل من <span style="font-family:courier new,courier,monospace;"><strong>user</strong></span> و <span style="font-family:courier new,courier,monospace;"><strong>group</strong></span> إلى المستخدم المجموعة التي سيعمل عليها الحوض الجديد.
		</li>
		<li>
			ستشير <span style="font-family:courier new,courier,monospace;"><strong>listen</strong></span> إلى مكان خاص لكل حوض.
		</li>
		<li>
			إن كل من<strong><span style="font-family:courier new,courier,monospace;"> listen.owner</span></strong> و <span style="font-family:courier new,courier,monospace;"><strong>listen.group </strong></span>يعرّفان ملكية المستمع (listener) -على سبيل المثال socket الخاصة بحوض php-fpm الجديد- ويجب على Nginx أن يكون قادرا على قراءة هذا socket، وهذا هو سبب أن socket يُنشأ مع اسم المستخدم والمجموعة تحت nginx الذي يشغل www-data.
		</li>
		<li>
			يسمح لك <span style="font-family:courier new,courier,monospace;"><strong>php_admin_value</strong></span> بوضع قيم إعداد php مخصصة والتي سنستخدمها لتعطيل دوال التي تُشغّل أوامر لينكس مثل <span style="font-family:courier new,courier,monospace;">exec</span>, <span style="font-family:courier new,courier,monospace;">passthru</span>, <span style="font-family:courier new,courier,monospace;">shell_exec</span>, <span style="font-family:courier new,courier,monospace;">system</span>.
		</li>
		<li>
			إن <span style="font-family:courier new,courier,monospace;"><strong>php_admin_flag</strong></span> مشابه لـ <span style="font-family:courier new,courier,monospace;">php_admin_value</span> لكنه مجرد مبدل لقيم المنطقية مثل on و off. سنعطل دالة PHP التي تدعى<span style="font-family:courier new,courier,monospace;"> allow_url_fopen</span> والتي تسمح لسكربت PHP بفتح ملفات عن بعد والتي يمكن أن تُستخدم بواسطة المهاجم.
		</li>
	</ul>
<p>
		<strong>ملاحظة</strong>: إن قيم <span style="font-family:courier new,courier,monospace;">php_admin_value</span> و <span style="font-family:courier new,courier,monospace;">php_admin_flag</span> يمكن تطبيقها بشكل عام، وعلى الرغم من ذلك قد يحتاجهما الموقع وهذا هو سبب عدم إعدادهما بشكل افتراضي. إن من مميزات أحواض php-fpm أنها تسمح لك بتخصيص إعدادات أمن لكل موقع، وعلاوة على ذلك، فيمكنك استخدام هذه الخيارات لأي إعدادات php أخرى، خارج المجال الأمني، لتخصيص بيئة الموقع.
	</p>

	<p>
		لن نتحدث في درسنا حول الأمن عن خيارات pm، لكن يجب أن تعرف أنها تسمح لك بإعداد أداء الحوض.
	</p>

	<p>
		وبالنسبة إلى خيار <span style="font-family:courier new,courier,monospace;">chdir</span> فيجب أن يكون / والذي يعبر عن جذر نظام الملفات، وهذا السطر لا يجب تغييره ما لم تكن تستخدم <span style="font-family:courier new,courier,monospace;">chroot</span>.
	</p>

	<p>
		لم يتم تضمين خيار <span style="font-family:courier new,courier,monospace;">chroot</span> في الإعدادات أعلاه لأنه سيسمح لك بتشغيل الحوض في بيئة مسجونة، مثل قفل المجلد، وهذا الأمر سيكون رائعًا لأغراض أمنية لأنه ستتمكن من قفل الحوض دخل مجلد الجذر للموقع، ولكن على الرغم من ذلك فإن هذا الخيار الأمني قد يتسبب بالعديد من المشاكل لأي تطبيق PHP يعتمد على تطبيقات النظام (system binaries) وتطبيقات مثل Imagemagick والتي لن تكون متوفرة.
	</p>

	<p>
		بمجرد انتهائك من الإعدادات أعلاه أعد تشغيل php-fpm لتفعيل الخيارات الجديدة وذلك عن طريق الأمر:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3987_34">
<span class="pln">sudo service php5-fpm restart</span></pre>

	<p>
		تأكد من أن الحوض يعمل بشكل صحيح وذلك بواسطة البحث عن عملياته كالتالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_53">
<span class="pln">ps aux |grep site1</span></pre>

	<p>
		إذا اتبعت التعليمات بدقة فستحصل على مخرجات مشابهة لهذه:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_55">
<span class="pln">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</span></pre>

	<p>
		بالإضافة إلى ذلك، سنعطل التخزين المؤقت الذي يوفره opcache، فهذا الأخير قد يُحسّن الأداء لكنه قد يتسبب في مشاكل أمنية.
	</p>

	<p>
		لتعطيله، عدل ملف<span style="font-family:courier new,courier,monospace;"> etc/php5/fpm/conf.d/05-opcache.ini/</span> باستخدام صلاحيات أعلى (super user) وأضف السطر التالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_57">
<span class="pln">opcache.enable=0</span></pre>

	<p>
		بعد ذلك أعد تشغيل php-fpm حتى تعمل الخيارات الجديدة:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_59">
<span class="pln">sudo service php5-fpm restart</span></pre>

	<h2>
		الخطوة الثانية - إعداد nginx
	</h2>
</div>

<div id="wmd-preview-section-15">
	<p>
		بعد أن انتهينا من إعداد حوض <span style="font-family:courier new,courier,monospace;">php-fpm</span> لموقعنا، سنقوم الآن بإعداد جزء الخادوم في nginx. ولذلك أنشئ ملفًا جديدًا وذلك باستخدام محررك المفضل كالتالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3987_20">
<span class="pln">sudo vim /etc/nginx/sites-available/site1</span></pre>

	<p>
		يجب أن يحتوي هذا الملف على:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3987_22">
<span class="pln">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;
    }
}</span></pre>

	<p>
		الشيفرة أعلاه تظهر إعدادات مشتركة لجزء الخادوم في nginx، لاحظ هذه الأجزاء:
	</p>

	<ul>
<li>
			جذر الويب (Web root) هو <span style="font-family:courier new,courier,monospace;">usr/share/nginx/sites/site1/</span>.
		</li>
		<li>
			اسم الخادوم يستخدم <span style="font-family:courier new,courier,monospace;">site1.example.org</span> التي ذكرناها في جزء المتطلبات الأساسية من هذا الدرس.
		</li>
		<li>
			يحدد <span style="font-family:courier new,courier,monospace;">fastcgi_pass </span>المتعامل (handler) لملفات php، يجب استخدام unix socket مختلفة لكل موقع مثل <span style="font-family:courier new,courier,monospace;">var/run/php5-fpm-site1.sock/</span>.
		</li>
	</ul>
<p>
		بعد ذلك أنشئ مجلد جذر الويب:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_47">
<span class="pln">sudo mkdir /usr/share/nginx/sites
sudo mkdir /usr/share/nginx/sites/site1</span></pre>

	<p>
		لتفعيل الموقع أعلاه تحتاج إلى إنشاء رابط رمزي (symlink) له في مجلد <span style="font-family:courier new,courier,monospace;">/etc/nginx/sites-enabled/</span>. يمكنك فعل ذلك باستعمال الأمر التالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_49">
<span class="pln">sudo ln -s /etc/nginx/sites-available/site1 /etc/nginx/sites-enabled/site1</span></pre>

	<p>
		في النهاية، أعد تشغيل nginx لتعمل التغييرات الجديدة كالتالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_51">
<span class="pln">sudo service nginx restart</span></pre>

	<h2>
		الخطوة الثالثة - التجارب
	</h2>
</div>

<div id="wmd-preview-section-16">
	<p>
		للتجارب، سنستخدم دالة <span style="font-family:courier new,courier,monospace;">phpinfo</span> والتي توفر لنا معلومات تفصيلية حول بيئة php.
	</p>

	<p>
		أنشئ ملفًا جديدًا باسم <span style="font-family:courier new,courier,monospace;">info.php</span> والذي يحتوي على سطر واحد فقط:
	</p>

	<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_3987_10">
<span class="pun">&lt;?</span><span class="pln">php phpinfo</span><span class="pun">();</span><span class="pln"> </span><span class="pun">?&gt;</span></pre>

	<p>
		ستحتاج هذا الملف في الموقع الافتراضي لـ nginx وفي جذر الويب <span style="font-family:courier new,courier,monospace;">/usr/share/nginx/html/</span>، ولهذا الغرض يمكنك استخدام محرر النّصوص كالتالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3987_12">
<span class="pln">sudo vim /usr/share/nginx/html/info.php</span></pre>

	<p>
		ثم انسخ الملف إلى جذر الويب للموقع الآخر (<span style="font-family:courier new,courier,monospace;">site1.example.org</span>) كالتالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3987_14">
<span class="pln">sudo cp /usr/share/nginx/html/info.php /usr/share/nginx/sites/site1/</span></pre>

	<p>
		أنت الآن مستعد لتشغيل أبسط اختبار للتأكد من مستخدم الخادوم، يمكنك إجراء الاختبار عن طريق متصفح أو من خلال طرفية خادوم و <span style="font-family:courier new,courier,monospace;">lynx</span> (متصفح يعمل عبر الطرفية)، وإذا لم تثبت <span style="font-family:courier new,courier,monospace;">lynx</span> سابقا في خادوم فيمكنك تثبيته بكل سهولة عن طريق الأمر:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3987_16">
<span class="pln"> sudo apt-get install lynx</span></pre>

	<p>
		تأكد أولا من وجود ملف <span style="font-family:courier new,courier,monospace;">info.php </span>في الموقع الافتراضي، ينبغي أن تتمكن من الوصول إليه عبر localhost كالتالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3987_18">
<span class="pln">lynx --dump http://localhost/info.php |grep 'SERVER\["USER"\]' </span></pre>

	<p>
		في الأمر السابق نرشح المخرجات باستخدام <span style="font-family:courier new,courier,monospace;">grep</span> لمتغير <span style="font-family:courier new,courier,monospace;">["SERVER["USER</span> فقط والذي يشير إلى مستخدم الخادوم، بالنسبة إلى الموقع الافتراضي يفترض أن تكون المخرجات تعرض مستخدم <span style="font-family:courier new,courier,monospace;">www-data</span> الافتراضي كالتالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_7">
<span class="pln">_SERVER["USER"]                 www-data</span></pre>

	<p>
		ونفس الشيء سنفعله للتأكد من مستخدم خادوم <span style="font-family:courier new,courier,monospace;">site1.example.org</span>:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_9">
<span class="pln">lynx --dump http://site1.example.org/info.php |grep 'SERVER\["USER"\]' </span></pre>

	<p>
		يجب أن ترى هذه المرة<span style="font-family:courier new,courier,monospace;"> site1</span> في المخرجات:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_11">
<span class="pln">_SERVER["USER"]                 site1</span></pre>

	<p>
		إذا قمت بعمل أية تخصيصات في إعدادات php في أحواض php-fpm الأساسية، فيمكنك أيضا التأكد من قيمهما بنفس الطريقة السابقة وذلك عن طريق ترشيح المخرجات التي تهمك.
	</p>

	<p>
		حتى الآن، عرفنا أن موقعينا يعملان تحت مستخدمين مختلفين، لكن لنرى الآن كيف يمكننا تأمين الاتصال، لتفسير المشكلة الأمنية التي نريد حلها في هذا المقال، سننشئ ملفًا يحتوي على معلومات حساسة، في العادة يحتوي هذا الملف معلومات الاتصال بقاعدة البيانات ويحتوي على تفاصيل اسم المستخدم وكلمة المرور لقاعدة بيانات المستخدم، فإذا وُجد أن أحدهم يستطيع الوصول إلى هذه المعلومات فسيتمكن من فعل أي شيء لموقعنا.
	</p>

	<p>
		أنشئ باستخدام محررك المفضل ملفًا جديدًا في موقعك الرئيسي يدعى<span style="font-family:courier new,courier,monospace;">usr/share/nginx/html/config.php/</span> ويحتوي على التالي:
	</p>

	<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_6994_13">
<span class="pun">&lt;?</span><span class="pln">php
$pass </span><span class="pun">=</span><span class="pln"> </span><span class="str">'secret'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">?&gt;</span></pre>

	<p>
		في الملف أعلاه عرّفنا متغيرًا يدعى <span style="font-family:courier new,courier,monospace;">pass</span> والذي يحتوي على قيمة <span style="font-family:courier new,courier,monospace;">secret</span>، وطبعا نريد تقييد الوصول إلى هذا الملف لذلك سنغير الصلاحيات إلى 400، والتي تعطي صلاحيات القراءة فقط لمالك الملف.
	</p>

	<p>
		لتغيير الصلاحيات إلى 400 نفذ الأمر التالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_15">
<span class="pln">sudo chmod 400 /usr/share/nginx/html/config.php</span></pre>

	<p>
		بالإضافة إلى ذلك موقعنا الرئيسي يعمل تحت مستخدم <span style="font-family:courier new,courier,monospace;">www-data</span> والذي يجب أن يكون قادرًا على قراءة هذا الملف، وبالتالي، غيّر ملكية الملف إلى ذاك المستخدم كالتالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_17">
<span class="pln">sudo chown www-data:www-data /usr/share/nginx/html/config.php</span></pre>

	<p>
		في مثالنا سنستخدم ملفًا آخر يدعى<span style="font-family:courier new,courier,monospace;"> usr/share/nginx/html/readfile.php/</span> لقراءة المعلومات السرية ومن ثم طباعتها، ويجب أن يحتوي هذا الملف على الشيفرة البرمجية التالية:
	</p>

	<pre class="ipsCode prettyprint lang-php prettyprinted" id="ips_uid_6994_19">
<span class="pun">&lt;?</span><span class="pln">php
include</span><span class="pun">(</span><span class="str">'/usr/share/nginx/html/config.php'</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln">$pass</span><span class="pun">);</span><span class="pln">
</span><span class="pun">?&gt;</span></pre>

	<p>
		بعد ذلك غيّر ملكية هذا الملف لمستخدم <span style="font-family:courier new,courier,monospace;">www-data</span> كالتالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_21">
<span class="pln">sudo chown www-data:www-data /usr/share/nginx/html/readfile.php</span></pre>

	<p>
		للتأكد من جميع الصلاحيات والملكيات في جذر ويب، نفّذ الأمر التالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_23">
<span class="pln">ls -l /usr/share/nginx/html/</span></pre>

	<p>
		يجب أن تكون المخرجات شبيهة بهذه:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_25">
<span class="pln">-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</span></pre>

	<p>
		الآن جرب الوصول إلى الملف السّابق على موقعك الافتراضي باستخدام الأمر:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_27">
<span class="pln">lynx --dump http://localhost/readfile.php</span></pre>

	<p>
		ستلاحظ أن <span style="font-family:courier new,courier,monospace;">secret</span> مطبوعة على الشاشة والتي تعني أن الملف مع المعلومات الحساسة يمكن الوصول إليه من داخل نفس الموقع، وهذا السلوك متوقع.
	</p>

	<p>
		الآن جرب نسخ ملف<span style="font-family:courier new,courier,monospace;"> usr/share/nginx/html/readfile.php/</span> إلى موقعك الثاني <span style="font-family:courier new,courier,monospace;">site1.example.org</span> كالتالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_29">
<span class="pln">sudo cp /usr/share/nginx/html/readfile.php /usr/share/nginx/sites/site1/</span></pre>

	<p>
		للحفاظ على علاقات الموقع/المستخدم، تأكد من أن الملفات داخل كل موقع مملوكة من طرف المستخدم المعني وذلك عن طريق تغيير ملكية الملف المنسوخ إلى <span style="font-family:courier new,courier,monospace;">site1</span> باستخدام الأمر التالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_31">
<span class="pln">sudo chown site1:site1 /usr/share/nginx/sites/site1/readfile.php</span></pre>

	<p>
		للتحقق من وضعك الصلاحيات والملكيات الصحيحة للملفات، اعرض قائمة محتويات جذر ويب <span style="font-family:courier new,courier,monospace;">site1</span> باستخدام الأمر:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_33">
<span class="pln">ls -l /usr/share/nginx/sites/site1/ </span></pre>

	<p>
		يجب أن ترى كالتالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_35">
<span class="pln">-rw-r--r-- 1 site1 site1  80 Jun 21 16:44 readfile.php</span></pre>

	<p>
		بعد ذلك حاول الوصول إلى نفس الملف من<span style="font-family:courier new,courier,monospace;"> site1.example.com</span> باستخدام الأمر:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_37">
<span class="pln">lynx --dump http://site1.example.org/readfile.php </span></pre>

	<p>
		سترى أنه تم إرجاع مساحة فارغة، وبالإضافة إلى ذلك، إذا بحثت عن الأخطاء في سجل الأخطاء لـ nginx باستخدام الأمر <span style="font-family:courier new,courier,monospace;">grep</span> التالي:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_39">
<span class="pln">sudo grep error /var/log/nginx/error.log </span></pre>

	<p>
		فسترى شيئا مشابها لهذا:
	</p>

	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6994_45">
<span class="pln">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</span></pre>

	<p>
		<strong>ملاحظة</strong>: سترى أيضا خطأ مشابهًا في مخرجات lynx إذا فعّلت خيار<span style="font-family:courier new,courier,monospace;"> display_errors </span>في إعدادات php-fpm في ملف <span style="font-family:courier new,courier,monospace;">etc/php5/fpm/php.ini/ </span>(بوضع On في ذلك الخيار). 
	</p>

	<p>
		يظهر التحذير أن السكربت من موقع <span style="font-family:courier new,courier,monospace;">site1.example.org</span> لا يمكنه قراءة الملف الحساس (<span style="font-family:courier new,courier,monospace;">config.php</span>) من الموقع الرئيسي وبالتالي، المواقع التي تعمل تحت عدة مستخدمين لا يمكنها تعريض أمن بقية المواقع.
	</p>

	<p>
		إذا ذهبت إلى نهاية جزء الإعدادات من هذا المقال، سترى أننا عطلنا التخزين المؤقت التي يوفرها opcache بشكل افتراضي، وإذا رغبت بمعرفة السبب حاول تفعيله مجددا وذلك عن طريق وضع <span style="font-family:courier new,courier,monospace;">opcache.enable=1</span> في ملف<span style="font-family:courier new,courier,monospace;">etc/php5/fpm/conf.d/05-opcache.ini/</span> عن طريق مستخدم <span style="font-family:courier new,courier,monospace;">sudo</span> ومن ثم إعادة تشغيل php5-fpm باستخدام الأمر <span style="font-family:courier new,courier,monospace;">sudo service php5-fpm restart</span>.
	</p>

	<p>
		ستجد أنه إذا قمت بإعادة خطوات الاختبار بنفس الترتيب فإنك ستتمكن من قراءة الملف الحساس على الرغم من صلاحياته وملكياته، وهذه المشكلة في opcache قد تم الإبلاغ عنها منذ فترة طويلة لكن لم يتم إصلاحها حتى وقت كتابة هذا المقال.
	</p>
</div>

<div id="wmd-preview-section-17">
	<h2 id="الخاتمة">
		الخاتمة
	</h2>

	<p>
		من الناحية الأمنية، يجب استخدام أحواض php-fpm مع مستخدم مختلف لكل موقع على نفس خادوم ويب nginx، فهذا الأمر حتى لو كان يضْعف الأداء قليلا، فإن ميزة عملية الفصل يمكنها منع خروق أمنية خطيرة.
	</p>

	<p>
		الفكرة التي شرحناها في هذا المقال ليست فريدة، وهي موجودة في تقنيات فصل PHP أخرى مثل SuPHP. وعلى الرغم من ذلك، أداء بقية البدائل أسوء من php-fpm.
	</p>

	<p>
		ترجمة -وبتصرف- للمقال: <a href="https://www.digitalocean.com/community/tutorials/how-to-host-multiple-websites-securely-with-nginx-and-php-fpm-on-ubuntu-14-04" rel="external nofollow">How To Host Multiple Websites Securely With Nginx And Php-fpm On Ubuntu 14.04</a> لصاحبه Anatoliy Dimitrov.
	</p>
</div>
]]></description><guid isPermaLink="false">251</guid><pubDate>Tue, 26 Apr 2016 08:58:18 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x625;&#x639;&#x62F;&#x627;&#x62F; &#x627;&#x633;&#x62A;&#x64A;&#x62B;&#x627;&#x642; &#x643;&#x644;&#x645;&#x629; &#x627;&#x644;&#x633;&#x631; &#x645;&#x639; &#x62E;&#x627;&#x62F;&#x648;&#x645; Nginx &#x639;&#x644;&#x649; Ubuntu</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A7%D8%B3%D8%AA%D9%8A%D8%AB%D8%A7%D9%82-%D9%83%D9%84%D9%85%D8%A9-%D8%A7%D9%84%D8%B3%D8%B1-%D9%85%D8%B9-%D8%AE%D8%A7%D8%AF%D9%88%D9%85-nginx-%D8%B9%D9%84%D9%89-ubuntu-r127/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_11/nginx-auth.png.e357e76f6889821a204da3377b974ffb.png" /></p>

<p dir="rtl">عند إعداد خادوم ويب توجد غالبًا أقسام من الموقع نرغب بتقييد الوصول إليها، تُوفِّر تطبيقات الويب عادةً طرق التصريح authorization والاستيثاق authentication الخاصّة بها، ولكن يُمكِن استخدام خادوم الويب بذاته لتقييد الوصول إن كانت هذه الطّرق غير كافية أو غير متوفّرة.</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/nginx-auth.png.83f7ee8a90d2da26dd8f3dc3a83b54ad.png"><img data-fileid="6589" class="ipsImage ipsImage_thumbnailed" alt="nginx-auth.thumb.png.beffa3706f5b103493e" src="https://academy.hsoub.com/uploads/monthly_2015_11/nginx-auth.thumb.png.beffa3706f5b103493eefbdd99e8c1c1.png"></a></p><p dir="rtl">سنشرح في هذا الدّرس كيف نحمي الممتلكات assets باستخدام كلمة سر على خادوم ويب Nginx يعمل على Ubuntu.</p><h2 dir="rtl">المتطلبات الأساسية</h2><p dir="rtl">نحتاج للوصول إلى بيئة خادوم Ubuntu لكي نبدأ، نحتاج أيضًا لمستخدم غير جذري non-root مع صلاحيّات sudo من أجل تنفيذ مهام إداريّة administrative، لكي تتعلّم كيفيّة إعداد مستخدم بامتيازات sudo اتبع دليلنا للإعداد الأولي لخادوم Ubuntu 14.04.</p><p dir="rtl">إن لم نقم مُسبقًا بتثبيت Nginx نستطيع تثبيته على جهازنا بكتابة ما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo apt-get update
sudo apt-get install nginx</pre><h2 dir="rtl">إنشاء ملف كلمات السر</h2><p dir="rtl">للبدء نحتاج لإنشاء الملف الذي سيحمل تركيبات أسماء المستخدمين وكلمات السّر، نستطيع فعل ذلك باستخدام أدوات OpenSSL المساعدة التي ربّما تكون متوفّرة مُسبقًا على خادومنا، وبشكلٍ بديل نستطيع استخدام الأداة المساعدة <span style="font-family:courier new,courier,monospace;">htpasswd</span> المُصمّمة لهذا الغرض والمُضمّنة في الحِزمة <span style="font-family:courier new,courier,monospace;">apache2-utils </span>(تستخدم ملفّات كلمات سر Nginx نفس الصّيغة التي تستخدمها Apache)، بإمكانك اختيار الطّريقة التي تفضّلها.</p><h3 dir="rtl">إنشاء ملف كلمات السر باستخدام أدوات OpenSSL المساعدة</h3><p dir="rtl">إن كُنّا نملك OpenSSL مُثبتًا على خادومنا فبإمكاننا إنشاء ملف كلمات سر بدون أي حِزَم إضافيّة.</p><p dir="rtl">سنقوم بإنشاء ملف مخفي يُدعى <span style="font-family:courier new,courier,monospace;">htpasswd.</span> في دليل الإعدادات<span style="font-family:courier new,courier,monospace;"> etc/nginx/</span> لتخزين تركيبات أسماء المستخدمين وكلمات السّر.</p><p dir="rtl">نستطيع إضافة اسم مستخدم إلى هذا الملف باستخدام هذا الأمر، سنختار الاسم sammy ليكون اسم مستخدم لدينا، ولكن تستطيع استخدام أي اسم ترغب به:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo sh -c "echo -n 'sammy:' &gt;&gt; /etc/nginx/.htpasswd"</pre><p dir="rtl">سنقوم بعد ذلك بإضافة كلمة سر مُشفّرة encrypted لاسم المستخدم بكتابة ما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo sh -c "openssl passwd -apr1 &gt;&gt; /etc/nginx/.htpasswd"</pre><p dir="rtl">نستطيع إعادة هذه العمليّة من أجل أسماء مستخدمين آخرين، وبإمكاننا أن نرى كيف يتم تخزين أسماء المستخدمين وكلمات السّر المُشفّرة داخل الملف بكتابة ما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">cat /etc/nginx/.htpasswd
</pre><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sammy:$apr1$wI1/T0nB$jEKuTJHkTOOWkopnXqC1d1</pre><h3 dir="rtl">إنشاء ملف كلمات السر باستخدام الأدوات المساعدة لـ Apache</h3><p dir="rtl">في حين أنّ OpenSSL تستطيع تشفير كلمات السّر من أجل استيثاق Nginx، يجد معظم المستخدمين أنّه من الأسهل استخدام أداة مُساعِدة مبنيّة لهذا الغرض، تقوم الأداة المُساعِدة <span style="font-family:courier new,courier,monospace;">htpasswd</span> الموجودة في الحزمة <span style="font-family:courier new,courier,monospace;">apache2-utils</span> بتخديم هذا الأمر بشكل جيّد.</p><p dir="rtl">نُثبِّت الحِزمة <span style="font-family:courier new,courier,monospace;">apache2-utils</span> على خادومنا بكتابة ما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo apt-get update
sudo apt-get install apache2-utils</pre><p dir="rtl">والآن بعد أن أصبح بإمكاننا الوصول للأمر <span style="font-family:courier new,courier,monospace;">htpasswd</span> نستطيع استخدامه لإنشاء ملف كلمات السّر الذي يستخدمه خادوم Nginx من أجل استيثاق المستخدمين، سنقوم بإنشاء ملف مخفي لهذا الغرض يُدعى <span style="font-family:courier new,courier,monospace;">htpasswd.</span> بداخل دليل الإعدادات <span style="font-family:courier new,courier,monospace;">etc/nginx/</span>.</p><p dir="rtl">عند استخدام هذه الأداة لأوّل مرّة نحتاج لإضافة الخيار <span style="font-family:courier new,courier,monospace;">c-</span> لإنشاء الملف المُحدَّد، نقوم بتحديد اسم مستخدم (في هذا المثال sammy) في نهاية الأمر لإنشاء مُدخَل جديد بداخل الملف:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo htpasswd -c /etc/nginx/.htpasswd sammy</pre><p dir="rtl">سيتم سؤالنا عن تزويد كلمة سر وتأكيدها للمستخدم.</p><p dir="rtl">نترك الوسيط <span style="font-family: 'courier new', courier, monospace; line-height: 24.8889px;">c- </span>لأي مستخدمين آخرين نرغب في إضافتهم:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo htpasswd /etc/nginx/.htpasswd another_user</pre><p dir="rtl">إن قمنا بمشاهدة محتويات الملف نستطيع رؤية اسم المستخدم وكلمة السّر المُشفّرة لكل تسجيل record:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">cat /etc/nginx/.htpasswd</pre><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sammy:$apr1$lzxsIfXG$tmCvCfb49vpPFwKGVsuYz.
another_user:$apr1$p1E9MeAf$kiAhneUwr.MhAE2kKGYHK.</pre><h2 dir="rtl">إعداد استيثاق كلمة السر لخادوم Nginx</h2><p dir="rtl">الآن وبعد أن أصبحنا نمتلك ملف لأسماء المستخدمين وكلمات السّر في صيغة يستطيع خادوم Nginx قراءتها، نحتاج لإعداد Nginx لكي يتفحّص هذا الملف قبل تخديم محتوانا المحمي.</p><p dir="rtl">نبدأ بفتح ملف إعدادات الحجب للخادوم والذي نرغب في إضافة تقييد restriction له، سنستخدم في مثالنا هذا ملف الخادوم الافتراضي default للحجب والمُثبَّت عبر حزمة Nginx في Ubuntu:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo nano /etc/nginx/sites-enabled/default</pre><p dir="rtl">ينبغي أن يبدو المحتوى داخل الملف مُشابِهًا لما يلي بعد إزالة التّعليقات:</p><p><strong>/etc/nginx/sites-enabled/default</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">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;
    }
}</pre><p dir="rtl">نحتاج لإعداد الاستيثاق أن نقرّر السياق context الذي نريد تقييده، يسمح لنا Nginx من بين الخيارات الأخرى بتعيين التقييد على مستوى الخادوم أو بداخل موقع مُحدَّد، سنقوم في مثالنا بتقييد كامل المستند root بحجب على المكان، ولكن بإمكانك تعديل هذه القائمة لكي تستهدف فقط دليل مُحدَّد ضمن مجال الويب.</p><p dir="rtl">نستخدم ضمن هذا الحجب على المكان الأمر التوجيهي <span style="font-family:courier new,courier,monospace;">auth_basic</span> لتشغيل الاستيثاق واختيار اسم نطاق ليتم عرضه للمستخدم عند المطالبة بالاعتمادات credentials، سنستخدم الأمر التوجيهي <span style="font-family:courier new,courier,monospace;">auth_basic_user_file</span> لكي يشير لخادوم Nginx إلى ملف كلمات السّر الذي أنشأناه:</p><p><strong>/etc/nginx/sites-enabled/default</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">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;
        auth_basic "Restricted Content";
        auth_basic_user_file /etc/nginx/.htpasswd;
    }
}</pre><p dir="rtl">بعد أن ننتهي نحفظ ونغلق الملف، نعيد تشغيل خادوم Nginx لتنفيذ سياسة policy كلمات السّر لدينا:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo service nginx restart</pre><p dir="rtl">يجب أن يكون الدليل الذي حددناه محميًّا الآن بكلمة سر.</p><h2 dir="rtl">تأكيد استيثاق كلمة السر</h2><p dir="rtl">للتأكّد من أنّ المحتوى محمي لدينا نُجرِّب النفاذ إلى المحتوى المُقيَّد من متصفّح إنترنت، يجب أن يتم عرض مُحث prompt لاسم المستخدم وكلمة السّر يُشبه ما يلي:</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/pic1.png.861cdb9414196e3ac5570e733e73b76e.png"><img data-fileid="6550" class="ipsImage ipsImage_thumbnailed" alt="pic1.thumb.png.7ab81b21167534040ec251310" src="https://academy.hsoub.com/uploads/monthly_2015_11/pic1.thumb.png.7ab81b21167534040ec251310d7f156e.png"></a></p><p dir="rtl">إن أدخلنا الاعتمادات الصحيحة سيتم السماح لنا بالنفاذ إلى المحتوى، وإن أدخلنا الاعتمادات الخاطئة أو ضغطنا على إلغاء Cancel سنشاهد صفحة الخطأ "Authorization Required":</p><p dir="rtl" style="text-align: center;"><a rel="external nofollow" name="_GoBack"></a><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/pic2.png.57b5554d476ad3d1c6497ba5cc3dd4f4.png"><img data-fileid="6551" class="ipsImage ipsImage_thumbnailed" alt="pic2.thumb.png.0d9ecfa4b3e2cfaa6ed71e043" src="https://academy.hsoub.com/uploads/monthly_2015_11/pic2.thumb.png.0d9ecfa4b3e2cfaa6ed71e04397c0bd6.png"></a></p><h2 dir="rtl">الخاتمة</h2><p dir="rtl">يجب أن يكون لدينا الآن كل ما نحتاجه لإعداد استيثاق أساسي لموقعنا، فلنضع في اعتبارنا أنّ حماية كلمة السّر يجب أن تكون جنبًا إلى جنب مع تشفير SSL كي لا يتم إرسال اعتماداتنا إلى الخادوم في شكل نص مُجرَّد plain text، يمكنك الإطلاع أيضا على <a href="https://academy.hsoub.com/devops/web-servers/nginx/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%B4%D9%87%D8%A7%D8%AF%D8%A9-ssl-%D9%84%D8%AE%D8%A7%D8%AF%D9%88%D9%85-nginx-%D8%B9%D9%84%D9%89-ubuntu-1404-r105/">كيفيّة إنشاء شهادة SSL موقّعة ذاتيًّا لاستخدامها مع Nginx</a>.</p><p dir="rtl">ترجمة -وبتصرّف- للمقال: <a rel="external nofollow" href="https://www.digitalocean.com/community/tutorials/how-to-set-up-password-authentication-with-nginx-on-ubuntu-14-04">How To Set Up Password Authentication with Nginx on Ubuntu 14.04</a> لصاحبه Justin Ellingwood.</p><p dir="rtl">حقوق الصورة البارزة: <a href="http://www.freepik.com/free-vector/laptop-security-vector-image_715008.htm" rel="external nofollow">Designed by Freepik</a>.</p>
]]></description><guid isPermaLink="false">127</guid><pubDate>Mon, 02 Nov 2015 22:57:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x62D;&#x645;&#x627;&#x64A;&#x629; &#x62E;&#x627;&#x62F;&#x648;&#x645; Nginx &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Fail2Ban &#x639;&#x644;&#x649; Ubuntu</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AD%D9%85%D8%A7%D9%8A%D8%A9-%D8%AE%D8%A7%D8%AF%D9%88%D9%85-nginx-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-fail2ban-%D8%B9%D9%84%D9%89-ubuntu-r124/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_10/fail2ban-nginx.png.e64e556034c88ce214b4ff7db64446d2.png" /></p>

<p dir="rtl">من المهم عند العمل على خادوم ويب تنفيذ تدابير أمنيّة لحماية موقعنا ومستخدمينا، إنّ حماية مواقع الإنترنت والتّطبيقات لدينا باستخدام سياسات الجّدار النّاري firewall policies وتقييد الوصول إلى بعض المناطق باستخدام استيثاق كلمة السّر password authentication هو نقطة بدء رائعة لتأمين النظام لدينا، ومع ذلك من المُرجَّح أن يجذب أي طلب لكلمة السّر مُتاح للعوام محاولات القوة القاسية brute force من قبل المستخدمين والروبوتات bots الخبيثين.</p><p dir="rtl" style="text-align: center;"><a href="https://academy.hsoub.com/uploads/monthly_2015_10/fail2ban-nginx.png.bbc8b9cce74f7a4cdac736c3715711fe.png" class="ipsAttachLink ipsAttachLink_image"><img data-fileid="6252" src="https://academy.hsoub.com/uploads/monthly_2015_10/fail2ban-nginx.thumb.png.b5ee4b114e5ad7d4ca9c0c57bf43831b.png" class="ipsImage ipsImage_thumbnailed" alt="fail2ban-nginx.thumb.png.b5ee4b114e5ad7d"></a></p><p dir="rtl">يتمكّن إعداد <strong>fail2ban</strong> من المساعدة في الحد من هذه المشكلة، فعندما يفشل المستخدمون بالاستيثاق إلى خدمة ما بشكلٍ متكرّر (أو الانخراط في أي نشاط مشبوه آخر) تستطيع fail2ban أن تصدر حظرًا مؤقّتًا على عنوان IP المُهاجِم عن طريق التّعديل بشكل ديناميكي على سياسة الجّدار النّاري التي تعمل حاليًّا. تعمل كل "jail" تابعة لـ fail2ban عن طريق تفحّص السّجلّات المكتوبة من قبل خدمة ما بحثًا عن أنماط patterns تُشير إلى محاولات فاشلة بالاستيثاق. من السّهل إلى حدٍّ ما إعداد fail2ban لكي تراقب سجلّات Nginx باستخدام البعض من مُرشّحات filters الإعداد المُضمَّنة والبعض الآخر الذي سنقوم بكتابته بأنفسنا.</p><p dir="rtl">سنشرح في هذا الدّرس كيفيّة تثبيت fail2ban وإعدادها لمراقبة سجلّات Nginx بحثًا عن محاولات التّسلّل، سنستخدم خادوم Ubuntu من أجل هذا.</p><h2 dir="rtl">المتطلبات الأساسية</h2><p dir="rtl">ينبغي قبل أن نبدأ أن نمتلك خادوم Ubuntu مع إعداد حساب غير جذري non-root، ويجب أن يكون هذا الحساب مُعدًّا بامتيازات <span style="font-family:courier new,courier,monospace;">sudo</span> من أجل إصدار أوامر إداريّة administrative commands. لكي تتعلّم كيفيّة إعداد مستخدم بامتيازات <span style="font-family:courier new,courier,monospace;">sudo</span> اتبع دليلنا للإعداد الأولي لخادوم Ubuntu 14.04.</p><h2 dir="rtl">تثبيت Nginx وإعداد استيثاق كلمة السر</h2><p dir="rtl">إن كنتَ مهتمًّا بحماية خادوم Nginx باستخدام fail2ban فمن الغالب أنك تملك مسبقًا خادومًا مُعدًّا وقيد التشغيل، وإن لم تكن كذلك تستطيع تثبيت Nginx من خلال مستودعات Ubuntu الافتراضيّة باستخدام <span style="font-family:courier new,courier,monospace;">apt</span>.</p><p dir="rtl">فلنقم بتحديث دليل الحِزَم المحلّي وتثبيت Nginx بكتابة ما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo apt-get update

sudo apt-get install nginx</pre><p dir="rtl">إنّ خدمة fail2ban مفيدة من أجل حماية نقاط تسجيل الدخول، ومن أجل أن يكون هذا مفيدًا لتثبيت Nginx يجب تنفيذ استيثاق كلمة السّر على الأقل لمجموعة فرعيّة من المحتوى على الخادوم، تستطيع اتباع هذا الدّليل لإعداد حماية كلمة السّر من أجل خادوم Nginx لديك.</p><h2 dir="rtl">تثبيت Fail2Ban</h2><p dir="rtl">بعد أن أصبح خادوم Nginx لدينا قيد التّشغيل وتمّ تمكين استيثاق كلمة السّر عليه نستطيع المضي قدمًا وتثبيت fail2ban (نقوم هنا بإدراج إعادة جلب للمستودع مرّة أخرى في حال قمتَ بالفعل بتثبيت Nginx في الخطوات السّابقة):</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo apt-get update

sudo apt-get install fail2ban</pre><p dir="rtl">سيقوم هذا بتثبيت برمجيّة fail2ban، والتي هي مُعدَّة افتراضيًّا لكي تحظر فقط محاولات تسجيل دخول SSH الفاشلة، نحتاج إلى تمكين بعض القواعد التي تقوم بإعدادها لكي تتفحّص سجلّات Nginx لدينا بحثًا عن أنماط تشير إلى نشاط خبيث.</p><h2 dir="rtl">ضبط الإعدادات العامة داخل Fail2Ban</h2><p dir="rtl">نحتاج لكي نبدأ إلى ضبط ملف الإعدادات الذي تستخدمه fail2ban لتحديد سجلّات التطبيقات التي يجب أن تراقبها والإجراءات التي يجب أن يتمّ اتخاذها عند إيجاد مُدخلات مُخالِفة، ومن الموارد الرئيسيّة التي يتم تزويدنا بها لهذا الأمر نجد الملف <span style="font-family:courier new,courier,monospace;">etc/fail2ban/jail.conf/</span>.</p><p dir="rtl">ولإجراء التعديلات نحتاج إلى نسخ هذا الملف إلى <span style="font-family:courier new,courier,monospace;">etc/fail2ban/jail.local/</span>، وهذا يمنع الكتابة فوق التغييرات التي أجريناها إن قام تحديث الحِزمة package بتزويدنا بملف جديد افتراضي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local</pre><p dir="rtl">نقوم بفتح الملف الجديد المنسوخ حتى نستطيع إعداد مراقبة سجلّات Nginx لدينا:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo nano /etc/fail2ban/jail.local</pre><h3 dir="rtl">تغيير الإعدادات الافتراضية</h3><p dir="rtl">ينبغي أن نبدأ بتقييم المجموعة الافتراضيّة داخل الملف لنرى إن كانت تُلائِم احتياجاتنا، نستطيع إيجاد هذه المجموعة تحت قسم<strong> [DEFAULT] </strong>داخل الملف. تقوم هذه العناصر بتعيين السّياسة policy العامّة وبإمكاننا تجاوز أي منها في jails مُحدّدة.</p><p dir="rtl">ومن أوائل العناصر التي يجب أن ننظر إليها هي قائمة العُمَلاء Clients التي لا تخضع لسياسات fail2ban، ويتم تعيينها باستخدام الأمر التّوجيهي <span style="font-family:courier new,courier,monospace;">ignoreip</span>، من الجّيد أحيانًا إضافة عنوان IP الخاص بنا أو بشبكتنا إلى قائمة الاستثناءات لتجنّب حظر أنفسنا، على الرّغم من أنّ هذا أقل من أن يكون مشكلة مع تسجيلات الدّخول إلى خادوم الويب إن كان بإمكاننا المحافظة على النفاذ للـ Shell، حيث أنّنا دائمًا نستطيع إلغاء الحظر يدويًّا. نستطيع إضافة عناوين IP أو شبكات إضافيّة بفصلها بمسافة Space إلى القائمة الحاليّة:</p><p style="text-align: left;"><strong>etc/fail2ban/jail.local/</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">[DEFAULT]

. . .
ignoreip = 127.0.0.1/8 your_home_IP</pre><p dir="rtl">ومن العناصر الأخرى التي قد نرغب بضبطها نجد <span style="font-family:courier new,courier,monospace;">bantime</span> والذي يتحكّم بعدد الثّواني التي سيتم خلالها حظر العضو المُخالِف، من المثالي تعيينه إلى مدّة طويلة كافية لتكون مُدمِّرة لجهود المستخدم الخبيث، وفي نفس الوقت قصيرة بما فيه الكفاية لتسمح للمستخدمين الشرعيّين لتصحيح أخطائهم، يتم تعيين هذه القيمة افتراضيًّا إلى 600 ثانية (10 دقائق)، قم بزيادتها أو إنقاصها على النحو الذي تراه مناسبًا:</p><p style="text-align: left;"><strong>etc/fail2ban/jail.local/</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">[DEFAULT]

. . .
bantime = 3600</pre><p dir="rtl">يُحدّد العنصران التّاليان نطاق أسطر السّجلّات المستخدمة لتحديد العميل المُخالِف، يُحدِّد <span style="font-family:courier new,courier,monospace;">findtime</span> المدّة الزمنية مُقدّرةً بالثواني ويُشير الأمر التّوجيهي <span style="font-family:courier new,courier,monospace;">maxretry</span> إلى عدد المحاولات التي يتم التسامح معها خلال تلك المدّة، فإن قام العميل بعدد محاولات أكثر من <span style="font-family:courier new,courier,monospace;">maxretry</span> خلال المدّة الزمنيّة المُحدّدة بواسطة <span style="font-family:courier new,courier,monospace;">findtime</span> فسيتمّ حظره:</p><p style="text-align: left;"><strong>etc/fail2ban/jail.local/</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">[DEFAULT]

. . .
findtime = 3600 # These lines combine to ban clients that fail
maxretry = 6    # to authenticate 6 times within a half hour</pre><h3 dir="rtl">إعداد تنبيهات البريد الإلكتروني (اختياري)</h3><p dir="rtl">نستطيع تمكين تنبيهات البريد الإلكتروني إن كُنّا نرغب باستقبال بريد كلّما حدث حظر، ويتوجب علينا أولًا لفعل هذا أن نقوم بإعداد <strong>MTA </strong>على خادومنا بحيث يستطيع إرسال بريد إلكتروني، لتتعلّم كيفيّة استخدام <span style="font-family:courier new,courier,monospace;">Postfix</span> من أجل هذه المهمّة اتبع هذا الدّليل.</p><p dir="rtl">ويتوجّب علينا بعد الانتهاء من إعداد MTA أن نقوم بضبط بعض الإعدادات الإضافيّة داخل القسم<strong> [DEFAULT]</strong> من الملف <span style="font-family:courier new,courier,monospace;">etc/fail2ban/jail.local/</span>. نبدأ بإعداد الأمر التّوجيهي mta، فإن قمنا بإعداد <span style="font-family:courier new,courier,monospace;">Postfix -</span>كما هو واضح في الدّرس التعليمي المذكور بالأعلى- نُغيّر هذه القيمة إلى “mail”:</p><p style="text-align: left;"><strong>etc/fail2ban/jail.local/</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">[DEFAULT]

. . .
mta = mail</pre><p dir="rtl">يجب أن نختار عنوان البريد الإلكتروني الذي سيتم إرسال التنبيهات إليه ونكتبه داخل الأمر التّوجيهي <span style="font-family:courier new,courier,monospace;">destemail</span>، بإمكاننا استخدام الأمر التّوجيهي <span style="font-family:courier new,courier,monospace;">sendername</span> لتعديل حقل المُرسِل <span style="font-family:courier new,courier,monospace;">Sender</span> في تنبيهات البريد الإلكتروني:</p><p style="text-align: left;"><strong>etc/fail2ban/jail.local/</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">[DEFAULT]

. . .
destemail = youraccount@email.com
sendername = Fail2BanAlerts</pre><p dir="rtl">إنّ الإجراء <span style="font-family:courier new,courier,monospace;">action</span> -بحسب تعبير fail2ban- هو العمليّة التي تتلو فشل العميل بالاستيثاق مرات كثيرة، الإجراء الافتراضي (يُدعى <span style="font-family:courier new,courier,monospace;">action_</span>) هو ببساطة حظر عنوان الـ IP من المنفذ port قيد الطلب، ويوجد على أيّة حال إجراءان آخران مُعدّان مُسبقًا يُمكن استخدامهما إن كنّا نملك إعداد بريد إلكتروني.</p><p dir="rtl">نستطيع استخدام الإجراء <span style="font-family:courier new,courier,monospace;">action_mw</span> لحظر العميل وإرسال تنبيه بريد إلكتروني إلى الحساب المضبوط لدينا مع تقرير “whois” حول عنوان المُخالِف، بإمكاننا أيضًا استخدام الإجراء <span style="font-family:courier new,courier,monospace;">action_mwl</span> والذي يقوم بنفس العمل ولكن يقوم بتضمين سطور سجلّات المُخالِف والتي قامت بإطلاق عمليّة الحظر:</p><p style="text-align: left;"><strong>etc/fail2ban/jail.local/</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">[DEFAULT]

. . .
action = %(action_mwl)s
</pre><h2 dir="rtl">إعداد Fail2Ban لمراقبة سجلات Nginx</h2><p dir="rtl">بعد أن قمنا بضبط بعض إعدادات fail2ban العامّة في مكانها الصحيح نستطيع التركيز على تمكين بعض jails المرتبطة بـ Nginx والتي ستراقب سجلّات خادوم الويب لدينا بحثًا عن أنماط سلوك مُعيّن.</p><p dir="rtl">تتميّز كل jails داخل ملف الإعدادات بترويسة header تحتوي اسم الـ jail بين قوسين مربّعين (كل قسم يشير إلى إعدادات jail مُحدّدة ما عدا القسم <strong>[DEFAULT]</strong>)، وافتراضيًّا نجد <strong>ssh]</strong> jail<strong>]</strong> هي الوحيدة المُمكّنة.</p><p dir="rtl">لتمكين مراقبة السّجلّات بحثًا عن محاولات تسجيل دخول Nginx سنقوم بتمكين <strong>[</strong>jail <strong>[nginx-http-auth</strong>، نُعدّل الأمر التّوجيهي enabled داخل هذا القسم بحيث يصبح true:</p><p style="text-align: left;"><strong>etc/fail2ban/jail.local/</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">[nginx-http-auth]

enabled = true
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx/error.log
. . .</pre><p dir="rtl">إنّ jail السّابقة هي jail الوحيدة الخاصّة بـ Nginx التي يتم تضمينها مع حزمة fail2ban الخاصّة بـ Ubuntu. نستطيع على أيّة حال إنشاء jails الخاصّة بنا لإضافة وظائف إضافيّة، نجد في هذا الرابط بعض من تفاصيل تنفيذ jails الإضافيّة هنا وهنا.</p><p dir="rtl">بإمكاننا إنشاء <strong>nginx-noscript]</strong> jail<strong>]</strong> لحظر العملاء الذين يبحثون عن تنفيذ واستغلال Script على الموقع، إن لم نكن نستخدم PHP أو أي لغة برمجة أخرى بالتزامن مع خادوم الويب لدينا فبإمكاننا إضافة هذه الـ jail لحظر من يطلب هذا النوع من الموارد:</p><p style="text-align: left;"><strong>etc/fail2ban/jail.local/</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">[nginx-noscript]

enabled = true
port = http,https
filter = nginx-noscript
logpath = /var/log/nginx/access.log
maxretry = 6
. . .</pre><p dir="rtl">نستطيع إضافة قسم يُدعى<strong> [nginx-badbots] </strong>لإيقاف بعض أنماط طلبات الروبوتات الخبيثة المعروفة:</p><p style="text-align: left;"><strong>etc/fail2ban/jail.local/</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">[nginx-badbots]

enabled = true
port = http,https
filter = nginx-badbots
logpath = /var/log/nginx/access.log
maxretry = 2</pre><p>وإن لم نكن نستخدم Nginx لتزويدنا بالنفاذ إلى محتوى الويب داخل الدّليل الرئيسي Home directory للمستخدم فبإمكاننا حظر المستخدمين الذين يطلبون هذه الموارد بإضافة <strong>nginx-nohome]</strong> jail<strong>]</strong>:</p><p style="text-align: left;"><strong>etc/fail2ban/jail.local/</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">[nginx-nohome]

enabled = true
port = http,https
filter = nginx-nohome
logpath = /var/log/nginx/access.log
maxretry = 2</pre><p dir="rtl">ينبغي علينا حظر العملاء الذين يحاولون استخدام خادوم Nginx لدينا كوسيط مفتوح open proxy، نستطيع إضافة <strong>nginx-noproxy]</strong> jail<strong>] </strong>لتتناسب مع هذه الطلبات:</p><p style="text-align: left;"><strong>etc/fail2ban/jail.local/</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">[nginx-noproxy]

enabled = true
port = http,https
filter = nginx-noproxy
logpath = /var/log/nginx/access.log
maxretry = 2</pre><p dir="rtl">بعد أن ننتهي من التعديلات التي نرغب بها نحفظ الملف ونغلقه، يتوجّب علينا الآن إضافة المُرشّحات filters من أجل jails التي قمنا بإنشائها.</p><h2 dir="rtl">إضافة المرشحات من أجل Nginx Jails الإضافية</h2><p dir="rtl">لقد قمنا بتحديث الملف <span style="font-family:courier new,courier,monospace;">etc/fail2ban/jail.local/</span> ببعض مواصفات jail الإضافيّة لتتناسب مع حظر مدى كبير من السّلوك السّيء، نحتاج لإنشاء ملفات ترشيح filter من أجل jails التي أنشأناها، حيث تُحدّد هذه الملفات الأنماط التي سنبحث عنها داخل سجلّات Nginx.</p><p dir="rtl">فلنبدأ بالانتقال إلى دليل المُرشّحات filters:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">cd /etc/fail2ban/filter.d</pre><p dir="rtl">نريد فعليًّا أن نبدأ بضبط مُرشِّح الاستيثاق المزوّد مُسبقًا مع Nginx لكي يتناسب مع أنماط فشل تسجيل الدّخول الموجودة في السّجلّات، نفتح الملف لتحريره:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo nano nginx-http-auth.conf</pre><p dir="rtl">نُضيف نمط جديد تحت التّخصيص failregex، حيث يتناسب هذا النّمط مع الأسطر التي توافق عدم إدخال المستخدم لاسم مستخدم أو كلمة سر:</p><p style="text-align: left;"><strong>etc/fail2ban/filter.d/nginx-http-auth.conf/</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">[Definition]

failregex = ^ \[error\] \d+#\d+: \*\d+ user "\S+":? (password mismatch|was not found in ".*"), client: &lt;HOST&gt;, server: \S+, request: "\S+ \S+ HTTP/\d+\.\d+", host: "\S+"\s*$
            ^ \[error\] \d+#\d+: \*\d+ no user/password was provided for basic authentication, client: &lt;HOST&gt;, server: \S+, request: "\S+ \S+ HTTP/\d+\.\d+", host: "\S+"\s*$

ignoreregex =</pre><p dir="rtl">بعد الانتهاء نقوم بحفظ وإغلاق الملف.</p><p dir="rtl">بعد ذلك نستطيع نسخ الملف <span style="font-family:courier new,courier,monospace;">apache-badbots.conf</span> لاستخدامه مع Nginx، بإمكاننا استخدام الملف كما هو ولكن سنقوم بنسخه إلى اسم آخر من أجل التوضيح، يتطابق هذا مع مرجعيّة المُرشّح التي قمنا بها داخل إعدادات jail:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo cp apache-badbots.conf nginx-badbots.conf</pre><p dir="rtl">ننشئ بعد ذلك مُرشّح من أجل <strong>nginx-noscript]</strong> jail<strong>]</strong>:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo nano nginx-noscript.conf</pre><p dir="rtl">نلصق التعريف التالي بداخله، ونترك لك الخيار في ضبط اللواحق في الـ Script لكي تزيل ملفّات لغات البرمجة التي يستخدمها الخادوم لديك بشكل شرعي أو لكي تضيف لواحق أخرى:</p><p style="text-align: left;"><strong>etc/fail2ban/filter.d/nginx-noscript.conf/</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">[Definition]

failregex = ^&lt;HOST&gt; -.*GET.*(\.php|\.asp|\.exe|\.pl|\.cgi|\.scgi)

ignoreregex =</pre><p dir="rtl">نقوم بحفظ الملف وإغلاقه.</p><p dir="rtl">ننشئ بعد ذلك مُرشّحًا من أجل <strong>nginx-nohome]</strong> jail<strong>]</strong>:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo nano nginx-nohome.conf</pre><p dir="rtl">نضع معلومات المرشّح التالية في الملف:</p><p style="text-align: left;"><strong>etc/fail2ban/filter.d/nginx-nohome.conf/</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">[Definition]

failregex = ^&lt;HOST&gt; -.*GET .*/~.*

ignoreregex =</pre><p dir="rtl">بعد الانتهاء نقوم بحفظ وإغلاق الملف.</p><p dir="rtl">بإمكاننا أخيرًا إنشاء المرشّح من أجل <strong>nginx-noproxy]</strong> jail<strong>]</strong>:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo nano nginx-noproxy.conf</pre><p dir="rtl">يتوافق تعريف المرشّح مع محاولات استخدام خادومنا كوسيط proxy:</p><p style="text-align: left;"><strong>etc/fail2ban/filter.d/nginx-noproxy.conf/</strong></p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">[Definition]

failregex = ^&lt;HOST&gt; -.*GET http.*

ignoreregex =</pre><p dir="rtl">بعد الانتهاء نقوم بحفظ وإغلاق الملف.</p><h2 dir="rtl">تفعيل Nginx Jails لدينا</h2><p dir="rtl">لكي يتم تنفيذ تغييراتنا على الإعدادات نحتاج إلى إعادة تشغيل خدمة fail2ban، نستطيع فعل ذلك بكتابة ما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo service fail2ban restart</pre><p>ينبغي أن يتم إعادة تشغيل الخدمة وتنفيذ سياسات الحظر المختلفة التي قمنا بإعدادها.</p><h2 dir="rtl">الحصول على معلومات حول Jails التي تم تمكينها</h2><p dir="rtl">نستطيع رؤية جميع jails التي تمّ تمكينها لدينا باستخدام الأمر <span style="font-family:courier new,courier,monospace;">fail2ban-client</span>:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo fail2ban-client status</pre><p dir="rtl">ينبغي أن نشاهد قائمة بكامل jails التي قمنا بتمكينها:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">Status
|- Number of jail: 6
<span style="line-height: 24.8889px;">`</span>- Jail list: nginx-noproxy, nginx-noscript, nginx-nohome, nginx-http-auth, nginx-badbots, ssh</pre><p dir="rtl">نستطيع النظر إلى <strong>iptables</strong> لكي نرى أنّ fail2ban قامت بتعديل قواعد الجّدار النّاري لدينا لإنشاء إطار عمل لمنع العملاء، وحتى بدون قواعد الجّدار النّاري السابقة سيكون لدينا الآن إطار عمل مُمكّن يسمح لـ fail2ban بحظر العملاء انتقائيًّا عن طريق إضافتهم إلى سلاسل chains مبنيّة لهذا الغرض:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo iptables -S</pre><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">-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</pre><p dir="rtl">وإن أردنا رؤية تفاصيل حظر مُطبَّق من قبل أي jail فمن الأسهل ربّما استخدام الأمر<span style="font-family:courier new,courier,monospace;"> fail2ban-client</span> مرة أخرى:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo fail2ban-client status nginx-http-auth</pre><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">Status for the jail: nginx-http-auth

|- filter
|  |- File list:        /var/log/nginx/error.log
|  |- Currently failed: 0
|  <span style="line-height: 24.8889px;">`</span>- Total failed:     0
<span style="line-height: 24.8889px;">`</span>- action
   |- Currently banned: 0
   |  <span style="line-height: 24.8889px;">`</span>- IP list:
   <span style="line-height: 24.8889px;">`</span>- Total banned:     0</pre><h2 dir="rtl">اختبار سياسات Fail2Ban</h2><p dir="rtl">من الهام اختبار سياسات fail2ban لكي نتأكّد من أنها تقوم بحظر نقل البيانات كما هو متوقّع، على سبيل المثال نستطيع إعطاء بيانات خاطئة في مُحث prompt استيثاق Nginx عدّة مرات، وبعد أن نتجاوز الحدّ ينبغي أن يتم حظرنا وألا نكون قادرين على الوصول للموقع، وإن قمنا بإعداد تنبيهات البريد الإلكتروني فيجب أن نرى رسائل حول الحظر في البريد الإلكتروني الذي قمنا باختياره لاستقبال التّنبيهات.</p><p dir="rtl">عندما ننظر إلى الحالة باستخدام الأمر<span style="font-family:courier new,courier,monospace;"> fail2ban-client</span> سنشاهد أنّ عنوان IP الخاص بنا يتم حظره من الموقع:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo fail2ban-client status nginx-http-auth</pre><p> </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">Status for the jail: nginx-http-auth
|- filter
|  |- File list:        /var/log/nginx/error.log
|  |- Currently failed: 0
|  <span style="line-height: 24.8889px;">`</span>- Total failed:     12
<span style="line-height: 24.8889px;">`</span>- action
   |- Currently banned: 1
   |  <span style="line-height: 24.8889px;">`</span>- IP list:       111.111.111.111
   <span style="line-height: 24.8889px;">`</span>- Total banned:     1</pre><p>وعندما نكون مقتنعين بأنّ قواعدنا تعمل بشكل صحيح نستطيع فك الحظر يدويًّا عن عنوان IP الخاص بنا عن طريق الأمر fail2ban-client بكتابة ما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo fail2ban-client set nginx-http-auth unbanip 111.111.111.111</pre><p><a rel="external nofollow" name="_GoBack"></a></p><p dir="rtl">نبغي أن نكون الآن قادرين على محاولة الاستيثاق مرة أخرى.</p><h2 dir="rtl">الخاتمة</h2><p dir="rtl">إنّ إعداد fail2ban لحماية خادوم Nginx لدينا هو عمليّة سهلة إلى حدٍّ ما في أبسط الحالات، توفّر fail2ban على أيّة حال قدرًا كبيرًا من المرونة لبناء سياسات تُلائِم احتياجاتنا الأمنيّة، وبإلقاء نظرة على المتغيّرات والأنماط داخل الملف <span style="font-family:courier new,courier,monospace;">etc/fail2ban/jail.local/</span> والملفات التي يعتمد عليها داخل الدّليل <span style="font-family:courier new,courier,monospace;">etc/fail2ban/filter.d/</span> والدّليل <span style="font-family:courier new,courier,monospace;">etc/fail2ban/action.d/</span> نجد العديد من الأجزاء التي يمكننا تطويعها tweak وتغييرها لكي تلبّي احتياجاتنا، إنّ تعلّم أساسيّات كيفيّة حماية خادومنا باستخدام fail2ban يزوّدنا بقدرٍ كبير من الأمان وبأقل جهد.</p><p dir="rtl">إن كنت ترغب في تعلّم المزيد حول <strong>fail2ban</strong> قم بزيارة الروابط التالية:</p><ul dir="rtl"><li><a href="https://academy.hsoub.com/devops/servers/%D9%83%D9%8A%D9%81-%D9%8A%D8%B9%D9%85%D9%84-fail2ban-%D8%B9%D9%84%D9%89-%D8%B2%D9%8A%D8%A7%D8%AF%D8%A9-%D8%AD%D9%85%D8%A7%D9%8A%D8%A9-%D8%AE%D8%A7%D8%AF%D9%88%D9%85%D9%83-r88/">كيف تعمل Fail2Ban لحماية الخدمات على خادوم لينِكس</a>.</li><li><a href="https://academy.hsoub.com/devops/servers/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AD%D9%85%D8%A7%D9%8A%D8%A9-ssh-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-fail2ban-%D8%B9%D9%84%D9%89-ubuntu-r113/">كيفيّة حماية SSH باستخدام Fail2Ban على Ubuntu 14.04.</a></li></ul><p dir="rtl">ترجمة -وبتصرّف- لـ <a rel="external nofollow" href="https://www.digitalocean.com/community/tutorials/how-to-protect-an-nginx-server-with-fail2ban-on-ubuntu-14-04">How To Protect an Nginx Server with Fail2Ban on Ubuntu 14.04</a> لصاحبه Justin Ellingwood.</p>
]]></description><guid isPermaLink="false">124</guid><pubDate>Thu, 22 Oct 2015 09:00:01 +0000</pubDate></item><item><title>&#x641;&#x647;&#x645; &#x628;&#x646;&#x64A;&#x629; &#x645;&#x644;&#x641; &#x625;&#x639;&#x62F;&#x627;&#x62F;&#x627;&#x62A; nginx &#x648;&#x633;&#x64A;&#x627;&#x642;&#x627;&#x62A; &#x627;&#x644;&#x625;&#x639;&#x62F;&#x627;&#x62F;&#x627;&#x62A;</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D9%81%D9%87%D9%85-%D8%A8%D9%86%D9%8A%D8%A9-%D9%85%D9%84%D9%81-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF%D8%A7%D8%AA-nginx-%D9%88%D8%B3%D9%8A%D8%A7%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF%D8%A7%D8%AA-r112/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_09/nginx-config.png.6a4bf410ff60c7115e0b42d7f1baed0c.png" /></p>

<p dir="rtl">يُعد إنجن إكس NginX خادوم ويب Web Server ذو أداء عالي وهو مسؤول عن معالجة العبء الواقع على بعض أكبر المواقع الإلكترونية Web Sites على الإنترنت Internet. وهو جيد خصوصًا في معالجة الكثير من الاتصالات المتزامنة concurrent ويتفوق في تخديم المحتوى الثابت static content.</p><p dir="rtl" style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_09/nginx-config.png.225fec3762fd90bea6ee980ce33eccd2.png"><img data-fileid="5405" class="ipsImage ipsImage_thumbnailed" alt="nginx-config.thumb.png.85f049fa82c413790" src="https://academy.hsoub.com/uploads/monthly_2015_09/nginx-config.thumb.png.85f049fa82c4137909e3c65ca161173e.png"></a></p><p dir="rtl">مع أنّ الكثير من المستخدمين يدركون قدرات Nginx، إلا أنه عادةً ما يحتار المستخدمين الجدد ببعض المصطلحات التي يجدونها في ملف إعدادات configuration خادوم Nginx. سنركّز في هذا الدليل على شرح البنية الأساسية لملف إعدادات Nginx بالإضافة لاستعراض بعض المبادئ guidelines في كيفية تصميم ملف الإعدادات.</p><h2 dir="rtl">فهم سياقات الإعدادات في Nginx</h2><p dir="rtl">سيُغطي هذا الدليل البنية الأساسية الموجودة في ملف الإعدادات الرئيسي Nginx. قد يختلف مكان هذا الملف وفقًا للطريقة التي اتبعتها عند تثبيت البرمجية Software على الخادوم. إلا أنَّك سوف تجده في العديد من التوزيعات distributions على المسار التالي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">/etc/nginx/nginx.conf</pre><p dir="rtl">إنّ لم يكن موجودًا فقد تجده على المسار:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">/usr/local/nginx/conf/nginx.conf</pre><p dir="rtl">أو المسار:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">/usr/local/etc/nginx/nginx.conf</pre><p dir="rtl">إنّ أحد أول الأمور التي ينبغي عليك ملاحظتها عندما تنظر إلى ملف الإعدادات الرئيسي هي أنَّه منظَّم في بنيةٍ من ثلاثة أقسام تعرّف بداية ونهاية كلٍ منها بالقوسين <strong>}</strong> و <strong>{</strong>. تسمى الأقسام المعرّفة باستخدام القوسين سياقات contexts وفقًا للغة Nginx، وذلك لأنها تحوي على إعداداتٍ مُفَصَّلة وموزعة بين تلك الأقسام وفقًا للمجال الذي يُعنى به كل قسم. يقدم هذا التقسيم بشكل أساسي بنيةً منظّمة وفق بعض الشروط المنطقية التي تقرّر فيما إن كان ينبغي تطبيق الإعدادات التي يحويها القسم أو لا.</p><p dir="rtl">وباعتبار أنه يمكن للسياقات أن تتداخل فيما بينها فإنNginx يقدم مستوًا من وراثة التعليمات directive inheritance. كقاعدةٍ عامة، إن كانت التعليمة صالحةً في عدّة مجالات scopes متدخلة فإنّ التصريح عنها في سياق أعلى boarder context سيُمرّر لأي سياقٍ أدنى (سياق ابن child context) كقيم افتراضية. يمكن للسياقات الأدنى أن يعيد تعريف override تلك القيم لاحقًا. جدير بالذكر أنّ عملية إعادة التعريف إلى أي مصفوفة-نوع array-type سينتج عنها استبدال القيم السابقة وليس إضافة append القيم الجديدة لها.</p><p dir="rtl">يمكن أن تستخدم التعليمات Directives ضمن السياقات المصمّمة لها فقط، إذ أنّ Nginx سيُصدر خطأ عند قراءته لملف إعدادات يحوي على تعليمات مصرّح عنها في السياق الخاطئ. يحوي <a rel="external nofollow" href="http://nginx.org/en/docs/dirindex.html">توثيق Nginx</a> على معلومات حول كلّ تعليمة والسياقات التي تكون صالحة ضمنها لذلك يُعد مرجع رائع إن لم تكن متأكدًا من معلوماتك.</p><p dir="rtl">سنناقش فيما يلي أكثر السياقات شيوعًا والتي قد تصادفها عند استخدامك Nginx.</p><h2 dir="rtl">السياقات الأساسية</h2><p dir="rtl">أول مجموعة سياقات سنشرحها هي السياقات الأساسية<strong> core contexts</strong> التي يستخدمها Nginx لإنشاء شجرة هرمية hierarchical tree وتوزيع الإعدادات - بحسب مهمّتها - في كتل Blocks منفصلة. تشكّل تلك السياقات البنية الأساسية لإعدادات <span style="line-height: 22.4px;">Nginx</span>.</p><h3 dir="rtl">السياق الأساسي</h3><p dir="rtl">إن أكثر سياق عام هو السياق الأساسي <strong>Main Context</strong>، والذي يدعى أيضًا بالسياق العام Global Context. إذ أنه السياق الوحيد غير المحتوى ضمن كتل السياق القياسية والتي تبدو كما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"># السياق الأساسي يوجد هنا، السياقات الأخرى تكون خارجا
. . .
context {
    . . .
}</pre><p dir="rtl">يمكن القول عن أيّة تعليمة موجودة خارج كل تلك الكتل بأنها تقع في السياق الأساسي. ضع في الحسبان أنه إن كانت إعدادات <span style="line-height: 22.4px;">Nginx</span> مضبوطةً على شكل وحدات modular فستحوي بعض الملفات على تعليماتٍ instructions تبدو وكأنها تقع خارج أقواس السياق إلا أنها ستُضمّن داخله عندما يتم دمج الإعدادات معًا.</p><p dir="rtl">يمثّل السياق الأساسي أوسع بيئة حاضنة لإعدادات <span style="line-height: 22.4px;">Nginx</span>، وهي مستخدمة لضبط التفاصيل التي تؤثر على كامل التطبيق application في مستوى أساسي. وفي الوقت الذي تؤثر فيه التعليمات الموجودة في هذا القسم على السياقات الأدنى فإن العديد من تلك التعليمات لا توّرث، إذ أنه من غير الممكن إعادة تعريفها في مستوياتٍ أدنى.</p><p dir="rtl">إن بعض التفاصيل الشائعة والتي تُهيّئ في السياق الرئيسي هي المستخدم user والمجموعة group التي ستُشغّل العمليات العاملة worker processes باسمهما، بالإضافة لعدد العمليات العاملة والملف الذي سيحتفظ بمعرّف العملية الرئيسية PID. يمكن أيضًا أن يُضبط ملف الأخطاء الافتراضي لكامل التطبيق ضمن هذا المستوى (كما يمكن أن يُعاد تعريف الملف ضمن سياقات مخصّصة أكثر).</p><h3 dir="rtl">سياق الأحداث</h3><p dir="rtl">إنَّ سياق الأحداث <strong>Events Context</strong> يقع ضمن السياق الأساسي. وهو يستخدم لضبط الخيارات العامة التي تؤثّر على كيفية معالجة <span style="line-height: 22.4px;">Nginx</span> للاتصالات في مستوى عام. يمكن أن يُعرّف سياق أحداث واحد فقط ضمن إعدادات <span style="line-height: 22.4px;">Nginx</span>.</p><p dir="rtl">سوف يبدو هذا السياق ضمن ملف الإعدادات كما يلي، خارج أقواس أي سياقٍ آخر:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"># السياق الأساسي

events {
    # سياق الأحداث
    . . .
}</pre><p dir="rtl">يستخدم <span style="line-height: 22.4px;">Nginx</span> وحدة معالجة اتصال مقادة بالأحداث event-based connection processing model لذلك فإن التعليمات المعرّفة داخل هذا السياق تحدّد كيف ينبغي على العمليات العاملة worker processes معالجة الاتصالات connections. تُستخدم التعليمات الموجودة هنا بشكل أساسي إما في اختيار الطريقة المستخدمة في معالجة الاتصال أو لتغيير كيفية تحقيق implement تلك الطرق methods.</p><p dir="rtl">عادةً ما تُختار طريقة معالجة الاتصال تلقائيًا بالاعتماد على أكثر الخيارات - التي توفّرها منصّة العمل platform - فاعليةً. بالنسبة لأنظمة لينكس Linux، فعادةً ما تكون طريقة epoll هي الخيار الأفضل.</p><p dir="rtl">هنالك عناصر أخرى يمكن ضبطها، كعدد الاتصالات التي يمكن لكل عملية عاملة أن تعالجها، وفيما إن كان على العملية أن تأخذ اتصالًا تلو الآخر أو أن تأخذ كل الاتصالات المنتظرة بعد أن يتم إعلامها بوجودها. وأيضًا فيما إن كان على العمليات العاملة أن تتناوب في الرد على الأحداث.</p><h3 dir="rtl">سياق HTTP</h3><p dir="rtl">عند إعداد <span style="line-height: 22.4px;">Nginx</span> كخادوم ويب أو خادوم وكيل معكوس reverse proxy، فسيحتفظ سياق HTTP بغالبية الإعدادات. سيحتوي السياق على كل التعليمات والسياقات الأخرى الضرورية لتعريف كيفية معالجة البرنامج لاتصالات HTTP أو HTTPS.</p><p dir="rtl">يُعد سياق HTTP أخًا لسياق الأحداث - أي أنهما يقعان في نفس المستوى - إذ أن كلاهما يُعد ابنًا للسياق الرئيسي، لذلك ينبغي أن يُدرجا جنبًا إلى جنب بدلًا من أن يتداخلا:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"># السياق الأساسي

events {
    # سياق الأحداث
    . . .
}

http {
    # سياق HTPP
    . . .
}</pre><p dir="rtl">فيما تختص السياقات الدنيا lower contexts في كيفية معالجات الطلبات، فإن التعليمات في هذا المستوى تتحكم بالقيم الافتراضية لكل الخواديم الافتراضية المعرّفة داخله. هنالك عدد كبير من التعليمات القابلة للضبط configurable ضمن هذا السياق والسياقات المحتواة ضمنه، يعتمد ذلك على طريقة التوريث inheritance التي ترغب أن يتم العمل وفقها.</p><p dir="rtl">فيما يلي مجموعة من التعليمات التي يمكن أن تصادفها خلال ضبط إعدادات <span style="line-height: 22.4px;">Nginx</span>:</p><ul dir="rtl"><li>تعليمات تتحكم بالمواقع الافتراضية لسجلات الوصول والأخطاء مثل (access_log و error_log).</li><li>تعليمات تضبط عمليات القراءة والكتابة I/O غير المتزامنة asynchronous من وإلى الملفات مثل (aio و sendfile و directio)،</li><li>تعليمات تضبط حالات الخادوم عندما تحدث الأخطاء مثل (error_page).</li><li>تعليمات تضبط عملية الضغط compression مثل (gzip و gzip_disable).</li><li>عمليات تحسّن fine-tune إعدادات اتصال TCP الحي TCP keep alive مثل (keepalive_disable و keepalive_requests و keepalive_timeout).</li><li>القواعد rules التي يتبعها <span style="line-height: 22.4px;">Nginx </span>عندما يحاول تحسين optimize الحزم packets واستدعاءات النظام system calls مثل (sendfile و tcp_nodelay و tcp_nopush).</li><li>تعليمات تضبط جذر المستندات document root وفهرس الملفات index files على مستوى التطبيق application-level مثل (root و index).</li><li>تعليمات تهيّئ العديد من جداول المقابلة hash tables المستخدمة لتخزين أتماط مختلفة من البيانات مثل (*_hash_bucket_size و *_hash_max_size المستخدمتين مع server_names بالإضافة لـ types و variables).</li></ul><h3 dir="rtl">سياق الخادوم</h3><p dir="rtl">يُعرّف سياق الخادوم Server Context ضمن سياق HTTP، ويُعد ذلك أوّل مثال لنا عن السياقات المتداخلة. كما أنّه أوّل سياق مرّ معنا يمكن تعريفه عدّة مرات.</p><p dir="rtl">قد يبدو التنسيق العام لسياق الخادوم مشابهًا لما يأتي، تذكّر أنّ هذا السياق سيقع ضمن سياق HTTP:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"># السياق الأساسي

http: {

    # سياق HTTP

    server {
    # سياق خادوم أول
    }

    server {
    # سياق خادوم ثاني
   }

}</pre><p dir="rtl">يعود سبب السماح بوجود أكثر من تعريف لسياق الخادوم إلى أن كل غرض instance يعرّف خادومًا افتراضيًا لمعالجة طلبات المستخدم client. بإمكانك تعريف كتل الخادوم server blocks بقدر حاجتك، إذ أنّه بإمكان كل منها أن يعالج مجموعة فرعية محدّدة من الاتصالات.</p><p dir="rtl">وبسبب امكانية وترجيح وجود عدة كتل خواديم، فإن هذا أوّل نوع من السياقات يحتّم على <span style="line-height: 22.4px;">Nginx</span> استخدام خوارزمية algorithm انتقاء لاتخاذ القرارات. إنّ كلّ طلب مستخدم سيُعالَج وفقًا للإعدادات المعرّفة في سياق خادوم وحيد، لذلك فإن على <span style="line-height: 22.4px;">Nginx</span> أن يقرّر أي سياق خادوم هو الأنسب وفقًا لتفاصيل الطلب. إنّ التعليمات التي تقرّر فيما إذا كانت كتلة الخادوم ستُستخدم أم لا هي:</p><ul dir="rtl"><li><strong>تعليمة التنصت</strong><span style="font-family:courier new,courier,monospace;"> listen</span>: تُصمَّم كتلة الخادوم للرد على الطلبات الواردة من مصدر معرّف بثنائية عنوان الإنترنت IP / المنفذ Port. فإن ورد طلب request من مستخدم يطابق ذلك المصدر فمن المحتمل أن يتم اختيار تلك الكتلة لمعالجة الاتصال.</li><li><strong>تعليمة اسم الخادم<span style="font-family:courier new,courier,monospace;"> </span></strong><span style="font-family:courier new,courier,monospace;">server_name</span>: هذه التعليمة هي المكوّن الآخر المستخدم في اختيار كتلة الخادوم التي ستقوم بالمعالجة. إن كان هنالك العديد من كتل الخادوم مزوّدةً بتعليمات تنصت مضبوطة بنفس القيم ويمكنها أن تعالج الطلب، فسيحلّل إنجن إكس ترويسة المُضيف Host header الخاصة بالطلب ويطابقها مع التعليمة.</li></ul><p dir="rtl">يمكن للتعليمات الموجودة ضمن هذا السياق أن تعيد تعريف العديد من التعليمات المعرّفة في سياق HTTP بما فيها تعليمات التسجيل logging، وجذر المستندات، والضغط، وإلى ما هنالك. وبالإضافة إلى التعليمات المأخوذة من سياق HTTP، فبإمكاننا أيضًا إعداد ملفات لمحاولة الرد على الطلبات عبر تعليمة (try_files)، وإصدار أمر لإعادة التوجيه وإعادة الكتابة (return و rewrite)، وضبط المتحولات عبر تعليمة (set).</p><h3 dir="rtl">سياق الموقع</h3><p dir="rtl">السياق التالي الذي ستتعرف عليه هو سياق الموقع location context وهو سياقٌ ستتعامل معه بشكل متكرّر. تتشارك سياقات الموقع العديد من الصفات مع سياقات الخادوم. فمثلًا، يمكن تعريف أكثر من سياق موقع، ويُستخدم كل منها لمعالجة نوع محدّد من طلبات المستخدم، ويتم اختيار كل موقع بناءًا على مطابقة تعريف الموقع مع طلب المستخدم باستخدام خوارزمية انتقاء.</p><p dir="rtl">في الوقت الذي تُعرّف فيه التعليمات - التي تحدّد فيما إن كان سيتم اختيار كتلة خادوم - ضمن السياق الخادوم ذاته، فإن المكوّن component الذي يقرّر مدى قدرة الموقع على معالجة الطلب يقع ضمن تعريف الموقع نفسه.</p><p dir="rtl">تبدو الصيغة العامة كما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">location match_modifier location_match {
    . . .
}</pre><p dir="rtl">تقع كتل الموقع ضمن سياقات الخواديم، وعلى عكس كتل الخادوم، يمكن لكتل الموقع أن تتداخل فيما بينها. قد يفيد ذلك في إنشاء سياق موقع أعم ليلتقط مجموعة فرعية محدّدة من الطلبات المتناقلة traffic، لتكمل السياقات الإضافية الداخلية معالجتها بإسهاب أكبر وفقًا لمعايير أدق.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"># السياق الأساسي

server {
    # سياق الخادوم

    location /match/criteria {
        # سياق موقع أول
    }

    location /other/criteria {
        # سياق موقع ثاني
 
        location nested_match {
            # موقع أول
        }
 
        location other_nested {
            # موقع ثاني
        }
    }
}</pre><p dir="rtl">بينما يتم اختيار سياقات الخواديم وفقًا لثنائية عنوان IP / المنفذ المطلوبة ولاسم المضيف الموجود ضمن ترويسة المضيف، فإن كتل الموقع تقسّم معالجة الطلب ضمن كتلة الخادوم بالنظر إلى معرّف الموارد الموّحد URI الخاص بالطلب. إن معرّف URI الخاص بالطلب هو جزءٌ من الطلب يأتي بعد اسم النطاق domain name وثنائية عنوان IP / المنفذ.</p><p dir="rtl">لذلك فإن طلب المستخدم <a rel="external nofollow" href="http://www.example.com/blog">http://www.example.com/blog</a> على المنفذ 80، يستخدم العنوان <span style="font-family:courier new,courier,monospace;">http www.example.com</span> والمنفذ 80 لتحديد كتلة الخادوم التي سيتم اختيارها. بعد اختيار الخادوم، سيُطابق الجزء /blog (المُمثّل لمعرّف URI الخاص بالطلب) مع المواقع المعرّفة لتحديد السياق الإضافي الذي ينبغي استخدامه ليرد على الطلب.</p><p dir="rtl">إنّ العديد من التعليمات التي يمكن أن تراها في سياق الموقع متوفّرةٌ أيضًا في مستويات الآباء (المستويات الأعلى) parent levels. فيما يلي مجموعة جديدة من التعليمات المستخدمة ضمن هذا المستوى تسمح لك بالوصول إلى المواقع الواقعة خارج جذر المستندات (تعليمة alias)، وتحديد الموقع كموقع يمكن الوصول له من الداخل فقط (تعليمة internal)، وكوكيل لخواديم أو مواقع أخرى (باستخدام برتوكولات http، fastcgi، scgi، uwsgi)</p><h2 dir="rtl">سياقات أخرى</h2><p dir="rtl">مع أنّ الأمثلة السابقة تمثّل السياقات الأساسية التي ستصادفها في <span style="line-height: 22.4px;">Nginx</span>، إلا أنه يوجد سياقات أخرى أيضًا. هنالك عدّة أسباب دعتنا لفصل السياقات التالية، فإما أنها تعتمد على الكثير من الوحدات الاختيارية، أو أنها تستخدم ضمن ظروف خاصة فقط، أو أنها تستخدم لوظائف لن يستخدمها معظم الأشخاص.</p><p dir="rtl">لكننا لن نناقش كل السياقات المتوفّرة، ولن نخوض بشرح السياقات الآتية بالتفصيل:</p><ul dir="rtl"><li><strong><span style="font-family:courier new,courier,monospace;">split_clients</span></strong> أُعد هذا السياق لتقسيم المستخدمين اللذين يستقبلهم الخادوم إلى فئات categories عبر عنونتهم بمتحولات تعتمد على النسبة المئوية. يمكن أن يُستخدم ذلك لاحقًا للقيام باختبار A/B عبر توفير محتويات content مختلفة لمُضيفين hosts مختلفين.</li><li><strong><span style="font-family:courier new,courier,monospace;">perl / perl_set</span></strong> يُهيّئ هذين السياقين معالجات بيرل Perl للموقع الذي تتواجد ضمنه. تستخدم هذه السياقات للمعالجة باستخدام بيرل فقط.</li><li><strong><span style="font-family:courier new,courier,monospace;">map</span></strong> يُستخدم هذا السياق لضبط قيمة متحول بالاعتماد على قيمة متحول آخر. إذ أنه يوفّر جدول مقابلة mapping لقيم المتحوّل الأول حتى يحدّد القيمة التي ينبغي ضبط المتحول الثاني بها.</li><li><strong><span style="font-family:courier new,courier,monospace;">geo</span></strong> يُستخدم هذا السياق - مثل السياق السابق - في تحديد جدول مقابلة. إلا أنّ هذا الجدول يستخدم خصيصًا لتصنيف عناوين IP. يضبط هذا السياق قيمة متحول وفقًا لعنوان IP المتّصل.</li><li><strong><span style="font-family:courier new,courier,monospace;">types </span></strong>يُستخدم هذا السياق أيضًا لجداول المقابلة. إذ أنه يُستخدم لمقابلة أنماط وسائط الإنترنت MIME بامتدادات (لواحق) extensions  الملفات التي ينبغي ربطهم بها. يوفّر <span style="line-height: 22.4px;">Nginx</span> ذلك عادةً عبر ملف يُضمّن محتواه داخل ملف الإعدادات<span style="font-family:courier new,courier,monospace;"> nginx.conf</span>.</li><li><strong><span style="font-family:courier new,courier,monospace;">charset_map</span></strong> يمثّل هذا السياق مثالًا آخر عن سياقات المقابلة، إذ أنه يُستخدم لإنشاء جدول مقابلة للتحويل conversion table من مجموعة محارف إلى مجموعة أُخرى. تضمّن كلا المجموعتين في ترويسة هذا السياق، ويضمّن جدول المقابلة في بنيته body.</li></ul><p dir="rtl">إنّ السياق التالي ليس شائعًا بقدر السياقات التي شرحناها حتى الآن، إلا أنّ التعرّف عليه يبقى مفيدًا.</p><h3 dir="rtl">سياق مجموعة الخواديم العليا</h3><p dir="rtl">يُستخدم سياق مجموعة الخواديم العليا upstream context لتعريف وإعداد الخواديم العليا upstream. يعرّف هذا السياق بشكل أساسي حوضًا pool معرّفًا باسم يحتوي على مجموعة الخواديم التي يستطيع <span style="line-height: 22.4px;">Nginx</span> أن يعمل كوكيل proxy عنها للطلبات. ستستخدم هذا السياق على الأرجح عندما تُعد وكلاءًا من مختلف الأنواع.</p><p dir="rtl">يجب وضع سياق مجموعة الخواديم العليا ضمن سياق HTTP، وخارج كلِّ سياقات الخواديم. تبدو الصيغة العامة له كما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"># السياق الأساسي

http {
    # سياق HTTP

    upstream upstream_name {
        # سياق مجموعة الخواديم العليا
        server proxy_server1;
        server proxy_server2;
        . . .
    }

    server {
        # سياق خادوم
   }
}</pre><p dir="rtl">يمكن فيما بعد أن تتم الإشارة إلى سياق مجموعة الخواديم العليا باسمه ضمن الخادوم أو كتل الموقع لتمرير طلبات ذات نوع محدّد لحوض الخواديم الذي تمّ تعريفه. ستستخدم عندها مجموعة الخواديم خوارزميةً لتحديد الخادوم الذي ينبغي أن يسلم الطلب له، تستخدم خوارزمية راوند روبن round-robin بشكل افتراضي. يسمح هذا السياق لـNginx أن يعمل على موازنة الحمل load balancing عندما يعمل كوكيل للطلبات.</p><h3 dir="rtl">سياق البريد</h3><p dir="rtl">بالرغم من أن Nginx يُستخدم عادةً كخادوم ويب أو خادوم وكيل معكوس، إلا أنه يعمل كخادوم وكيل للبريد mail proxy server بأداءٍ عالي جدًا. يسمّى السياق المستخدم لهذا النوع من التعليمات بالبريد mail. يعرّف سياق البريد The mail context ضمن السياق العام، أو السياق الأساسي (خارج سياق HTTP).</p><p dir="rtl">الوظيفة الأساسية لسياق البريد هي توفير مجال لإعداد وكيل للبريد على الخادوم. يمكن لـ<span style="line-height: 22.4px;">Nginx</span> أن يعيد توجيه redirect طلبات المصادقة authentication لخادوم مصادقة خارجي authentication server. ويمكنه بعد ذلك أن يوفّر الوصول إلى خواديم البريد العاملة ببرتوكولات POP3 و IMAP لجلب بيانات البريد الفعلية. يمكن لسياق البريد أن يُعد أيضًا للاتصال بخادوم الترحيل العامل ببرتوكول SMTP (SMTP Relayhost) إن دعت الحاجة.</p><p dir="rtl">عمومًا، قد يبدو شكل سياق البريد مشابهًا لما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"># السياق الأساسي

events {
    # سياق الأحداث
}

mail {
    # سياق البريد
}</pre><h3 dir="rtl">السياق الشرطي</h3><p dir="rtl">يمكن أن يُنشئ السياق الشرطي if لتوفير معالجة شرطية للتعليمات المعرّفة بداخله. وكما هو حال عبارات الشرط if في لغات البرمجة التقليدية، فإن تعليمة if في Nginx ستنفذ التعليمات المتحواة ضمنها إن كان الشرط محقّقًا وأعاد القيمة الصحيحة True.</p><p dir="rtl">يُقدَّم السياق if في <span style="line-height: 22.4px;">Nginx</span> من قِبل وحدة إعادة الكتابة rewrite module وهي الغاية الأساسية من استخدام هذا السياق. باعتبار أنّ <span style="line-height: 22.4px;">Nginx</span> سيختبر حالات الطلب باستخدام العديد من التعليمات الأخرى المعمولة لهذا الغرض، فلا ينبغي استخدام تعليمة if في أغلب حالات التنفيذ الشرطي. تُعد هذه الملاحظة هامةً لدرجة أنّ مجتمع <span style="line-height: 22.4px;">Nginx</span> أنشأ صفحةً وسمّاها <a rel="external nofollow" href="http://wiki.nginx.org/IfIsEvil">if الشريرة</a>.</p><p dir="rtl">إنّ المشكلة الأساسية هي أنّ ترتيب المعالجة لدى <span style="line-height: 22.4px;">Nginx</span> قد يؤدي في كثير من الأحيان إلى نتائج غير متوقعة تظهر وكأنها تقلب معنى كتلة if رأسًا على عقب. تُعد تعليمتي إعادة التوجيه return وإعادة الكتابة rewrite التعليمتين الوحيدتين اللتين يعتبر استخدامهما آمنًا داخل هذه السياقات، إذ أنها أُنشئت لأجلهما. ضع في الحسبان أيضًا أنّه عند استخدام سياق if فإنّه يقدّم تعليمة try_files داخل نفس السياق بلا فائدة.</p><p dir="rtl">غالبًا ما يتم استخدام if لتحديد فيما إنّ كان هنالك حاجة لتعليمة return أو تعلمية rewrite. وستقع غالبًا داخل كتل الموقع، لذلك فستبدو الصيغة العامة مشابهةً لما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"># السياق الأساسي

http {

    # سياق HTTP
    server {
        # سياق خادوم

        location location_match {
            # سياق موقع
            if (test_condition) {
                #  سياق شرطي if
            }
        }
    }
}</pre><h3 dir="rtl">سياق تحديد الاستثناءات</h3><p dir="rtl">يُستخدم سياق تحديد الاستثناءات Limit_except Context لتحديد استخدام طرق HTTP Methods محدّدة داخل سياق الموقع. فمثلًا، إن كان ينبغي لمجموعة محدّدة فقط من المستخدمين أن يصلوا إلى محتوى طريقة POST Method، أما البقيّة فينبغي أن يتمكّنوا من قراءة المحتوى، فيمكنك استخدام كتلة limit_except لتعريف تلك المتطلّبات.</p><p dir="rtl">سيبدو المثال السابق مشابهًا لما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">. . .

# سياق موقع أو خادوم

location /restricted-write {
    # سياق موقع

    limit_except GET HEAD {
        # سياق تحديد الاستثناءات
        allow 192.168.1.1/24;
        deny all;
    }
}</pre><p dir="rtl">ستطبق التعليمات الموجودة داخل السياق - والتي يقصد منها تقييد الوصول - عند مصادفة أيٍ من طرق HTTP باستثناء تلك المدرجة ضمن ترويسة السياق. إنّ نتيجة المثال السابق هي أنّه بإمكان أي مستخدم استخدام أفعال GET و HEAD، إلا أنّه يسمح فقط للمستخدمين المتصلين من الشبكة الفرعية subnet ذات العنوان 192.168.1.1/24 باستخدام طرق أخرى.</p><h2 dir="rtl">قواعد عامة حول السياقات ينبغي اتباعها</h2><p dir="rtl">الآن وبعد أن أصبح لديك فكرة عن السياقات الشائعة التي يمكن أن تصادفها أثناء استعراضك لإعدادات إنجن إكس، فبإمكاننا شرح بعض القواعد المُثلى التي يمكن اتباعها عند التعامل مع سياقات Nginx.</p><h3 dir="rtl">تطبيق التعليمات في أعلى سياق متوفر</h3><p dir="rtl">إنّ العديد من التعليمات تكون صالحةً داخل أكثر من سياق واحد. فمثلًا، هنالك بضعة تعليمات يمكن وضعها داخل كل من سياقات HTTP والخادوم والموقع. يمنحنا ذلك مرونةً عند ضبط تك التعليمات.</p><p dir="rtl">ولكن كقاعدة عامة، عادةً ما يكون من الأفضل تعريف التعليمات في أعلى سياق تقبل التعريف ضمنه، وإعادة تعريفها ضمن السياقات الأدنى عند الحاجة. يمكن ذلك بسبب وحدة الوراثة inheritance model التي تحقّقها إنجن إكس. هنالك العديد من الأسباب لاستخدام هذه الاستراتيجية.</p><p dir="rtl">أولًا، إنّ التعريف ضمن أعلى مستوى يجنّبك تكرار نفس التعريف ضمن السياقات الأخوة. فمثلًا، في المثال التالي يعرّف كل موقع نفس جذر المستندات.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">http {

    server {

        location / {
            root /var/www/html;
            . . .
        }

        location /another {
            root /var/www/html;
            . . .
        }
    }
}</pre><p dir="rtl">يمكنك نقل الجذر خارج كتلة الخادوم، أو حتى لكتلة HTTP كما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">http {

    root /var/www/html;

    server {

        location / {
            . . .
        }

        location /another {
            . . .
        }
    }
}</pre><p dir="rtl">أغلب الأحيان، سيكون مستوى الخادوم ملائمًا أكثر، إلا أنّ التصريح declaring في مستوىً أعلى له محاسنه. إنّ ذلك لا يسمح بضبط التعليمة في أماكن أقل فحسب، وإنما سيسمح لك بتمرير القيمة الافتراضية لكل الأبناء، ما يمنع ظهور الحالات التي تصادف فيها خطأً لأنك نسيت تعليمةً ضمن مستوىً أدنى. يمكن أن يكون ذلك مشكلةً كبيرةً في الإعدادات الطويلة. إن التصريح في مستوىً عالي يوفّر لك قيمةً افتراضيةً صحيحة.</p><h3 dir="rtl">استخدام عدة سياقات أشقاء عوضا عن المنطق الشرطي If في المعالجة</h3><p dir="rtl">عندما تريد معالجة الطلبات كل بشكل مختلف، اعتمادًا على بعض المعلومات التي يمكنك ايجادها ضمن طلب المستخدم، فعادةً ما يلجئ المستخدمون إلى سياق if ليحاولوا معالجتها شرطيًا. هنالك بعض المشاكل المترافقة مع ذلك كنا قد ذكرناها سابقًا بإيجاز.</p><p dir="rtl">أول مشكلة هي أنّ تعليمة if عادةً ما تعيد نتائج لا تتوافق مع توقعات مدير النظام administrator. مع أنّ المعالجة ستُؤدي دائمًا إلى نفس النتائج عند توفير نفس المُدخلات، إلا أنّ الطريقة التي يتبعها <span style="line-height: 22.4px;">Nginx</span> في تفسير البيئة يمكن أن تختلف كثيرًا عما هو متوقع ما ام تخضع لاختبارات مكثّفة.</p><p dir="rtl">السبب الثاني هو أنّ هنالك تعليمات معدّة لهذا الغرض بالتحديد، وهي مستخدمةٌ للعديد من تلك الأغراض. يستخدم <span style="line-height: 22.4px;">Nginx </span>خوارزمية انتقاء - ذات توثيق جيد - لاختيار كتل الخادوم وكتل الموقع. لذلك، يفضّل نقل الإعدادات المختلفة إلى الكتل المخصّصة لها إن كان ذلك ممكنًا، ما يسمح لتلك الخوارزمية بمعالجة منطق عملية الاختيار.</p><p dir="rtl">فمثلًا، عوضًا عن الاعتماد على إعادة الكتابة rewrites للحصول على طلب المستخدم بالشكل format الذي ترغب بالعمل به، فعليك أن تجرّب إعداد كتلتين للطلب، أحدهما تمثّل الطريقة المرغوب بها، والأخرى تلتقط الطلبات العشوائية وتعيد توجيهها - وقد تعيد كتابتها - للكتلة الصحيحة.</p><p dir="rtl"><a rel="external nofollow" name="_GoBack"></a> عادةً ما تكون النتائج أسهل للقراءة كما أنها تمتلك محاسن كونها ذات أداء عالي. لا تخضع الطلبات الصحيحة لأي معالجة إضافية وفي العديد من الحالات يمكن تجاوز الطلبات غير الصحيحة عبر تعليمة إعادة التوجيه عوضًا عن تعليمة إعادة الكتابة والتي ينبغي أنّ يكون عبء تنفيذها أقل.</p><h2 dir="rtl">الخلاصة</h2><p dir="rtl">إلى هنا، ينبغي أن تكون قد حصلت على فهم جيّد لأكثر سياقات Nginx شيوعًا وللتعليمات التي تُنشئ الكتل التي تعرّف تلك السياقات.</p><p dir="rtl">تحقّق دائمًا من توثيق <span style="line-height: 22.4px;">Nginx</span> للحصول على معلومات حول أي السياقات هو الأنسب لوضع تعليمة ما بداخله ولتقييم الموقع الأكثر فاعلية. إنّ الحرص أثناء إنشاء الإعدادات لن يسهل من عملية الصيانة فحسب، بل أنه سيرفع الأداء أيضًا في أغلب الآحيان.</p><p dir="rtl">ترجمة -بتصرف- للمقال <a rel="external nofollow" href="https://www.digitalocean.com/community/tutorials/understanding-the-nginx-configuration-file-structure-and-configuration-contexts">Understanding the Nginx Configuration File Structure and Configuration Contexts</a> لكاتبه <a rel="external nofollow" href="https://www.digitalocean.com/community/users/jellingwood">Justin Ellingwood</a>.</p>
]]></description><guid isPermaLink="false">112</guid><pubDate>Wed, 30 Sep 2015 11:05:36 +0000</pubDate></item><item><title>&#x625;&#x646;&#x634;&#x627;&#x621; &#x634;&#x647;&#x627;&#x62F;&#x629; SSL &#x644;&#x62E;&#x627;&#x62F;&#x648;&#x645; Nginx &#x639;&#x644;&#x649; Ubuntu 14.04</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%B4%D9%87%D8%A7%D8%AF%D8%A9-ssl-%D9%84%D8%AE%D8%A7%D8%AF%D9%88%D9%85-nginx-%D8%B9%D9%84%D9%89-ubuntu-1404-r105/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_09/ssl-nginx.png.2b6c154f9405bf8f3113053af264705b.png" /></p>

<p>TLS، أو حماية طبقة النقل (Transport Layer Security)، وسلفها SSL أو طبقة الحِزَم الآمنة (Secure Sockets Layer) هما عبارة عن بروتوكولات آمنة يتم إنشاؤها بهدف توجيه تدفّق البيانات العادية (traffic) ضمن طريق مشفّر وآمن أثناء تنقّلها، وقد قمنا سابقا بشرح <a href="https://academy.hsoub.com/devops/servers/%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%B4%D9%87%D8%A7%D8%AF%D8%A9-ssl-%D9%84%D8%AE%D8%A7%D8%AF%D9%88%D9%85-apache-%D8%B9%D9%84%D9%89-ubuntu-1404-r104/">كيفية إعداد SSL على خادوم Apache</a>، سنقوم في هذا الدرس بشرح كيفية إعداده مع خادوم nginx.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_09/ssl-nginx.png.5ceaa8901881c042b1c087afab7da50f.png"><img data-fileid="4735" class="ipsImage ipsImage_thumbnailed" alt="ssl-nginx.thumb.png.d2870ad6fd48c1bd8692" src="https://academy.hsoub.com/uploads/monthly_2015_09/ssl-nginx.thumb.png.d2870ad6fd48c1bd86921f222af52c73.png"></a></p><p>باستخدام هذه التكنولوجيا، يمكن للخواديم أن تقوم بإرسال تدفّق البيانات بشكل آمن بينها وبين الزائر دون الحاجة إلى القلق بخصوص وجود إمكانية لاعتراض تدفّق البيانات بينها وقراءتها بواسطة شخص ما من الخارج. يساعد نظام الشهادات المستخدمين على التحقق من هوية المواقع التي يزورونها أيضًا.</p><p>في هذا الدرس، سنشرح كيفيّة إنشاء شهادة SSL موقّعة ذاتيًا لخادوم Nginx على Ubuntu 14.04، لن تسمح الشهادة الموقّعة ذاتيًا لمستخدميك من أن يتحققوا من هوية موقعك بما أنّها ليست موقّعة بواسطة واحدة من الجهات التي يثق بها متصفّحك، ولكنّها ستسمح لك بتشفير الاتصالات مع زوّارك.</p><h2>المتطلبات</h2><p>قبل أن تبدأ، يجب أن تهتم ببعض الإعدادات بالطبع.</p><p>سنستخدم مستخدمًا غير مستخدم الجذر مع صلاحيات sudo في هذا الدرس. يمكنك إعداد واحد عبر اتباع الخطوات المذكورة في <a href="https://academy.hsoub.com/devops/servers/%D8%A7%D9%84%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A7%D9%84%D8%A7%D8%A8%D8%AA%D8%AF%D8%A7%D8%A6%D9%8A-%D9%84%D8%AE%D8%A7%D8%AF%D9%88%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r4/">درسنا حول إعداد خادوم أوبونتو 14.04 الابتدائي</a>.</p><p>ستحتاج أيضًا إلى تثبيت خادوم Nginx. إذا كنت تريد إعداد خادوم LEMP كامل (Linux, Nginx, MySQL, PHP) فإنّه يمكنك مراجعة <a href="https://academy.hsoub.com/devops/servers/%D9%83%D9%8A%D9%81-%D8%AA%D9%8F%D8%AB%D8%A8%D9%91%D9%90%D8%AA-%D8%AD%D9%90%D8%B2%D9%85-mysql%D8%8C-nginx%D8%8C-linux-lemp-%D9%88php-%D8%B9%D9%84%D9%89-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r29/">درسنا حول تثبيت LEMP على أوبونتو 14.04</a>.</p><p>إذا كنت تريد خادوم Nginx فقط، فيمكنك تثبيته بواسطة:</p><pre data-pbcklang="" data-pbcktabsize="" class="ipsCode prettyprint">sudo apt-get update
sudo apt-get install nginx</pre><h2>الخطوة الأولى: إنشاء شهادة SSL</h2><p>فلنبدأ عبر إنشاء مسار فرعي ضمن مجلّد إعدادات خادوم Nginx لنضع ملفّات الشهادة التي سنقوم بإنشائها فيه:</p><pre data-pbcklang="" data-pbcktabsize="" class="ipsCode prettyprint">sudo mkdir /etc/nginx/ssl</pre><p>والآن وبعد أن قمنا بإنشاء ذلك المسار، يمكننا أن نقوم بإنشاء تلك الملفّات بأمر واحد وهو:</p><pre data-pbcklang="" data-pbcktabsize="" class="ipsCode prettyprint">sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt</pre><p>سيتم سؤالك عدّة أسئلة. قبل أن نتعرّف عليها، فلنتعرّف على ما يعنيه الأمر السابق:</p><ul><li><strong>openssl</strong>: هذا هو الأمر الأساسي الذي يتم توفيره بواسطة OpenSSL لإنشاء وإدارة الشهادات، المفاتيح وطلبات التوقيع.. إلخ.</li><li><strong>req</strong>: يحدد هذا الأمر الفرعي أننا نريد استخدام إدارة طلبات توقيع الشهادة X.509. X.509 هو عبارة عن معيار بنية تحتية للمفتاح العمومي يحتاجه كلٌّ من SSL وTLS لإدار الشهادات. نريد أن نقوم بإنشاء شهادة X.509 جديدة، ولذلك فإننا سنستخدم هذا الأمر الفرعي.</li><li><strong>x509-</strong>: يقوم هذا أيضًا بتعديل الأمر السابق عبر إخبار الأداة أننا نريد إنشاء شهادة موقّعة ذاتيًا عوضًا عن إنشاء طلب توقيع شهادة، والذي كان ليحدث بالحالة العادية.</li><li><strong>nodes-</strong>: يخبر هذا الخيار OpenSSL بأننا لا نريد تأمين ملفّ المفتاح الخاصّ بنا بجملة مرور، لأنّ استخدام هذا الخيار سيعترض طريق خادوم nginx عندما يتم تشغيله تلقائيًا حيث أنّه يجب علينا إدخال جملة المرور في كلّ مرّة يبدأ فيها الخادوم وفي كلّ مرّة يتم فيها إعادة تشغيله.</li><li><strong>days 365-</strong>: يحدد هذا أنّ الشهادة التي سنقوم بإنشائها صالحة لمدّة 365 يومًا.</li><li><strong>newkey rsa:2048-</strong>: سينشئ هذا الخيار طلب الشهادة ومفتاحًا خاصًّا جديدًا في الوقت ذاته. هذا ضروري جدًا بما أننا لم نقم بإنشاء مفتاح خاصّ مسبقًا. يقوم <strong>rsa:2048</strong> بإخبار OpenSSL بأن يقوم بتوليد مفتاح RSA بطول 2048 بت.</li><li><strong>keyout-</strong>: يسمّي هذا المُعامِل الملفّ الناتج لملفّ المفتاح الخاصّ الذي يتم إنشاؤه.</li><li><strong>out-</strong>: يسمّي هذا الخيار ملفّ الشهادة الناتج الذي نقوم بإنشائه.</li></ul><p>كما وضّحنا أعلاه، ستقوم هذه الخيارات بإنشاء ملفّ مفتاح وشهادة. سيتم سؤالنا بضع أسئلة عن خادومنا بهدف تضمين المعلومات بشكل صحيح في تلك الشهادة.</p><p>قم بكتابة الأجوبة بشكل صحيح، أهمّ واحد منها هو جواب ذاك السؤال الذي يسألك عن:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">"Common Name (e.g. server FQDN or YOUR name)". </pre><p>يجب أن تقوم بإدخال اسم نطاقك الذي تريد استخدامه مع خادومك، أو عنوان الـIP العام إذا كنتَ لا تمتلك نطاقًا بعد.</p><p>أجوبة الأسئلة ستبدو شيئًا كهذا:</p><pre data-pbcklang="" data-pbcktabsize="" class="ipsCode prettyprint">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</pre><p>سيتم إنشاء الشهادة والمفتاح في مسار <span style="font-family:courier new,courier,monospace;">etc/nginx/ssl/</span>.</p><h2>الخطوة الثانية: إعداد Nginx ليستخدم SSL</h2><p>الآن وبعد أن أصبح ملفّا الشهادة والمفتاح متوفّرين في مسار إعدادات Nginx، نحتاج الآن فقط إلى تعديل إعدادات خادوم Nginx الخاصّة بنا ليستفيد من التغييرات الجديدة. يمكنك تعلّم المزيد عن إعدادات خادوم Nginx من <a href="https://academy.hsoub.com/devops/web-servers/nginx/">خلال قراءة تصنيف nginx على أكاديمية حسوب</a>.</p><p>يستطيع الإصدار 0.7.14 والأعلى منه من Nginx (تأتي أوبونتو 14.04 بالإصدار 1.4.6) أن يقوم بتفعيل SSL في نفس كتلة الخادوم (Server Block) كتدفّق HTTP عادي. يسمح لنا هذا بإعداد الوصول إلى نفس الموقع بطريقةٍ مختصرة بشكل أكبر.</p><p>قد تبدو إعدادات الخادوم الخاصّة بك كالتالي:</p><pre data-pbcklang="" data-pbcktabsize="" class="ipsCode prettyprint">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;
        }
}</pre><p>الشيء الوحيد الذي يجب علينا فعله لنجعل SSL تعمل على نفس الخادوم مع السماح باتصالات HTTP العادية هو إضافة السطور التالية:</p><pre data-pbcklang="" data-pbcktabsize="" class="ipsCode prettyprint">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;
        }
}</pre><p>عندما تنتهي، احفظ الملفّ وأغلقه.</p><p>الآن ستحتاج إلى إعادة تشغيل خادوم Nginx فقط لكي تأخذ التغييرات مجراها:</p><pre data-pbcklang="" data-pbcktabsize="" class="ipsCode prettyprint">sudo service nginx restart</pre><p>سيقوم هذا بإعادة تحميل إعدادات موقعك، وسيصبح قادرًا على الاستجابة إلى كل من طلبات HTTP وHTTPS.</p><h2>الخطوة الرابعة: اختبر إعداداتك</h2><p>يجب الآن أن تعمل وظيفة SSL بشكلٍ جيّد معك، ولكن يجب علينا اختبارها لنتأكّد من ذلك.</p><p>أولًا، دعنا نتحقق أنّه ما يزال بإمكاننا الوصول إلى الموقع عبر بروتوكول HTTP العادي. في متصفّحك، قم بزيارة اسم نطاق الخادوم الخاصّ بك أو عنوان الـIP:</p><pre data-pbcklang="" data-pbcktabsize="" class="ipsCode prettyprint">http://اسم_النطاق_أو_عنوان_الآي_بي</pre><p>يجب أن ترى الموقع العادي. في حالتي، سأرى رسالة Nginx الافتراضية فقط:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_09/001.png.fd6777bb6a1c74673fa9e42970000acb.png"><img data-fileid="4653" class="ipsImage ipsImage_thumbnailed" alt="001.thumb.png.7d78cece516e72fc3c6954e235" src="https://academy.hsoub.com/uploads/monthly_2015_09/001.thumb.png.7d78cece516e72fc3c6954e235e95acd.png"></a></p><p>إذا وصلت إلى هذه الصفحة، فهذا يعني أنّ خادومك ما يزال يخدم طلبات HTTP بشكل صحيح.</p><p>الآن يمكننا التحقق مما إذا كان خادومنا قادرًا على استخدام SSL للتواصل أم لا. قم بذلك عبر كتابة بروتوكول https عوضًا عن http:</p><pre data-pbcklang="" data-pbcktabsize="" class="ipsCode prettyprint">https://اسم_النطاق_أو_عنوان_الآي_بي</pre><p>سترى رسالة تنبيه أن متصفّحك لم يتمكّن من التحقق من هوية خادومك لأنّه لم يتم توقيع الشهادة الخاصّة به من قبل جهة من الجهات التي يثق بها ذلك المتصفّح.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_09/002.png.3fc6f4b7d3bc85f9ed67e7423ef610e9.png"><img data-fileid="4654" class="ipsImage ipsImage_thumbnailed" alt="002.thumb.png.852b277e3f5e4dd9e13dadb36d" src="https://academy.hsoub.com/uploads/monthly_2015_09/002.thumb.png.852b277e3f5e4dd9e13dadb36d27205a.png"></a></p><p>هذه رسالة متوقّعة بمّا أنّ شهادتنا هي شهادة موقّعة ذاتيًا (self-signed). صحيح أّنّه لن يكون من الممكن استخدام شهادتنا للتحقق من هوية خادومنا، إلّا أنّ الخادوم سيزال قادرا على التواصل المشفّر.</p><p>بمّا أنّ هذه الرسالة هي رسالة متوقّعة، فيمكنك الضغط على زرّ "المتابعة على كلّ حال" أو "Proceed anyway" أو أيّ خيار مشابه تجده أمامك للمتابعة. يجب أن ترى صفحة موقعك مجددًا:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_09/001.png.fd6777bb6a1c74673fa9e42970000acb.png"><img data-fileid="4653" class="ipsImage ipsImage_thumbnailed" alt="001.thumb.png.7d78cece516e72fc3c6954e235" src="https://academy.hsoub.com/uploads/monthly_2015_09/001.thumb.png.7d78cece516e72fc3c6954e235e95acd.png"></a></p><p>قد يظهر لك متصفّحك اسم بروتوكول "https" مشطوبًا في شريط العنوان أو محطّمًا أو بجانبه إشارة قفل مشطوبة. إذا ضغطت على أيقونة القفل، ستجد بعض المعلومات عن الاتصال:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_09/003.png.bf66724d0e5e0548ff904cb74f790ea3.png"><img data-fileid="4655" class="ipsImage ipsImage_thumbnailed" alt="003.thumb.png.50bcb093a1afbb6dc21cfba8bf" src="https://academy.hsoub.com/uploads/monthly_2015_09/003.thumb.png.50bcb093a1afbb6dc21cfba8bf5323f7.png"></a></p><p>كما يمكنك أن ترى، المشكلة هي أنّ المتصفّح غير قادر على التحقق من هوية الخادوم بسبب أنّ شهادته ليست موقّعة من جهة إصدارات شهادات موثوقة بالنسبة إلى المتصفّح لا أكثر. يُظهر لك القسم الذي بالمنتصف أنّ الاتصال مشفّر، وهذا يعني أننا حققنا هدفنا على كلّ حال.</p><h2>الخاتمة</h2><p>لقد قمتَ الآن بإعداد خادوم Nginx الخاصّ بك ليعالج كلًّا من طلبات HTTP وSSL. سيساعدك هذا على التواصل مع زوّارك بشكل أأمن بالإضافة إلى جعل الجهات الخارجية غير قادرة على قراءة تدفّق البيانات الخاصّ بك.</p><p>إذا كنتَ تخطط لإطلاق موقعٍ للعموم وتحتاج SSL، فإنّه يجب عليك شراء شهادة SSL من جهة شهادات موثوقة لموقعك لتجنّب ظهور رسالة التحذير الصفراء لزوّاك موقعك.</p><p>ترجمة -وبتصرف- للمقال: <a rel="external nofollow" href="https://www.digitalocean.com/community/tutorials/how-to-create-an-ssl-certificate-on-nginx-for-ubuntu-14-04">How To Create an SSL Certificate on Nginx for Ubuntu 14.04</a> لصاحبه: Justin Ellingwood.</p><p>حقوق الصورة البارزة: <a rel="external nofollow" target="_blank" href="http://www.freepik.com/free-vector/protection-infographic_793799.htm">Designed by Freepik</a>.</p>
]]></description><guid isPermaLink="false">105</guid><pubDate>Thu, 10 Sep 2015 17:14:40 +0000</pubDate></item><item><title>&#x641;&#x647;&#x645; &#x643;&#x64A;&#x641;&#x64A;&#x629; &#x62A;&#x648;&#x638;&#x64A;&#x641; FastCGI &#x643;&#x648;&#x633;&#x64A;&#x637; &#x644;&#x640; Nginx</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D9%81%D9%87%D9%85-%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%AA%D9%88%D8%B8%D9%8A%D9%81-fastcgi-%D9%83%D9%88%D8%B3%D9%8A%D8%B7-%D9%84%D9%80-nginx-r73/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_08/fastcgi-nginx_(1).png.9fbca909a92b11ca63dac3ee4f43f0d8.png" /></p>

<p dir="rtl">لقد أصبح Nginx أحد أكثر التطبيقات البرمجية المتوفرة لخواديم الويب Web Servers مرونةً وقوة. ولكن إذا ما نظرنا إليه من الناحية التصميمية فإنه يعد أولًا وقبل كل شيء خادومًا وسيطا Proxy Server. إن التركيز على أداء Nginx كوسيط يعني أنه ذو أداء عالي عندما يعمل على معالجة الطلبات بالتعاون مع خواديم أخرى.</p><p dir="rtl" style="text-align: center;"><a href="https://academy.hsoub.com/uploads/monthly_2015_08/fastcgi-nginx_(1).png.22db31d6b0c39e63b184f239f959ed8b.png" class="ipsAttachLink ipsAttachLink_image"><img data-fileid="4326" src="https://academy.hsoub.com/uploads/monthly_2015_08/fastcgi-nginx_(1).thumb.png.69e40473044ad230bef7915c34edabc1.png" class="ipsImage ipsImage_thumbnailed" alt="fastcgi-nginx_(1).thumb.png.69e40473044a"></a></p><p dir="rtl" style="text-align: center;"> </p><p dir="rtl">يمكن لـ Nginx أن يلعب دور الوسيط باستخدام بروتوكولات Protocols http ,FastCGI ,uwsgi ,SCGI ,memcached. سنناقش في هذه المقالة استخدام FastCGI للقيام بالوساطة proxying، فهو يعد واحدًا من أكثر البرتوكولات التي تُستخدم لذلك الغرض.</p><h2 dir="rtl">لماذا نستخدم FastCGI للقيام بالوساطة؟</h2><p dir="rtl">يستخدم FastCGI للقيام بالوساطة ضمن Nginx كي يترجم طلبات المستخدمين Clients لخادوم التطبيقات Application Server الذي لا يقوم بمعالجة طلبات المستخدمين مباشرةً أو الذي لا ينبغي له ذلك. إنّ FastCGI هو برتوكول مبني على برتوكول Common Gateway Interface الأقدم والذي يشار إليه اختصارًا CGI، وقد أُريد من بروتوكول FastCGI أن يحسّن أداء البروتوكول السابق عبر عدم معالجة كل طلب في عملية Process خاصة به. يُستخدم البرتوكول ليمثّل واجهة interface ذات فعالية أكبر مع الخواديم التي تعالج طلبات المحتوى الديناميكي.</p><p dir="rtl">إن معالجة PHP هي أحد حالات الاستخدام use-case الرئيسية لبرتوكول FastCGI ضمن Nginx. وعلى عكس أباتشي Apache، الذي يستطيع معالجة PHP مباشرةً باستخدام وحدة <span style="font-family:courier new,courier,monospace;">mod_php</span>، فإنه ينبغي على Nginx الاعتماد على معالج PHP منفصل لمعالجة طلبات PHP. غالبًا ما تُنجز تلك المعالجة باستخدام <span style="font-family:courier new,courier,monospace;">php_fpm</span> وهو معالج PHP قد اختبر بشكل كبير للعمل مع Nginx.</p><p dir="rtl">يمكن أن يُستخدم Nginx مع FastCGI للعمل مع تطبيقات تستخدم لغاتٍ أخرى طالما أنه يتوفر مكونات مهيّأة للاستجابة لطلبات FastCGI.</p><h2 dir="rtl">أسياسيات قيام FastCGI بالوساطة</h2><p dir="rtl">عادةً ما تتضمن طلبات الوساطة proxying requests عنوان الخادوم الوسيط- Nginx في حالتنا- الذي يوجّه الطلبات من قبل المستخدمين إلى الخادوم الوسيط بينه (الخلفي) Backend Server. يستخدم Nginx التعليمة <span style="font-family:courier new,courier,monospace;">fastcgi_pass</span> للتعريف عن الخادوم الفعلي الذي ستوجّه إليه الطلبات باستخدام برتوكول FastCGI. فمثلًا، لتوجيه أي طلب موافق للغة PHP إلى الخادوم الخلفي المخصص لمعالجة PHP باستخدام برتوكول FastCGI، فقد يبدو المقطع البرمجي للموقع Location Block مشابهًا لما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"># server context

location ~ \.php$ {
   fastcgi_pass 127.0.0.1:9000;
}

. . .
</pre><p dir="rtl">في الواقع، لن يعمل المقطع السابق إذا ما تم تنفيذه على حاله لأنه يقدّم معلوماتٍ قليلةً جدًا. في كل مرّة يتم فيها إنشاء اتصال وسيط Proxy Connection فإنه يجب ترجمة الطلب الأصلي لضمان أن يتمكن الخادوم الخلفي من فهم الطلب المُدار Proxied request. وباعتبار أننا نغيّر البرتوكولات بتمرير الطلب عبر FastCGI فإن ذلك يتطلب بعض العمل الإضافي، سنصطلح في هذه المقالة على عملية تمرير الطلبات عبر FastCGI بتمرير FastCGI أي <span style="font-family:arial,helvetica,sans-serif;">FastCGI pass</span>.</p><p dir="rtl">إنّ القيام بالوساطة من بروتوكول Http وإليه http-to-http Proxying ينطوي بشكل رئيسي على زيادة حجم الترويسة Header ليضمن أن يمتلك الخادوم الخلفي المعلومات التي يحتاجها للرد على الخادوم الوسيط والذي ينوب بدوره عن المستخدم Client، أما FastCGI فهو برتوكول منفصل لا يستطيع قراءة ترويسات Http. مع أخذ ذلك بالحسبان فإن أية معلومات ذات صلة يجب أن تمرّر للخادوم الخلفي عبر وسيلة أخرى.</p><p dir="rtl">إن الطريقة الأساسية لتمرير المعلومات الإضافية عند استخدام برتوكول FastCGI هي باستخدام الإعدادات Parameters. حيث يجب أن يُهيّئ الخادوم الخلفي لقراءة تلك الإعدادات ومعالجتها والتصرّف وفقًا لقيمها. يستطيع Nginx أن يحدّد إعدادات FastCGI باستخدام التعليمة <span style="font-family:courier new,courier,monospace;">fastcgi_param</span>.</p><p dir="rtl">إن الحد الأدنى للإعدادات الواجب ضبطها حتى يعمل FastCGI كوكيل PHP مشابهة لما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"># 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;
}

. . .
</pre><p dir="rtl">لقد قمنا في الإعدادات السابقة بضبط إعدادات FastCGI وهما <span style="font-family:courier new,courier,monospace;">REQUEST_METHOD</span> و <span style="font-family:courier new,courier,monospace;">SCRIPT_FILENAME</span>. إن كل من الإعدادات السابقة ضرورية للخادوم الخلفي حتى يتمكن من فهم طبيعة الطلب. إذ أن الإعداد الأول يخبره بنوع العملية التي يجب أن يقوم بإنجازها، أما الإعداد الثاني فيخبر مجموعة الخواديم Upstream - التي تعالج طلبات الخادوم الوسيط- بالملف الذي يجب أن ينفّذه.</p><p dir="rtl">استخدمنا في المثال بعض المتغيرات variables في Nginx لضبط قيم تلك الإعدادات. سيحوي المتغير <span style="font-family:courier new,courier,monospace;">request_method$ </span>على نوع الوظيفة http method التي طلبها المستخدم.</p><p dir="rtl">من ناحية أخرى فإن قيمة الإعداد <span style="font-family:courier new,courier,monospace;">SCRIPT_FILENAME</span> هي عبارة عن دمج قيمتي المتغيرين <span style="font-family:courier new,courier,monospace;">document_root<span style="line-height: 22.3999996185303px;">$</span></span> و <span style="font-family:courier new,courier,monospace;">fastcgi_script_name</span><span style="line-height: 22.3999996185303px;"><span style="font-family:courier new,courier,monospace;">$</span>.</span> أما المتغير<span style="font-family:courier new,courier,monospace;"> document_root<span style="line-height: 22.3999996185303px;">$</span></span> فسيحوي على مسار المجلد الرئيسي والذي ضبط عبر التعليمة root. سيضبط المتغير <span style="font-family:courier new,courier,monospace;">fastcgi_script_name<span style="line-height: 22.3999996185303px;">$</span></span> بمعرف الموارد الموحد URI المطلوب. إن انتهى  معرف URI للطلب request URI  بالرمز <span style="font-family:courier new,courier,monospace;">(/)</span>، فستلحق قيمة التعليمة <span style="font-family:courier new,courier,monospace;">fastcgi_index</span> في النهاية. إن هذا النوع من المرجعية الذاتية self-referential في تعريف الموقع ممكن لأننا نشغّل معالج FastCGI على نفس الجهاز الذي يشغّل Nginx. فلنلقي نظرة على مثال آخر:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"># 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;
}

. . .</pre><p dir="rtl">إن اختير الموقع location في المثال السابق ليعالج طلبًا في المسار: <span style="font-family:courier new,courier,monospace;">/scripts/test/ </span>فإن قيمة المسار الوسيط <span style="font-family:courier new,courier,monospace;">SCRIPT_FILENAME</span> ستنتج عن دمج قيم تعليمة root ومعرّف URI للطلب بالإضافة للتعليمة<span style="font-family:courier new,courier,monospace;"> fastcgi_index</span>. وبالتالي ستكون قيمة الإعداد في مثالنا هذا هي: <span style="font-family:courier new,courier,monospace;">var/www/html/scripts/test/index.php/</span></p><p dir="rtl">هنالك تعديل هام آخر قمنا به في الإعدادات السابقة، إذ أننا ضبطنا خادوم FastCGI الخلفي FastCGI backend ليستخدم مقبس يونيكس Unix Socket عوضًا عن مقبس شبكة Network socket. يمكن لـ Nginx أن يستخدم أيًا من الواجهتين Interface ليتصل مع مجموعة خواديم FastCGI Upstream. إن كان معالج FastCGI يعمل على نفس الخادوم فعادةً ما يُستحسن استخدام مقبس يونيكس من أجل الأمان.</p><h2 dir="rtl">شرح إعدادات FastCGI</h2><p dir="rtl">هنالك قاعدة أساسية لكتابة نص برمجي (كود) Code قابل للصيانة وهي محاولة اتباع مبدأ DRY أي لا تكرر نفسك "Don’t Repeat Yourself". يساعد ذلك في تقليل الأخطاء بالإضافة لجعل الكود قابلًا لإعادة الاستخدام كما أنها تتيح تنظيمًا أفضل. إنّ أحد أكثر التوصيات الأساسية لإدارة Nginx هي أن تُضبط كل الأوامر في أوسع مجال ممكن لها، تطبّق تلك الأهداف الأساسية على إعداداتNginx أيضًا.</p><p dir="rtl">عند التعامل مع إعدادات الوسيط لـ FastCGI فسيتم تشارك الغالبية العظمى للإعدادات في معظم حالات الاستخدام. بسبب ذلك وبسبب الطريقة التي تعمل بها وحدة الوراثة inheritance التابعة لـ Nginx فإنه دائمًا ما يستحسن تعريف الوسطاء في مجال عام.</p><h3 dir="rtl">التصريح عن تفاصيل إعدادات FastCGI في السياقات الأم Parent Contexts</h3><p dir="rtl">إن أحد الطرق لتقليل التكرار هو التصريح عن تفاصيل الإعدادات في السياق الأم، أي سياق أعلى. يمكن لكل الإعدادات الموجودة خارج التعليمة <span style="font-family:courier new,courier,monospace;">fastcgi_pass </span>أن تُضبط في مستويات أعلى. إذ أنها ستتدفق للأسفل نحو الموقع الذي تم منه تمرير الإعداد. وذلك يعني أنّه يمكن لعدّة أماكن أن تستخدم نفس الإعدادات.</p><p dir="rtl">فمثلًا، يمكننا أن نعدّل على القسم العلوي من المقطع البرمجي السابق لجعله مفيدًا في عدة مواقع:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"># 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;
}

. . .</pre><p dir="rtl">إنّ كلًا من تصاريح<span style="font-family:courier new,courier,monospace;"> fastcgi_param</span> والتعليمة <span style="font-family:courier new,courier,monospace;">fastcgi_index</span> في المثال السابق متوفرين لدى مقطعي الموقع location block الواردين لاحقًا. تلك هي إحدى الطرق لإزالة التكرار.</p><p dir="rtl">بكل الأحوال، إن للإعدادات السابقة مساوئ كبيرة، إن صُرّح عن أية <span style="font-family:courier new,courier,monospace;">fastcgi_param</span> ضمن سياق أدنى فلن تتم وراثة أيٍّ من قيم <span style="font-family:courier new,courier,monospace;">fastcgi_param</span> ضمن السياقات العليا (السياقات الأم). أي إما أن تستخدم القيم الموروثة فقط أو لا تستخدم أيًا منها.</p><p dir="rtl">تُعد التعليمة <span style="font-family:courier new,courier,monospace;">fastcgi_param</span> مصفوفةً array من التعليمات في لغةNginx. من منظور المستخدمين فإن أي مصفوفة تعليمات هي بشكل أساسي تعليمة يمكن استخدامها أكثر من مرة ضمن سياق واحد. وأي تصريح لاحق سيضيف معلومات جديدة إلى ما يعرفه Nginx من التصريح السابق. لقد صمّمت التعليمة <span style="font-family:courier new,courier,monospace;">fastcgi_param</span> كمصفوفة من التعليمات حتى تسمح للمستخدمين بضبط عدّة إعدادات.</p><p dir="rtl">تورّث أي مصفوفة تعليمات إلى سياق أدنى، أو سياق ابن child context، بطريقة مختلفة عن بعض التعليمات الأخرى. ستورّث معلومات مصفوفة التعليمات إلى سياقات الأبناء فقط إن لم تكن موجودة في أي مكان ضمن سياق الابن. وذلك يعني أنك إن استخدمت تعليمة <span style="font-family:courier new,courier,monospace;">fastcgi_param</span> ضمن موقعك فإنها ستمحي القيم الموروثة من السياق الأعلى تمامًا.</p><p dir="rtl">فمثلًا، يمكننا التعديل قليلًا على الإعدادات السابقة كما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"># 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;
}

. . .</pre><p dir="rtl">قد تعتقد للوهلة الأولى أنه ستتم وراثة الإعدادات <span style="font-family:courier new,courier,monospace;">REQUEST_METHOD</span> و <span style="font-family:courier new,courier,monospace;">SCRIPT_FILENAME</span> في مقطع لموقع ثانٍ، بالإضافة لتوفير الإعداد <span style="font-family:courier new,courier,monospace;">QUERY_STRING</span> ضمن ذلك السياق المحدّد.</p><p dir="rtl">لكن ما يحدث في الحقيقة هو أنّ كل قيم <span style="font-family:courier new,courier,monospace;">fastcgi_param</span> التابعة للأب ستُمحى ضمن السياق الثاني، وسيضبط الإعداد <span style="font-family:courier new,courier,monospace;">QUERY_STRING </span>فقط. بينما ستبقى الإعدادات <span style="font-family:courier new,courier,monospace;">REQUEST_METHOD</span> و <span style="font-family:courier new,courier,monospace;">SCRIPT_FILE</span> دون ضبط.</p><h3 dir="rtl">ملاحظة حول القيم المتعدّدة للوسطاء ضمن نفس السياق</h3><p dir="rtl">يجدر بالذكر هنا أثار ضبط قيم متعدّدة لنفس الإعدادات ضمن سياق واحد. فلنأخذ المثال التالي لمناقشة ذلك:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"># 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;
}

. . .</pre><p dir="rtl">في المثال السابق، قمنا بضبط الإعدادات <span style="font-family:courier new,courier,monospace;">TEST</span> و <span style="font-family:courier new,courier,monospace;">DOCUMENT_ROOT</span> عدّة مرات ضمن سياقٍ واحد. باعتبار أن <span style="font-family:courier new,courier,monospace;">fastcgi_param</span> مصفوفة تعليمات فإن كلّ تصريح لاحق سيُضاف إلى سجلات Nginx الداخلية. سيحظى الإعداد <span style="font-family:courier new,courier,monospace;">TEST</span> بعدة تصاريح ضمن المصفوفة يضبط من خلالها بالقيم <span style="font-family:courier new,courier,monospace;">one</span> و <span style="font-family:courier new,courier,monospace;">two</span> و <span style="font-family:courier new,courier,monospace;">three</span>.</p><p dir="rtl">من المهم أن ندرك هنا أنّ كلّ ذلك سيمرّر إلى خادوم FastCGI الخلفي دون أي معالجة إضافية من Nginx. يعني ذلك أنّ القرار حول كيفية معالجة تلك القيم يعود بشكل كامل إلى معالج Nginx المختار. للأسف، على اختلاف معالجات FastCGI فإن كلًا منها يعالج القيم الممرّرة بطريقة تختلف تمامًا عن الأخرى.</p><p dir="rtl">فمثلًا، إن استقبلت PHP-FPM الإعدادات السابقة فستفسر القيم النهائية لتحل محل أي قيم سابقة. بهذه الحالة سيُضبط الإعداد <span style="font-family:courier new,courier,monospace;">TEST</span> بالقيمة <span style="font-family:courier new,courier,monospace;">three</span>. وبالمثل سيضبط الإعداد <span style="font-family:courier new,courier,monospace;">DOCUMENT_ROOT</span> بالقيمة <span style="font-family:courier new,courier,monospace;">override</span>.</p><p dir="rtl">ولكن إن مُرّرت القيم السابقة لخادومٍ مثل FsgiWrap، فستفسَّر القيم بشكل مختلف كثيرًا. ففي البداية سيقوم بتمرير تمهيدي ليقرر أي القيم ينبغي استخدامها لتشغيل البريمج script. وسيستخدم القيمة <span style="font-family:courier new,courier,monospace;">initial</span> للإعداد <span style="font-family:courier new,courier,monospace;">DOCUMENT_ROOT</span> ليبحث عن البريمج. إلا أنه عندما سيمرّر القيم الفعلية للبريمج فسيمرر القيم الأخيرة كما يفعل <span style="font-family:courier new,courier,monospace;">PHP-FPM</span> تمامًا.</p><p dir="rtl">إن التضارب inconsistency وعدم إمكانية التنبؤ unpredictability يعني أنك لا تستطيع، بل أنه لا ينبغي لك، أن تعتمد على الخادوم الخلفي لتفسير نيّتك بشكل صحيح إذا ما ضبطّت الإعدادات أكثر من مرّة واحدة. فالطريقة الوحيدة الآمنة هي بالتصريح عن كل إعداد مرّةً واحدة. يعني ذلك أيضًا أنه لا يوجد طريقة آمنة لإعادة تعريف <span style="font-family:courier new,courier,monospace;">overriding</span> القيمة الافتراضية باستخدام تعليمة <span style="font-family:courier new,courier,monospace;">fastcgi_param</span>.</p><h3 dir="rtl">طريقة تضمين إعدادات مكتوبة بملف منفصل ضمن ملف إعدادات FastCGI الأساسي</h3><p dir="rtl">يوجد طريقة أخرى لتفصل بنود إعداداتك الشائعة، أي التي تقوم بها بشكل متكرّر. بإمكاننا استخدام تعليمة <span style="font-family:courier new,courier,monospace;">include</span> لقراءة محتوى ملف منفصل وتضمينها في الموقع الذي تم فيه التصريح عن التعليمة.</p><p dir="rtl">يعني ذلك أنه بإمكاننا الاحتفاظ بكل الإعدادات الشائعة في ملف واحد ومن ثمّ تضمينه في أي مكان ضمن إعداداتنا إن اقتضى الأمر. وباعتبار أن Nginx سيضع محتوى الملف حيثما وجدت تعليمة <span style="font-family:courier new,courier,monospace;">include</span> فلن نكون قد ورثنا من سياق الأم إلى سياق الابن. سيمنع ذلك قيم <span style="font-family:courier new,courier,monospace;">fastcgi_param</span> من أن تُمحى وسيمنحنا القدرة على ضبط إعدادات إضافية عند الحاجة.</p><p dir="rtl">يمكننا في البداية أن نضبط قيم إعدادات FastCGI الشائعة لدينا في ملف منفصل وتخزينه ضمن المسار الحاوي على ملف الإعدادات الأصلي، سنقوم بتسمية ذلك الملف<span style="font-family:courier new,courier,monospace;"> fastcgi_common</span>:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;</pre><p dir="rtl">يمكننا الآن أن نستورد محتوى الملف حيثما نريد استخدام قيم تلك الإعدادات:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"># 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;
}

. . .
</pre><p dir="rtl">لقد قمنا هنا بنقل قيم بعض الإعدادات الشائعة إلى ملف اسمه<span style="font-family:courier new,courier,monospace;"> fastcgi_common</span> والموجود في المسار الافتراضي الحاوي على إعدادات NGINX. ثمّ نستورد القيم المصرّح عنها في الملف عندما نحتاج لإدخالها. هنالك العديد من الأمور التي يجب ملاحظتها حول هذه الإعدادات:</p><p dir="rtl">أولًا، لم نضع في الملف الذي ننوي استيراده أي قيم قد نرغب بتخصيصها وفقًا لموقعه، بسبب مشكلة التفسير التي ذكرناها سابقًا والتي تحدث عندما نضبط عدة قيم لنفس الإعداد، ولأنه لا يمكن ضبط التعليمات التي ليست على شكل مصفوفة non-array directives إلا مرّةً واحدة خلال السياق، لذا نضع العناصر التي لن نرغب بتغييرها فقط في الملف المشترك. إنّ كلّ تعليمة (أو إعداد أساسي) قد نرغب بتخصيصه وفقًا لموقعه يجب ألا يضمّن في الملف المشترك.</p><p dir="rtl">الأمر الآخر الذي ربما قد لاحظته أننا قد ضبطنا بعض إعدادات FastCGI الإضافية في المقطع البرمجي للموقع الثاني. وتلك هي الإمكانية التي كنا نأمل الوصول إليها. تمكّنا من إضافة إعدادات <span style="font-family:courier new,courier,monospace;">fastcgi_param</span> إضافية كلما اقتضت الحاجة ومن دون أن تُمسح القيم المشتركة.</p><h3 dir="rtl">استخدام الملف fastcgi_params أو الملف fastcgi.conf</h3><p dir="rtl">بأخذ الاستراتيجية السابقة بالحسبان فإن مطوري Nginx والعديد من فرق تحزيم التوزيعات distribution packaging teams قد عملوا على توفير مجموعة من الإعدادات شائعة الاستخدام والتي يمكن أن تضمنها في مواقع تمرير FastCGI أي FastCGI pass location. تدعى تلك الإعدادات <span style="font-family:courier new,courier,monospace;">fastcgi_params</span> أو <span style="font-family:courier new,courier,monospace;">fastcgi.conf</span>.</p><p>إنّ هذين الملفين متشابهين كثيرًا ولكن مع وجود اختلاف وحيد ممثّل في تمرير قيم متعدّدة لإعداد واحد، وهي المشكلة التي ناقشناها سابقًا، لا يحتوي <span style="font-family:courier new,courier,monospace;">fastcgi_params</span> على تصريح عن الإعداد <span style="font-family:courier new,courier,monospace;">SCRIPT_FILENAME</span> على عكس الملف <span style="font-family:courier new,courier,monospace;">fastcgi.conf</span>.</p><p>لقد أوجِد الملف <span style="font-family:courier new,courier,monospace;">fastcgi_params</span> منذ وقتٍ أبعد. ثم ظهرت الحاجة لإنشاء ملف جديد عندما اتُّخذ قرارٌ لتوفير قيمةٍ افتراضية للإعداد <span style="font-family:courier new,courier,monospace;">SCRIPT_FILENAME</span> وذلك حتى نتجنب تجزئة الإعدادات التي تعتمد على <span style="font-family:courier new,courier,monospace;">fastcgi_params</span>، إن عدم فعل ذلك قد يؤدي إلى ضبط ذلك الإعداد في كل من الملف المشترك وموقع تمرير FastCGI.</p><p>العديد من مشرفي تحزيم التوزيعات الشهيرة قد صوّتوا لتضمين إحدى هذين الملفين فقط أو لتطابق محتواهما تمامًا. إن توفّر لديك أحد هذين الملفين فقط فاستخدمه وعدّل عليه كما تشاء ليناسب احتياجاتك.</p><p dir="rtl">إن كان كلا الملفين متوفرين لك، فقد يكون من الأفضل أن تضمّن الملف<span style="font-family:courier new,courier,monospace;"> fastcgi.conf</span> في معظم مواقع تمرير FastCGI، وذلك لأنه يتضمّن تصريحًا عن الإعداد<span style="font-family:courier new,courier,monospace;"> SCRIPT_FILENAME</span>. عادةً ما يُرغب بذلك إلا أنّ هنالك بعض الحالات التي قد ترغب فيها بتخصص هذه القيمة.</p><p dir="rtl">يمكن تضمين هذين الملفين عبر الإشارة إلى موقعهما بالنسبة إلى المجلد الجذر root الحاوي على إعدادات Nginx. إن مسار المجلد الجذر لإعداداتNginx يكون مشابهًا لما يلي: <span style="font-family:courier new,courier,monospace;">etc/nginx/ </span>وذلك إن تم تثبيته باستخدام مدير الحزم package manager.</p><p dir="rtl">يمكنك تضمين الملفين كما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"># server context

location ~ \.php$ {
   include fastcgi_params;
   # You would use "fastcgi_param SCRIPT_FILENAME . . ." here afterwards
   . . .
}</pre><p dir="rtl">أو كما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"># server context

location ~ \.php$ {
   include fastcgi.conf;
   . . .
}</pre><h2 dir="rtl">تعليمات وإعدادات ومتغيرات FastCGI المهمّة</h2><p dir="rtl">لقد قمنا في القسم السابق بضبط عدد لا بأس به من الإعدادات بهدف شرح مفاهيمٍ أخرى، وعادةً ما كنا نضبطها بمتغيرات Nginx. كما أننا قدمنا بعض تعليمات FastCGI من دون شرحٍ وفير. سنناقش في هذا القسم بعض التعليمات شائعة الضبط، وبعض الإعدادات التي قد تحتاج لتعديلها، بالإضافة لبعض المتغيرات التي قد تحوي معلوماتٍ تحتاجها.</p><h3 dir="rtl">تعليمات FastCGI الشائعة:</h3><p dir="rtl">سنستعرض فيما يلي بعض أكثر التعليمات المفيدة للعمل مع تمريرات FastCGI:</p><ul dir="rtl"><li><strong><span style="font-family:courier new,courier,monospace;">fastcgi_pass</span></strong>: هي التعليمة التي تقوم بعملية تمرير الطلبات الموجودة ضمن السياق الحالي إلى الخادوم الخلفي. تعرٍّف هذه التعليمة الموقع الذي يمكن الوصول عبره إلى معالج FastCGI.</li><li><strong><span style="font-family:courier new,courier,monospace;">fastcgi_param</span></strong>: وهي مصفوفة التعليمات التي يمكن استخدامها لضبط قيم الإعدادات. غالبًا ما يقترن استخدام هذه التعليمة مع متغيرات Nginx لضبط وسطاء FastCGI بالقيم المحدّدة في الطلب.</li><li><strong><span style="font-family:courier new,courier,monospace;">try_files</span></strong>: ليست تعليمةً خاصة بـ FastCGI، إلا أنها استخدامها شائع في موقع تمرير FastCGI، عادةً ما تستخدم كجزء من إجراء الطلب الوقائي للتأكد من وجود الملف المطلوب قبل تمريره إلى معالج FastCGI.</li><li><strong><span style="font-family:courier new,courier,monospace;">include</span></strong>: مجدّدًا، ليست تعليمةً خاصة بـ FastCGI، إلا أنها تستخدم بكثافة عالية في سياقات تمرير FastCGI أي FastCGI pass contexts. غالبًا ما تستخدم لتضمين تفاصيل الإعدادات الشائعة والمشتركة بين عدّة مواقع.</li><li><strong><span style="font-family:courier new,courier,monospace;">fastcgi_split_path_info</span></strong>: تستخدم هذه التعليمة لتعريف التعابير النمطية regular expression مع مجموعتي التقاط captured groups. تُستخدم المجموعة الأولى كقيمة للمتغير <span style="font-family:courier new,courier,monospace;">fastcgi_script_name$</span> بينما تستخدم المجموعة الثانية كقيمة للمتغير <span style="font-family:courier new,courier,monospace;">fastcgi_path_info$</span>. عادةً ما تستخدم كلا المجموعتين لتحليل parse الطلب بشكل صحيح حتى يعرف المعالج أي الأجزاء المشكّلة للطلب تمثل الملفات الواجب تشغيلها وأي الأجزاء تمثل المعلومات الإضافية الواجب تمريرها إلى السكربت.</li><li><strong><span style="font-family:courier new,courier,monospace;">fastcgi_index</span></strong>: تعرّف هذه التعليمة ملف الفهرسة index file الذي ينبغي الحاقه بقيمة الإعداد <span style="font-family:courier new,courier,monospace;">fastcgi_script_name$</span> والتي تنتهي بـ (<span style="font-family:courier new,courier,monospace;">/.</span>عادةً ما يكون ذلك مفيدًا إن كان الإعداد <span style="font-family:courier new,courier,monospace;">SCRIPT_FILENAME</span> مضبوطًا بقيمة <span style="font-family:courier new,courier,monospace;">document_root$fastcgi_script_name$</span> وكان مقطع الموقع معدّا لقبول الطلبات الحاوية على معلومات المسار الإضافية.</li><li><strong><span style="font-family:courier new,courier,monospace;">fastcgi_intercept_errors</span></strong>: تعرّف هذه التعليمة فيما إذا كان ينبغي معالجة الأخطاء المتلقاة من خادوم FastCGI أو تمريرها مباشرةً إلى المستخدم.</li></ul><p dir="rtl">تمثّل التعليمات السابقة أكثر التعليمات التي ستستخدمها عندما تصمّم تمرير FastCGI نموذجي. ومع أنك قد لا تستخدمها كلها بنفس الوقت، إلا أنك ستلاحظ أنها تتفاعل بشكل وثيق جدًا مع إعدادات ومتغيرات FastCGI التي سنتحدث عنها فيما يلي.</p><h3 dir="rtl">المتغيرات شائعة الاستخدام مع FastCGI:</h3><p dir="rtl">قبل أن نتمكن من الكلام عن الإعدادات التي ستستخدمها على الأرجح مع تمريرات FastCGI، علينا الكلام قليلًا عن بعض نتغيرات Nginx الشائعة والتي ستستفيد منها في ضبط تلك الإعدادات. تعرّف وحدة FastCGI الخاصة بـ Nginx بـ Nginx’s FastCGI module بعض تلك المتغيرات، إلا أن معظمها من الوحدة الأساسية Core module.</p><ul><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">query_string$</span></strong> أو <strong><span style="font-family:courier new,courier,monospace;">args$</span></strong>: هي القيم الممرّرة arguments في الطلب الأصلي للمستخدم.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">is_args$</span></strong>: ستساوي قيمتها “?” إن حوى الطلب على قيم ممرّرة وإلا فستُضبط قيمتها بسلسلة نصية فارغة. يفيد ذلك عند إنشاء إعدادات قد تأخذ قيمًا أو لا تأخذ.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">request_method$</span></strong>: يشير هذا المتغير إلى نوع الطلب request method المستخدم الأصلي. يمكن أن يفيد ذلك بتحديد فيما إذا كان ينبغي السماح لعملية operation ما في السياق الحالي أم لا.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">content_type$</span></strong>: يضبط هذا المتغير بقيمة الحقل content-type الموجود في ترويسة الطلب. يحتاج الوسيط إلى هذه المعلومات إن كان نوع الطلب المستخدم هو POST وذلك حتى يتمكن من معالجة المحتويات اللاحقة بشكل صحيح.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">content_length$</span></strong>: يضبط هذا المتغير قيمة الحقل Content-Length الموجود في ترويسة المستخدم. هذه المعلومات لازمة لأي طلب للمستخدم من النوع POST.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">fastcgi_script_name$</span></strong>: يحتوي هذا المتغير على ملف السكربت الذي يجب تشغيله. إن انتهى الطلب بـ (/) فستحلق قيمة التعليمة fastcgi_index إلى النهاية. وبحال استخدام التعليمة fast_split_path_info فستضبط قيمة هذا المتحول بالمجموعة اللاقطة الأولى المعرّفة من قبل التعليمة. ينبغي على قيمة هذا المتغير أن تشير إلى الملف الفعلي الذي يجب تشغيله.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">request_filename$</span></strong>: يحتوي هذا المتغير على مسار الملف المطلوب. يحصل المتغير على هذه القيمة بأخذ المسار الحالي لمجلد المستندات الأساسي document root، مع أخذ كل من التعليمتين root و alias بعين الاعتبار. بالإضافة لأخذ قيمة المتغير fastcgi_script_name$. تعد هذه الطريقة مرنةً للغاية لإسناد قيمة للإعداد SCRIPT_FILENAME.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">request_uri$</span></strong>: يحتوي هذا المتغير على الطلب كاملًا كما استُقبل من المستخدم، يتضمّن ذلك السكربت، أية معلومات مسار إضافية، بالإضافة إلى أي عبارة استعلام query string.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">fastcgi_path_info$</span></strong>: يحتوي هذا المتغير على معلومات المسار الإضافية التي قد تتوفّر بعد اسم السكربت في الطلب. وقد تحوي قيمته أحيانًا على موقعٍ آخر ينبغي على السكربت أن يعلم به حتى يتم تنفيذه. يحصل هذا المتغير على قيمته من مجموعة التعابير النمطية regex الثانية عند استخدام تعليمة fastcgi_split_path_info.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">document_root$</span></strong>: يحتوي هذا المتغير على المسار الحالي لمجلد المستندات الأساسي. وسيتم ضبطه تبعًا لتعليمتي root و alias.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">uri$</span></strong>: يحتوي هذا المتغير على قيمة URI الحالية بعد تسويتها normalization. وبما أن تعليمات معينة تقوم بإعادة الكتابة rewrite أو بإعادة التوجيه الداخلي internallly redirect يمكن أن تترك أثرًا على معرّف URI فإن هذا المتغير سيستخلّص تلك التعديلات.</p></li></ul><p dir="rtl">كما ترى، يوجد العديد من المتغيرات المتوفّرة لك عندما تقرّر كيف تضبط إعدادات FastCGI. العديد منها متشابه إلا أنها تملك بعض الفوارق الصغيرة والتي ستنعكس على تنفيذ بريمجك.</p><h3 dir="rtl">إعدادات FastCGI الشائعة:</h3><p dir="rtl">تمثّل إعدادات FastCGI المعلومات التي نرغب بجعلها متاحةً لمعالج FastCGI - الذي نرسل إليه الطلبات- على شكل أزواج مفتاح-قيمة key-value. لن تحتاج كلّ التطبيقات إلى نفس الإعدادات لذلك غالبًا ما ستحتاج لمراجعة توثيق التطبيق.</p><p dir="rtl">تُعد بعض تلك الإعدادات ضروريةً للمعالج حتى يتمكن من تحديد السكربت - الذي ينبغي تشغيله- بشكل صحيح. بينما أُتيح البعض الآخر للسكربت، إذ أنها قد تغيّر سلوكه إن كان معدًّا ليعتمد على مجموعةٍ من الإعدادات.</p><ul><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">QUERY_STRING</span></strong>: ينبغي أن يُضبط هذا الإعداد بأي عبارة استعلام مقدّمة من قِبل المستخدم. عادةً ما تكون على شكل أزواج مفتاح-قيمة مزوّدةً بعد إشارة "?"  في معرّف URI. عادةً ما يُضبط هذا الإعداد بقيمة أحد المتحولين query_string$ أو args$، إذ ينبغي عليهما أن يحويا على نفس البيانات.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">REQUEST_METHOD</span></strong>: يدّل هذا الإعداد معالجَ FastCGI على نوع الإجراء الذي طلبه المستخدم. وهو أحد الإعدادات القلائل التي يجب ضبطها حتى يتم التمرير بشكل صحيح.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">CONTENT_TYPE</span></strong>: إن ضُبط نوع الطلب في الإعداد السابق ليكون POST فيجب أن يُضبط هذا الإعداد. يشير هذا الإعداد إلى نوع البيانات التي ينبغي على معالج FastCGI توقعها. غالبًا ما يضبط هذا الإعداد بالمتغير content_type$ فقط، والذي يضبط بدوره وفقًا للمعلومات المأخودة من الطلب الأصلي.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">CONTENT_LENGTH</span></strong>: يجب أن يضبط هذا الإعداد إن كان نوع الطلب هو POST. يشير هذا <span style="line-height: 22.3999996185303px; text-align: right;">الإعداد</span> إلى طول المحتوى، وغالبًا ما يضبط بالمتغير content_length$ والذي يأخذ قيمته من المعلومات المتوفّرة في طلب المستخدم الأصلي.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">SCRIPT_NAME</span></strong>: يستخدم هذا <span style="line-height: 22.3999996185303px; text-align: right;">الإعداد</span> ليُشير إلى اسم السركبت الأساسي الذي يجب تشغيله. وهو <span style="line-height: 22.3999996185303px; text-align: right;">إعداد</span> هامٌ للغاية يمكن ضبطه بعدّة طرق وفقًا لاحتياجاتك. عادةً ما يُضبط بالمتغير fastcgi_script_name$ والذي يجب أن يكون معرّف URI للطلب، أو معرف URI للطلب متبوعًا بـ fastcgi_index إن انتهى المعرّف بـ (/)، أو المجموعة اللاقطة الأولى إن استُخدم fastcgi_fix_path_info.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">SCRIPT_FILENAME</span></strong>: يحدّد هذا الإعداد الموقع الفعلي على القرص للسكربت الذي يجب تشغيله. وبسبب ارتباطه مع الإعداد SCRIPT_NAME، تقترح بعض أدلة الاستخدام Guides أن تستعيض عن استخدامه بالمتغيرين document_root$fastcgi_script_name$. يتوفر بديلٌ آخر يملك العديد من المحاسن وهو استخدام request_filename$.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">REQUEST_URI</span></strong>: ينبغي أن تحوي على معرّف URI للطلب كاملًا ومن من دون تعديل، بالإضافة إلى السكربت الذي يجب تشغيله، ومعلومات المسار الإضافية، وأي قيمٍ ممرّرة. تفضّل بعض التطبيقات أن تحلّل تلك المعلومات بنفسها، ويقدم هذا الإعداد المعلومات اللازمة لهم للقيام بذلك.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">PATH_INFO</span></strong>: إن ضُبط cgi.fix_pathinfo بالقيمة “1” في ملف إعدادات PHP، فسيحوي هذا الإعداد على أية معلومات مسار إضافية additional path information مذكورة بعد اسم السكربت. عادةً ما يُستخدم هذا <span style="line-height: 22.3999996185303px; text-align: right;">الإعداد</span> لتعريف الملف الممرّر file argument والذي سيحدّد تصرُّف السكربت. قد يترتّب على ضبط cgi.fix_pathinfo بالقيمة "1" آثارٌ أمنية إن لم تكن طلبات السكربت قد فُحصت بوسائل أخرى (سنناقش ذلك لاحقًا). قد يُضبط هذا <span style="line-height: 22.3999996185303px; text-align: right;">الإعداد</span> أحيانًا بالمتغير fastcgi_path_info$ والذي يحوي على المجموعة اللاقطة لثانية من التعليمة fastcgi_split_path_info. وفي حالاتٍ أخرى، سيكون هنالك حاجةٌ لاستخدام متغير مؤقت، إذ أنه يمكن لمعالجةٍ أخرى أن تمسح تلك القيمة أحيانًا.</p></li><li dir="rtl"><p dir="rtl"><strong><span style="font-family:courier new,courier,monospace;">PATH_TRANSLATED</span></strong>: يربط هذا <span style="line-height: 22.3999996185303px; text-align: right;">الإعداد</span> بين معلومات المسار المحتواة ضمن PATH_INFO والمسار الفعلي على نظام الملفات filesysem path. عادةً ما يُضبط هذا <span style="line-height: 22.3999996185303px; text-align: right;">الإعداد</span> بـ document_root$fastcgi_path_info$، ولكن أحيانًا يجب استبدال المتغير الأخير بالمتغير المؤقت الذي أشرنا إليه سابقًا.</p></li></ul><h2 dir="rtl">التحقق من الطلبات قبل تمريرها إلى FastCGI    </h2><p dir="rtl">إنّ أحد المواضيع بالغة الأهمية التي لم نغطها حتى الآن هو كيفية تمرير الطلبات الديناميكية للخادوم بشكلٍ آمن. إن تمرير كلّ الطلبات للخادوم الخلفي بغض النظر عن صحتها لا يسبب خفض فاعلية الخادوم فحسب، بل إنه خَطِرٌ أيضًا. إذ أنه من الممكن للمهاجمين إنشاء طلباتٍ خبيثة في محاولةٍ منهم لتشغيل نص برمجي ما. في الواقع، حتى نعالج هذا الخطأ علينا أن نضمن إرسال الطلبات الصالحة فقط لمعالج FastCGI، يمكننا القيام بذلك بعدة طرق وذلك تبعًا لاحتياجات إعدادنا الخاص وفيما إن كان معالج FastCGI يعمل على نفس النظام المشغِّل لـ Nginx أم لا.  </p><p dir="rtl">إحدى القواعد الأساسية التي يجب أن تحدد لنا كيفية ضبط الإعدادات، هي أنه علينا ألا نسمح بأي معالجة أو تفسير لملفات المستخدم. إذ أنه من السهل نسبيًا على المستخدمين المخادعين malicious users أن يضمّنوا نصًا برمجيًا صالحًا valid code في ملفاتٍ تبدو في الظاهر أنها ملفاتٍ غيرُ مؤذيةٍ كالصور. حالما يُرفع ملفٌ كهذا إلى الخادوم علينا أن نضمن ألا يجد طريقًا للوصول إلى معالج FastCGI.</p><p dir="rtl">إنّ المشكلة الأساسية التي نحاول حلها هنا هي في الواقع محدّدةٌ في مواصفات CGI specification. تتيح لك تلك المواصفات تحديد ملف السكربت الذي ترغب بتشغيله متبوعًا بمعلومات المسار الإضافية التي يمكن للسكربت أن يستخدمها. إن نموذج التنفيذ هذا يسمح للمستخدمين بطلب معرف URI قد يبدو كسكربت صالح legitimate، إلا أن الجزء الذي سيتم تنفيذه سيكون مذكورًا قبله في المسار.</p><p dir="rtl">فالنأخذ مثلًا طلبًا لـ: <span style="font-family:courier new,courier,monospace;">test.jpg/index.php/ </span>إن كانت إعداداتك تمرّر ببساطة كل الطلبات التي تنتهي بـ <span style="font-family:courier new,courier,monospace;">.php</span> إلى المعالج دون التحقق من مدى صحتها فسيتحقق المعالج، إن كان يحقّق المواصفات، من وجود ذلك الموقع وسينفذّه إن أمكن. أما إذا لم يجد الملف فسيتّبع المواصفات وسيحاول تنفيذ الملف <span style="font-family:courier new,courier,monospace;">test.jpg/ </span>وسيعتبر أن <span style="font-family:courier new,courier,monospace;">index.php/</span> تمثّل معلومات المسار الإضافية الخاصة بالسكربت. كما ترى يمكن لذلك أن يسمح ببعض النتائج غير المرغوب بها إطلاقًا عندما يجتمع مع فكرة رفع المستخدم للملفات.</p><p dir="rtl">هنالك مجموعة من الطرق المختلفة لحل تلك المشكلة. أسهل تلك الطرق هو ببساطة تعطيل خاصية معالجة معلومات المسار من قِبَل المعالج، وذلك إن كان تطبيقك لا يعتمد على تلك المعلومات الإضافية. يمكن تعطيل تلك الخاصية لدى PHP-FPM من خلال الملف <span style="font-family:courier new,courier,monospace;">php.ini</span>، فمثلًا إن كنت تستخدم نظام أوبونتو Ubuntu فيمكن تحرير الملف التالي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo nano /etc/php5/fpm/php.ini</pre><p dir="rtl">ببساطة، ابحث عن الخيار cgi.fix_pathinfo وألغِ تعليقه ثم اضبطه بالقيمة “0” لتعطّل هذه “الميزة” كما يلي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">cgi.fix_pathinfo=0</pre><p dir="rtl">أعد تشغيل عملية PHP-FPM حتى تأخذ التعديلات حيّز التنفيذ:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo service php5-fpm restart</pre><p dir="rtl">سيدفع ذلك PHP لتنفيذ الجزء الأخير من المسار فقط، وبالتالي ففي المثال السابق إن لم يكن الملف <span style="font-family:courier new,courier,monospace;">test.jpg/index.php/ </span>موجودًا فسيصدر PHP خطأ عوضًا عن محاولة تنفيذ الملف <span style="font-family:courier new,courier,monospace;">test.jpg/ </span>إذا كان معالج FastCGI يعمل على نفس الخادوم الذي يُشغل Nginx فلدينا خيارٌ آخر وهو ببساطةٍ التحقق من وجود الملفات على القرص قبل تمريرها إلى المعالج. فإذا لم يكن الملف التالي موجودًا <span style="font-family:courier new,courier,monospace;">test.jpg/index.php/ </span>فسيصدر خطأ. أما إن كان موجودًا فسيُرسل إلى الخادوم الخلفي لتتم معالجته. سينتج عن ذلك عمليًا سلوكٌ يشبه إلى حد بعيد ما رأيناه سابقًا.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">location ~ \.php$ {
       try_files $uri =404;
       . . .
}</pre><p dir="rtl">إن كان تطبيقك يعتمد في سلوكه على معلومات المسار حتى يقوم بعملية التفسير بشكل صحيح فما زال بإمكانك السماح بتطبيق ذلك السلوك بأمان عبر القيام بالاختبارات قبل اتخاذ قرارٍ بإرسال الطلب إلى الخادوم الخلفي. فمثلًا، بإمكاننا مطابقة المجلدات التي نخرن فيها الملفات المرفوعة غير الموثوقة تحديدًا وضمان ألا تمرّر إلى المعالج. مثلًا، إن كان مجلد الملفات المرفوعة على المسار: <span style="font-family:courier new,courier,monospace;">/uploads/ </span>فعلينا إنشاء مقطع موقع يتم مطابقته قبل أن يتم تقييم أي عبارة منتظمة:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">location ^~ /uploads {

}</pre><p dir="rtl">بإمكاننا إضافة أي نوع من معالجة ملفات PHP داخل المقطع البرمجي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">location ^~ /uploads {
   location ~* \.php$ { return 403; }
}</pre><p dir="rtl">سيعمل الموقع الأم parent location على مطابقة أي طلب يبدأ بـ <span style="font-family:courier new,courier,monospace;">uploads/ </span>وأيُّ طلب يتعامل مع ملفات PHP سيُرد عليه بالخطأ 403 عوضًا عن إرساله إلى الخادوم الخلفي.</p><p dir="rtl">يمكنك أيضًا استخدام التعليمة <span style="font-family:courier new,courier,monospace;">fastcgi_splite_path_info</span> للتعريف يدويًا عن الجزء من الطلب، الذي يجب تفسيره كسكربت والجزء الدي يجب تعريفه على أنه معلومات المسار الإضافية باستخدام التعابير النمطية. يسمح لك ذلك بأن تستمر في الاعتماد على وظيفة معلومات المسار، على أن تعرّف بدقة ما تعتبره بريمجًا وما تعتبره مسارًا.</p><p dir="rtl">فمثلًا، بإمكاننا إعداد مقطع لموقع يقوم باعتبار أن أول جزء مكون للمسار ينتهي ب .php هو السكربت الذي ينبغي تشغيله. ويعتبر الباقي معلومات المسار الإضافية. وذلك يعني أنه من أجل الطلب: <span style="font-family:courier new,courier,monospace;">test.jpg/index.php/ </span>فسيتم إرسال كامل المسار إلى المعالج باعتباره اسم السكربت ولا يحوي معلومات مسار إضافية.</p><p dir="rtl">يمكن أن يكون الموقع كالآتي:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">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;
}</pre><p dir="rtl">ينبغي أن يعمل المقطع السابق عندما تكون قيمة <span style="font-family:courier new,courier,monospace;">cgi.fix_pathinfo</span> في إعداد PHP مضبوطةً بالقيمة "1" حتى تسمح بمعلومات المسار الإضافية. وهنا، إن مقطع الموقع السابق لا يطابق الطلبات التي تنتهي بـ <span style="font-family:courier new,courier,monospace;">.php</span> وحسب، بل تلك التي تنتهي بـ .php قبل إشارة "/" مباشرةً والتي تدل على مكون إضافي يتبع مسار المجلد directory.</p><p dir="rtl">تعرّف التعليمة <span style="font-family:courier new,courier,monospace;">fastcgi_split_path_info</span> داخل المقطع مجموعتين لاقطتين captured group باستخدام التعابير النمطية. تطابق المجموعة الأولى الجزء الممتد من بداية عنوان URI وحتى أول ورود لـ <span style="font-family:courier new,courier,monospace;">.php</span> ويضعه في المتغير <span style="font-family:courier new,courier,monospace;">fastcgi_script_name$</span>. ومن ثم يضع أي معلومة مذكورة في الجزء الباقي، والممتد بدءًا من النقطة التي انتهى عندها الجزء الأول وحتى نهاية العنوان، في المجموعة اللاقطة الثانية والتي تخزّن في متغير يدعى <span style="font-family:courier new,courier,monospace;">fastcgi_path_info<span style="line-height: 22.3999996185303px;">$</span>.</span></p><p dir="rtl">نستخدم التعليمة set لنخزن القيمة المحفوظة في <span style="font-family:courier new,courier,monospace;">fastcgi_path_info<span style="line-height: 22.3999996185303px;">$</span></span>، حتى هذه النقطة، في متغير يدعى <span style="font-family:courier new,courier,monospace;">orig_path<span style="line-height: 22.3999996185303px;">$</span></span>. وذلك لأن قيمة المتغير <span style="font-family:courier new,courier,monospace;">fastcgi_path_info<span style="line-height: 22.3999996185303px;">$</span></span> ستُمحى في لحظة عبر التعليمة try_files.</p><p dir="rtl">بإمكاننا التحقق من اسم السكربت الذي التقطناه سابقًا باستخدام التعليمة <span style="font-family:courier new,courier,monospace;">try_files</span>. وهي عبارة عن عملية تطبّق على ملف file operation تتأكد من أنّ السكربت الذي نحاول تشغيله مخزن على القرص. ولكن لذلك تأثيرًا جانبيًا يتمثل في مسح قيمة المتحول <span style="font-family:courier new,courier,monospace;">fastcgi_path_info<span style="line-height: 22.3999996185303px;">$</span></span>.</p><p dir="rtl">بعد القيام بالتمرير التقليدي عبر FastCGI فإننا نضبط <span style="font-family:courier new,courier,monospace;">SCRIPT_FILENAME</span> كما العادة. نضبط أيضًا الإعداد <span style="font-family:courier new,courier,monospace;">PATH_INFO</span> بالقيمة التي المخزّنة في المتغير <span style="font-family:courier new,courier,monospace;">orig_path<span style="line-height: 22.3999996185303px;">$</span></span>. فبالرغم من أن قيمة <span style="font-family:courier new,courier,monospace;">fastcgi_path_info<span style="line-height: 22.3999996185303px;">$</span></span> قد مُسحت، إلا أن قيمته الأصلية محفوظة في ذلك المتغير. كما أننا نضبط الوسيط <span style="font-family:courier new,courier,monospace;">PATH_TRANSLATED</span> ليربط map بين معلومات المسار الإضافية والموقع الذي تُحفظ فيه على القرص، نقوم بذلك عبر دمج قيمتي المتغيرين <span style="font-family:courier new,courier,monospace;">document_root<span style="line-height: 22.3999996185303px;">$</span></span> و <span style="font-family:courier new,courier,monospace;">orig_path<span style="line-height: 22.3999996185303px;">$</span></span>.</p><p dir="rtl">يسمح لنا ذلك ببناء طلباتٍ مثل:<span style="font-family:courier new,courier,monospace;"> index.php/users/view/ </span>بحيث يتمكن الملف: <span style="font-family:courier new,courier,monospace;">index.php/ </span>من معالجة المعلومات المتعلقة بالمجلد: <span style="font-family:courier new,courier,monospace;">users/view/ </span>وبنفس الوقت نتجنب المواقف التي سيُشغّل بها الطلب: <span style="font-family:courier new,courier,monospace;">test.jpg/index.php/ </span>سيُضبط البريمج دائمًا بأقصر مكوّن ينتهي بـ .<span style="font-family:courier new,courier,monospace;">php</span>، وبالتالي سنتجنب تلك المشكلة.</p><p dir="rtl">يمكننا أيضًا تحقيق ذلك باستخدام تعليمة alias إن احتجنا إلى تغيير موقع ملفات السكربتات. علينا فقط أن نأخذ ذلك بالحسبان في كل من ترويسة الموقع وتعريف <span style="font-family:courier new,courier,monospace;">fastcgi_split_path_info</span>.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">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;
}</pre><p dir="rtl">سوف يسمح لك ذلك لتشغيل تطبيقاتك التي تستخدم الإعداد <span style="font-family:courier new,courier,monospace;">PATH_INFO</span> بأمان. تذكّر أنه عليك تعديل الخيار <span style="font-family:courier new,courier,monospace;">cgi.fix_pathinfo</span> في ملف<span style="font-family:courier new,courier,monospace;"> php.ini </span>وضبطه بالقيمة "1" حتى يعمل بشكل صحيح. قد يترتب عليك أيضًا أن تعطّل <span style="font-family:courier new,courier,monospace;">security.limit_extensions</span> في الملف<span style="font-family:courier new,courier,monospace;"> php-fpm.conf</span>.</p><h2 dir="rtl">الخلاصة</h2><p dir="rtl">نأمل أنك تملك الآن فهمًا أفضل لإمكانية قيام FastCGI بالوساطة عنNginx. تسمح هذه الإمكانية لـ Nginx باستخدام قوته في معالجة الاتصالات بسرعة وتحضير المحتوى الثابت static content، بينما تُحمّل مسؤولية المحتوى الديناميكي dynamic content لبرمجيات مناسبة لذلك. يسمح FastCGI لـ Nginx بالعمل مع عدد كبير من التطبيقات، عبر إعدادات آمنة وذات أداء.</p><p dir="rtl">ترجمة – وبتصرّف– للمقال <a rel="external nofollow" href="https://www.digitalocean.com/community/tutorials/understanding-and-implementing-fastcgi-proxying-in-nginx">Understanding and Implementing FastCGI Proxying in Nginx</a> لمؤلفه Justin Ellingwood.</p>
]]></description><guid isPermaLink="false">73</guid><pubDate>Sun, 14 Jun 2015 14:58:31 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x625;&#x639;&#x62F;&#x627;&#x62F; &#x627;&#x633;&#x62A;&#x64A;&#x62B;&#x627;&#x642; HTTP &#x645;&#x639; Nginx &#x639;&#x644;&#x649; Ubuntu 14.04</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A7%D8%B3%D8%AA%D9%8A%D8%AB%D8%A7%D9%82-http-%D9%85%D8%B9-nginx-%D8%B9%D9%84%D9%89-ubuntu-1404-r95/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_08/nginx-http-auth.jpg.0ea1ffc31ee823b6d460fc1e574fb178.jpg" /></p>

<div id="wmd-preview-section-10"><p>Nginx (وتلفظ "engine x") هو خادوم ويب حرّ ومفتوح المصدر، يعمل كخادوم بروكسي معكوس reverse proxy للبروتوكولات HTTP ،POP3 ،SMPT ،IMAP، كتبه Igor Sysoe بهدف التركيز على المرونة، الخفة، وقلّة استهلاك الموارد وذلك بالمقارنة مع أباتشي Apache.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_08/nginx-http-auth.jpg.5c9a4d7c67f47bb852b3b551fdd41c52.jpg"><img data-fileid="3751" class="ipsImage ipsImage_thumbnailed" src="https://academy.hsoub.com/uploads/monthly_2015_08/nginx-http-auth.thumb.jpg.35f1c2ad6222f96cef6c1d3f656787e3.jpg" alt="nginx-http-auth.thumb.jpg.35f1c2ad6222f9"></a></p></div><div id="wmd-preview-section-12"><p><strong>المتطلبات</strong></p><p>كشرط مسبق لهذا الدرس سأفترض أنك انتهيت من <a href="https://academy.hsoub.com/devops/servers/%D8%A7%D9%84%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%A7%D9%84%D8%A7%D8%A8%D8%AA%D8%AF%D8%A7%D8%A6%D9%8A-%D9%84%D8%AE%D8%A7%D8%AF%D9%88%D9%85-%D8%A3%D9%88%D8%A8%D9%86%D8%AA%D9%88-1404-r4/">الإعدادات الأولية على الخادوم الافتراضي الخاص بك VPS</a> إضافةً إلى <a href="https://academy.hsoub.com/devops/web-servers/nginx/%D8%AA%D9%86%D8%B5%D9%8A%D8%A8%D8%8C-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D9%88%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-nginx-%D9%83%D8%AE%D8%A7%D8%AF%D9%88%D9%85-%D9%88%D9%8A%D8%A8-r1/">تثبيت Nginx بنجاح</a>. </p></div><div id="wmd-preview-section-13"><h2 id="الخطوة-الأولى-تثبيت-apache-utils">الخطوة الأولى: تثبيت Apache Utils</h2><p>نحتاج أولًا إلى الأداة <span style="font-family:courier new,courier,monospace;">htpasswd</span> بهدف إنشاء وتحديث ملف لتخزين معلومات التوثيق الأساسية للمستخدم (الاسم وكلمة المرور)، <span style="font-family:courier new,courier,monospace;">htpasswd</span> هي جزء من حزمة apache2-utils والتي يمكنك تركيبها بالأمر التالي: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo apt-get install apache2-utils
</pre></div><div id="wmd-preview-section-14"><h2 id="الخطوة-الثانية-إنشاء-مستخدم">الخطوة الثانية: إنشاء مستخدم</h2><p>إنشاء ملف <span style="font-family:courier new,courier,monospace;">htpasswd.</span> داخل دليل موقع الويب الخاص بك يؤمن بواسطة Nginx. يُنشئ الأمر التالي الملف اللازم ويضيف اسم مُستخدم مع كلمة مرور مُشفّرة له: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo htpasswd -c /etc/nginx/.htpasswd exampleuser </pre><p>هنا ستطلب منك الأداة اختيار كلمة المرور: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">New password: 
Re-type new password: 
Adding password for user exampleuser </pre><p>وهكذا تكون صيغة ملف<span style="font-family:courier new,courier,monospace;"> htpasswd. </span>مشابهة لهذا: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">login:password </pre><p>خُذ بعين الاعتبار أن <span style="font-family:courier new,courier,monospace;">htpasswd</span> يجب أن يكون قابلًا للوصول بواسطة حساب المستخدم الذي يُشغّل Nginx.</p></div><div id="wmd-preview-section-15"><h2 id="الخطوة-الثالثة-تحديث-إعدادات-nginx">الخطوة الثالثة: تحديث إعدادات Nginx</h2><p>يقع ملف ضبط Nginx ضمن الدليل <span style="font-family:courier new,courier,monospace;">/etc/nginx/sites-available/</span>. أضف السطرين التاليين إلى آخره لحماية مسار النطاق الذي ترغب به: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">auth_basic "Restricted"; 
auth_basic_user_file /etc/nginx/.htpasswd; </pre><p>يحمل السطر الثاني مكان ملف <span style="font-family:courier new,courier,monospace;">htpasswd.</span> الخاص بموقعك. <br>على سبيل المثال لنقل بأنّ ملف ضبط nginx لموقعنا هو <span style="font-family:courier new,courier,monospace;">/etc/nginx/sites-available/website_nginx.conf/</span>؛ افتح الملف بواسطة المحرّر النصيّ الذي تفضّله:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo vi /etc/nginx/sites-available/website_nginx.conf </pre><p>ثم أضف هذين السطرين إلى المسار التالي: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">server { 
    listen portnumber; 
    server_name ip_address; 
    location / { 
         root /var/www/mywebsite.com; 
         index index.html index.htm; 
         auth_basic "Restricted"; #For Basic Auth 
         auth_basic_user_file /etc/nginx/.htpasswd; #For Basic Auth 
    } 
} 
</pre></div><div id="wmd-preview-section-16"><h2 id="الخطوة-الرابعة-أعد-تحميل-nginx">الخطوة الرابعة: أعد تحميل Nginx</h2><p>يتوجب علينا أخيرًا إعادة تحميل إعدادات Nginx لتأخذ التغييرات الجديدة موضع التنفيذ على موقع الوِب الخاص بنا. بعد ذلك جرّب الدخول إلى النطاق الذي تمّت حمايته بواسطة معلومات التوثيق السابقة: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">$ sudo /etc/init.d/nginx reload 
* Reloading nginx configuration... </pre><p>حاول الآن الدخول إلى موقعك أو إلى مسار النطاق المحمي وسيطلب منك المتصفح إدخال اسم المستخدم وكلمة المرور للمتابعة، ولن يكون بإمكانك استعراض المحتوى دون معلومات الولوج الصحيحة.</p><p>رائع! أصبح لديك الآن نطاق ويب محمي باستخدام توثيق Nginx الأساسي.</p><p>ترجمة -وبتصرف- للمقال <a rel="external nofollow" href="https://www.digitalocean.com/community/tutorials/how-to-set-up-http-authentication-with-nginx-on-ubuntu-12-10">How To Set Up HTTP Authentication With Nginx On Ubuntu 12.10</a>.</p><p>حقوق الصورة البارزة: <a href="http://www.freepik.com/free-vector/fingerprint-line-design_737150.htm" rel="external nofollow">Designed by Freepik</a>.</p></div>
]]></description><guid isPermaLink="false">95</guid><pubDate>Wed, 12 Aug 2015 16:40:19 +0000</pubDate></item><item><title>&#x62A;&#x639;&#x644;&#x645; &#x643;&#x64A;&#x641; &#x62A;&#x646;&#x634;&#x626; &#x645;&#x62F;&#x648;&#x646;&#x629; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Ghost &#x648; Nginx &#x639;&#x644;&#x649; Ubuntu</title><link>https://academy.hsoub.com/devops/servers/web/nginx/%D8%AA%D8%B9%D9%84%D9%85-%D9%83%D9%8A%D9%81-%D8%AA%D9%86%D8%B4%D8%A6-%D9%85%D8%AF%D9%88%D9%86%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-ghost-%D9%88-nginx-%D8%B9%D9%84%D9%89-ubuntu-r86/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_08/ghost-nginx-ubuntu.png.0bd5ad7e602f0810beb8ef024afc636d.png" /></p>

<div id="wmd-preview-section-67"><p id="مقدمة">Ghost هي منصة تدوين حرّة ومفتوحة المصدر تتميّز بخفتها (~7.5MB)، سهولة استخدامها، قابليتها العاليّة للتخصيص، بالإضافة إلى توفّر العديد من السِمات themes لها عبر الإنترنت مجانًا أو بشكل مدفوع. </p><p style="text-align: center;"><a href="https://academy.hsoub.com/uploads/monthly_2015_08/ghost-nginx-ubuntu.png.432db7f60fcf5fa042c813a9026b3833.png" class="ipsAttachLink ipsAttachLink_image"><img data-fileid="3515" src="https://academy.hsoub.com/uploads/monthly_2015_08/ghost-nginx-ubuntu.thumb.png.fcb5c371cbf04d79aa80f04831c8b1dd.png" class="ipsImage ipsImage_thumbnailed" alt="ghost-nginx-ubuntu.thumb.png.fcb5c371cbf"></a><br>في هذا الدرس سوف نشرح خطوات تركيب وإعداد منصة Ghost على نظام Ubuntu 14.04، بالإضافة إلى إعداد خادوم Nginx لمنافذ البروكسي proxy ports، وكذلك تركيب حزمة forever للمحافظة على تشغيل Ghost في الخلفية.</p></div><div id="wmd-preview-section-68"><h2 id="المتطلبات">المتطلبات</h2><p>لا يشترط Ghost توفّر أي حد أدنى من المساحة على الخادوم، لكن خُذ بعين الاعتبار عدد الزوار المتوقعين لمدوّنتك وكمّ المحتوى الذي ترغب بمشاركته لتتمكّن من تقدير المساحة المناسبة عند الإنشاء. في هذا الدرس ولغرضٍ تعليمي فقط سوف نختار أقلّ مساحة ممكنة. <br>قبل البدء نحن نحتاج ما يلي: </p><ul><li>نظام Ubuntu 14.04 على خادومك. </li><li>عنوان نطاق مُسجّل ومربوط مع الـ IP الخاص بخادومك. </li><li>مستخدم عادي non-root مع صلاحيات الجذر، والذي سوف نستخدمه لتنفيذ جميع الأوامر المذكورة هنا، وفي حال كان الأمر يحتاج إلى صلاحيات الجذر فسنستخدم sudo.</li></ul></div><div id="wmd-preview-section-69"><h2 id="الخطوة-الأولى-تركيب-nodejs-و-npm">الخطوة الأولى: تركيب Node.js و Npm</h2><p>في البداية نحن بحاجة إلى تحديث فهارس مدير الحزم وتركيب كلًا من zip و wget حيث سنحتاجهما لاحقًا أثناء الدرس. </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo apt-get update 
sudo aptitude install zip wget </pre><p>يتطّلب Ghost تركيب Node.js v0.10.x (آخر إصدار مستقل)، فالإصدار غير المستقر (v0.12.x) ليس مدعومًا بعد. يوصي موقع Ghost.org تحديدًا بكلًا من Node.js v0.10.36 و npm v2.5.0. <br>يمكنك تركيب Node.js باستخدام PPA على Ubuntu [من هذا الدرس][1]. <br>عند الانتهاء من تثبيت Node.js، تحقّق من رقم الإصدار عبر تشغيل: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">node -v </pre><p>يُفترض أن يكون الخرج مشابهًا لهذا: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">v0.10.38 </pre><p>تحقّق أيضًا من وجود npm: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">npm -v </pre><p>إذا كانت مثبّتة فهذا سيُعيد لك رقم الإصدار: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">1.4.28 </pre><p>في غير ذلك ستظهر أمامك رسالة خطأ. عندها يمكنك تركيب npm بهذا الأمر: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo apt-get install npm </pre><p>ثم حدّث إصدار npm إلى الرقم 2.5.0 بتشغيل الأمر: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo npm install npm@2.5.0 -g </pre><p>تحقّق مجددًا من الإصدار المُثبّت: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">npm -v </pre><p>يُفترض أن يكون الخرج كهذا: <br> </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">2.5.0</pre><h2>الخطوة الثانية: تركيب Ghost</h2></div><div id="wmd-preview-section-70"><p>يتوجب علينا الآن تركيب Ghost، مُتبعين نصيحة موقع Ghost.org بتثبيت المنصّة على المسار<span style="font-family:courier new,courier,monospace;">var/www/ghost/</span>. <br>بدايةً سنُنشئ الدليل <span style="font-family:courier new,courier,monospace;">var/www/</span> ثم سنحصل على أحدث إصدار من Ghost من خلال مستودع GitHub الخاص بهم: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo mkdir -p /var/www 
cd /var/www/ 
sudo wget https://ghost.org/zip/ghost-latest.zip </pre><p>هكذا نكون قد حصلنا على الإصدار الأخير لـ Ghost، وعلينا الآن فكّ الضغط عن الحزمة والانتقال إلى الدليل<span style="font-family:courier new,courier,monospace;"> /var/www/ghost/:</span> </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo unzip -d ghost ghost-latest.zip 
cd ghost/ </pre><p>بقي علينا أخيرًا تركيب بعض الاعتماديات اللازمة للمنصّة: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo npm install --production </pre><p>هكذا نكون قد أنهينا عملية تركيب Ghost. لننتقل الآن إلى إعداد المنصّة قبل البدء بتشغيلها.</p></div><div id="wmd-preview-section-71"><h2 id="الخطوة-الثالثة-إعداد-ghost">الخطوة الثالثة: إعداد Ghost</h2><p>ملف الضبط الخاص بمنصة Ghost يجب أن يكون على المسار التالي <span style="font-family:courier new,courier,monospace;">var/www/ghost/config.js/</span> إلا أنّه وعند التركيب لن يكون هناك ملف بهذا الاسم، وعوضًا عن ذلك سنجد الملف <span style="font-family:courier new,courier,monospace;">config.example.js</span>. <br>أنشئ نسخة من الملف <span style="font-family:courier new,courier,monospace;">config.example.js</span> باسم <span style="font-family:courier new,courier,monospace;">config.js</span> ضمن نفس المجلد عبر الأمر <span style="font-family:courier new,courier,monospace;">cp </span>لاستخدامه في كتابة الإعدادات الخاصة بك. </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo cp config.example.js config.js </pre><p>من أهم المعلومات التي نحتاج إلى تعديلها في الملف السابق هو الرابط URL وإعدادات البريد أسفل القسم production. في غير ذلك سيأخذك الرابط إلى الصفحة الافتراضية للمدوّنة <a rel="external nofollow" href="http://my-ghost-blog.com">http://my-ghost-blog.com</a>. وعلى الرغم من أنه يمكن تشغيل Ghost بدون ضبط إعدادات البريد إلا أنه لا يُنصح بذلك، فعلى سبيل المثال يُرسل Ghost كلمة مرور مُستخدم المدوّنة إلى هذا البريد في حال نسيانها. <br>حرّر الملف بإحدى الأدوات التي تُفضّل: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo nano config.js </pre><p>عليك أولًا تغيير قيمة url إلى عنوان نطاقك (أو استخدم رقم IP الخاص بخادومك في حال لم ترغب باستعمال عنوان النطاق حاليًا). انتبه إلى الصياغة الصحيحة لعنوان الرابط بحيث تشبه <a rel="external nofollow" href="http://example.com/">http://example.com</a> أو <a rel="external nofollow" href="http://45.55.76.12">http://45.55.76.126</a> وإلا فإن Ghost لن يعمل. <br>قم أيضًا بتغيير قيمة host ضمن قسم server إلى 0.0.0.0. <br>يُظهر الملف التالي النموذج المُعدّل الخاص بالدرس:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"> var path = require(‘path’), config; config = { // ### Production // When running Ghost in the wild, use the production environment // Configure your URL and mail settings here production: { url: ‘http://my-ghost-blog.com’, mail: { // Your mail settings }, database: { client: ‘sqlite3’, connection: { filename: path.join(__dirname, ‘/content/data/ghost.db’) }, debug: false }, server: { // Host to be passed to node’s `net.Server#listen()` host: ‘127.0.0.1’, // Port to be passed to node’s `net.Server#listen()`, for iisnode s$ port: ‘2368’ } }, (…)</pre><p>احفظ الملف واخرج من المحرّر النصيّ nano عبر الضغط على <span style="font-family:courier new,courier,monospace;">CTRL+X</span> ثم <span style="font-family:courier new,courier,monospace;">Y</span> واضغط <span style="font-family:courier new,courier,monospace;">Enter</span>. <br>تأكّد أنك لا تزال ضمن الدليل <span style="font-family:courier new,courier,monospace;">/var/www/ghost/</span> ثم شغّل Ghost من خلال الأمر: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo npm start --production </pre><p>يُفترض أن يكون الخرج شيئًا مشابهًا لهذا:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"> &gt; ghost@0.6.4 start /var/www/ghost &gt; node index Migrations: Database initialisation required for version 003 Migrations: Creating tables… Migrations: Creating table: posts […]</pre><p>إذا كان كلّ شيء قد تمّ كما يجب؛ حينها يمكنك الوصول إلى مدونتك عبر المنفذ 2368: <br><a rel="external nofollow" href="http://your_domain._name:2368/">http://your_domain._name:2368</a> (أو <a rel="external nofollow" href="http://your_servers_ip:2368/">http://your_servers_ip:2368</a>). <br>اضغط الآن على<span style="font-family:courier new,courier,monospace;"> CTRL+C</span> لإيقاف عمل Ghost</p></div><div id="wmd-preview-section-72"><h2 id="الخطوة-الرابعة-تركيب-nginx">الخطوة الرابعة: تركيب Nginx</h2><p>الخطوة التالية هي تثبيت Nginx والذي يسمح للاتصالات على المنفذ 80 أن تتمّ عبر منفذ Ghost، بعبارة أبسط يسمح لنا Nginx الوصول للمدوّنة من دون الحاجة لإضافة المنفذ 2368: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo apt-get install nginx </pre><p>نحتاج الآن إلى ضبط Nginx، لننتقل أولًا إلى الدليل <span style="font-family:courier new,courier,monospace;">etc/nginx/</span> لحذف الملف الافتراضي <span style="font-family:courier new,courier,monospace;">etc/nginx/sites-enabled/</span>: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">cd /etc/nginx/ 
sudo rm sites-enabled/default </pre><p>سنُنشئ ملف جديد في المسار <span style="font-family:courier new,courier,monospace;">/etc/nginx/sites-available/</span> باسم ghost ثم نحرّره باستخدام nano: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo touch /etc/nginx/sites-available/ghost 
sudo nano /etc/nginx/sites-available/ghost </pre><p>الصق النصّ التالي في الملف السابق بعد تغيير المحتوى المُحدّد باللون الأحمر إلى عنوان نطاقك أو رقم الـ IP الخاص بخادومك:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"> server { listen 80; server_name your_domain.tld; location / { proxy_set_header X-Real-IP remoteaddr;proxysetheaderHosthttp_host; proxy_pass http://127.0.0.1:2368; } }</pre><p>سنُنشى اختصارًا لإعداداتنا في sites-enabled: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo ln -s /etc/nginx/sites-available/ghost /etc/nginx/sites-enabled/ghost </pre><p>ثم نُعيد تشغيل Nginx: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo service nginx restart </pre><p>الآن سنُنشئ مستخدمًا جديدًا لأغراض أمنيّة بحيث لا يمتلك أذوات سوى على الدليل <span style="font-family:courier new,courier,monospace;">var/www/ghost/</span>؛ ففي حال تعرّض Ghost لخطرٍ ما فإن نظامك سيظل في أمان: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo adduser --shell /bin/bash --gecos 'Ghost application' ghost </pre><p>إسناد الصلاحيات المُناسبة: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo chown -R ghost:ghost /var/www/ghost/ </pre><p>يمكنك الآن الولوج مستعملا المستخدم الجديد: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">su - ghost </pre><p>أخيرًا نحن بحاجة إلى إعادة تشغيل Ghost: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">cd /var/www/ghost 
npm start –production</pre><p>يمكنك الآن الوصول إلى مدونتك عبر المنفذ 80 من خلال ///:http.</p></div><div id="wmd-preview-section-73"><h2 id="الخطوة-الخامسة-الإبقاء-على-تشغيل-ghost-في-الخلفية">الخطوة الخامسة: الإبقاء على تشغيل Ghost في الخلفية</h2><p>الخطوة الأخيرة هي المحافظة على تشغيل Ghost في الخلفية طوال الوقت، وسوف نستخدم لذلك الأداة forever التي تُبقي Ghost يعمل في الخلفية وتراقبه في حال انهياره بحيث تُشغّل نسخة أخرى منه من جديد. <br>قم بتركيب الأداة forever بالأمر التالي ضمن مجلّد ghost <span style="font-family:courier new,courier,monospace;">/var/www/ghost</span>، لكن أولًا عليك الخروج من المستخدم Ghost ثم الدخول بالمستخدم العادي: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">exit 
sudo npm install -g forever </pre><p>شغّل Ghost مع المستخدم ghost على أن تكون ضمن الدليل الصحيح: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">su - ghost 
cd /var/www/ghost 
forever start index.js </pre><p>يفترض أن يكون الخرج مشابهًا لهذا:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint"> warn: –minUptime not set. Defaulting to: 1000ms warn: –spinSleepTime not set. Your script will exit if it does not stay up for at least 1000ms info: Forever processing file: index.js</pre><p>بشكل افتراضي يعمل forever ضمن وضع المطوّرين، يمكنك تعديل هذا من خلال الأمر: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">NODE_ENV=production forever start index.js </pre><p>أما إذا رغبت بإيقاف عمل forever فنفّذ الأمر الآتي ضمن دليل Ghost: <br> </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">forever stop index.js</pre><h2>أخطاء مُحتملة</h2></div><div id="wmd-preview-section-74"><p>إذا واجهت رسالة الخطأ التالية: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">Error: SQLITE_READONLY: attempt to write a readonly database </pre><p>شغّل forever كجذر root (اكتب exit للخروج من المستخدم الحالي أولًا): </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo forever start index.js </pre><p>إذا أعاد لك الأمر الأخير رسالة تفيد بعدم وجود forever استخدم الأمر مع المسار الكامل: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">sudo /usr/local/bin/forever start index.js </pre><p>إذا واجهت رسالة الخطأ التالية: </p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">error: Cannot start forever 
error: script /home/ghost/index.js does not exist. </pre><p>فهذا يعني أنك لست ضمن الدليل الصحيح <span style="font-family:courier new,courier,monospace;">var/www/ghost/</span>. انتقل إليه أولًا ثم نفّذ الأمر من جديد.</p></div><div id="wmd-preview-section-75"><h2 id="الخلاصة">الخلاصة</h2><p>تهانينا. لقد تمكّنت من تثبيت Ghost وتعلّمت كيفيّة استخدام Nginx لضبط بروكسي المنافذ. كما تعلّمت كيفيّة الإبقاء على المهام تعمل ضمن الخلفية باستخدام العقدة forever.</p><p>ترجمة -وبتصرف- للمقال <a rel="external nofollow" href="https://www.digitalocean.com/community/tutorials/how-to-create-a-blog-with-ghost-and-nginx-on-ubuntu-14-04">How To Create a Blog with Ghost and Nginx on Ubuntu 14.04</a> لصاحبه Hamza Shezad.</p></div>
]]></description><guid isPermaLink="false">86</guid><pubDate>Sat, 25 Jul 2015 10:32:49 +0000</pubDate></item></channel></rss>
