عند نشر أي تطبيق ويب على خادم حقيقي، نادرًا ما تعرّض التطبيق مباشرة للإنترنت. بدلًا من ذلك نضع أمامه بوّابة ذكية اسمها reverse proxy، وNginx هو الخيار الأكثر شيوعًا لهذه المهمّة. في هذا المقال سنُعدّ Nginx كبروكسي عكسي يمرّر الطلبات لتطبيق خلفي يعمل على المنفذ 3000، ثم نُفعّل HTTPS مجانًا عبر Let’s Encrypt، ونختم بأهمّ ممارسات الأمان. كل ملفات الإعداد هنا حقيقية وقابلة للتطبيق مباشرة.
ما هو الـ reverse proxy ولماذا نحتاجه
الـ reverse proxy هو خادم يقف بين المستخدمين وتطبيقك الخلفي. عندما يطلب المستخدم موقعك، يصل الطلب أولًا إلى Nginx، ثم يقوم Nginx بتمريره داخليًا إلى تطبيقك (مثلًا تطبيق Node.js يعمل على المنفذ 3000)، ويعيد الرد للمستخدم. لماذا نفعل ذلك؟ لأنه يتيح لنا إنهاء TLS في مكان واحد، وتقديم عدّة مواقع من خادم واحد، وإخفاء تفاصيل التطبيق الخلفي، وإضافة طبقات أمان وضغط وتخزين مؤقّت دون تعديل التطبيق نفسه.
تثبيت Nginx
على توزيعات Debian وUbuntu، التثبيت مباشر:
sudo apt-get update
sudo apt-get install nginx
sudo systemctl enable --now nginx
تأكّد أنه يعمل بفتح عنوان IP الخادم في المتصفّح، يجب أن ترى صفحة Nginx الافتراضية. على توزيعات RHEL/CentOS استخدم sudo dnf install nginx بدلًا من apt.
كتابة كتلة server للبروكسي العكسي
أنشئ ملف إعداد جديدًا لموقعك داخل /etc/nginx/sites-available/. لنفترض أن نطاقك هو example.com وتطبيقك يعمل على 127.0.0.1:3000. أنشئ الملف /etc/nginx/sites-available/example.com:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
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;
# دعم WebSocket إن احتاجه التطبيق
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
كل سطر هنا مقصود. المفتاح proxy_pass يحدّد وجهة الطلبات الداخلية. أمّا ترويسات proxy_set_header فهي حيوية: Host يمرّر اسم النطاق الأصلي للتطبيق (بدونه قد يكسر التطبيق التوجيه أو إنشاء الروابط)، وX-Real-IP وX-Forwarded-For ينقلان عنوان IP الحقيقي للزائر بدل عنوان الخادم، وX-Forwarded-Proto يخبر التطبيق هل جاء الطلب عبر HTTP أم HTTPS وهو ضروري لكي يولّد التطبيق روابط صحيحة.
الآن فعّل الموقع بإنشاء رابط رمزي إلى sites-enabled، ثم اختبر الإعداد وأعد التحميل:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
الأمر nginx -t يفحص صحّة الإعداد قبل تطبيقه، وهذه عادة يجب أن تلتزم بها دائمًا قبل أي reload حتى لا تُسقط الخادم بخطأ إملائي.
تفعيل TLS عبر Let’s Encrypt وCertbot
الآن لنجعل الموقع يعمل على HTTPS مجانًا. أداة Certbot من Let’s Encrypt تقوم بكل العمل: تطلب الشهادة، وتعدّل إعداد Nginx، وتضيف إعادة التوجيه تلقائيًا. ثبّتها عبر:
sudo apt-get install certbot python3-certbot-nginx
ثم اطلب الشهادة لنطاقك. سيقرأ Certbot كتلة server التي كتبتها ويحقنها بإعدادات TLS:
sudo certbot --nginx -d example.com -d www.example.com
سيسألك Certbot عن بريدك الإلكتروني والموافقة على الشروط، ثم يسألك إن كنت تريد إعادة توجيه HTTP إلى HTTPS تلقائيًا، اختر نعم. بعد نجاح العملية، سيُعدّل ملفك ليستمع على المنفذ 443 مع الشهادة، ويضيف كتلة إعادة توجيه من المنفذ 80. النتيجة النهائية ستشبه:
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
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 example.com www.example.com;
return 301 https://$host$request_uri;
}
كتلة المنفذ 80 الأخيرة مهمّتها الوحيدة هي إعادة توجيه أي زائر يصل عبر HTTP إلى نسخة HTTPS بشكل دائم (301). شهادات Let’s Encrypt صالحة 90 يومًا، لكن Certbot يثبّت مؤقّتًا (timer) للتجديد التلقائي. تأكّد منه عبر:
sudo certbot renew --dry-run
أفضل ممارسات أمان مختصرة
بعد أن يعمل الموقع، أضف هذه التحسينات داخل كتلة server أو في ملف /etc/nginx/nginx.conf:
# إخفاء رقم إصدار Nginx من الترويسات وصفحات الأخطاء
server_tokens off;
# تفعيل الضغط لتقليل حجم الردود
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
# تحديد أقصى حجم لجسم الطلب لمنع الرفع الضخم
client_max_body_size 10M;
السطر server_tokens off يخفي إصدار Nginx الذي قد يساعد المهاجمين، وgzip on يضغط الردود النصّية فيقلّل استهلاك الباندويدث ويسرّع التحميل، وclient_max_body_size يحمي خادمك من طلبات رفع ملفات ضخمة قد تستنزف موارده. بعد أي تعديل، لا تنسَ nginx -t ثم systemctl reload nginx.
أخطاء شائعة
- نسيان
proxy_set_header Host: يصل التطبيق الخلفي بترويسة Host خاطئة فينكسر إنشاء الروابط أو التوجيه الداخلي. هذه الترويسة شبه إلزامية لأي بروكسي عكسي. - خطأ 502 Bad Gateway: يعني أن Nginx لم يستطع الوصول إلى التطبيق الخلفي. تحقّق أن التطبيق يعمل فعلًا على المنفذ الصحيح عبر
curl http://127.0.0.1:3000، وأنproxy_passيشير للعنوان والمنفذ الصحيحين. - عدم إعادة تحميل Nginx بعد التعديل: تعدّل الملف ثم تتفاجأ بأن شيئًا لم يتغيّر. أي تغيير لا يُطبّق إلا بعد
sudo nginx -t && sudo systemctl reload nginx. - تعارض كتل server: وجود أكثر من كتلة بنفس
server_nameوالمنفذ يسبّب سلوكًا غير متوقّع. تأكّد من حذف الإعداد الافتراضي إن لم تحتجه.
الخطوة التالية
الآن لديك بروكسي عكسي آمن يعمل بـ HTTPS. الخطوة التالية المقترحة: إضافة ترويسات أمان حديثة مثل Strict-Transport-Security وX-Content-Type-Options، وضبط limit_req للحدّ من معدّل الطلبات (rate limiting) لحماية تطبيقك من هجمات القوّة الغاشمة على نقاط تسجيل الدخول.

اترك تعليقاً
يجب أنت تكون مسجل الدخول لتضيف تعليقاً.