هناك دائمًا طرق متعددة لتعزيز مرونة وأمان تطبيقك Node.js. ويتيح لك استخدام وكيل عكسي مثل Nginx إمكانية تحميل طلبات الرصيد وتخزين محتوى ثابت في ذاكرة التخزين المؤقت وتنفيذ بروتوكول أمان طبقة النقل (TLS) وهي اختصار لـTransport Layer Security. ويضمن تفعيل HTTPS المشفر على خادمك أن الاتصالات من وإلى تطبيقك تبقى آمنة.
يتضمن تطبيق وكيل عكسي باستخدام TLS/SSLعلى الحاويات مجموعة من الإجراءات مختلفة عن العمل مباشرة على نظام تشغيل مضيف. على سبيل المثال، إذا كنت تحصل على شهادات من Let’s Encrypt لتطبيق يعمل على الخادم، فستثبّت البرنامج المطلوب مباشرة على مضيفك. أما الحاويات فتسمح لك أن تسلك نهجا مختلفا. باستخدام Docker Compose، يمكنك إنشاء حاويات لتطبيقك، وخادم الويب الخاص بك، وعميل Certbot الذي سيتيح لك الحصول على شهاداتك. ويمكّنك اتباع هذه الخطوات من الاستفادة من مزايا النمطية وقابلية التنقل في سير عملٍ يعتمد على الحاويات.
في هذا الدرس، سوف تنشر تطبيق Node.js بوكيل عكسي Nginx باستخدام Docker Compose. وستحصل على شهادات TLS/SSL للمجال المرتبط بتطبيقك كما ستتأكد من حصوله على تصنيف أمان عالي من SSL Labs. وفي الأخير، سوف تنشئ وظيفة cron لتجديد شهاداتك بحيث يظل نطاقك آمنًا.
المتطلبات الأساسية
لمتابعة هذا البرنامج التعليمي، ستحتاج إلى ما يلي:
- خادم أوبونتو 18.04 ومستخدم غير جذري ذي صلاحيات sudo وجدار حماية نشط. للحصول على إرشادات حول كيفية إعدادها، يرجى الاطلاع على دليل إعداد الخادم الأولي.
- Docker مثبت على خادمك. للحصول على إرشادات حول تثبيت Docker، اتبع الخطوتين 1 و 2 للدليل كيفية تثبيت واستخدام Docker على Ubuntu 18.04. للحصول على إرشادات حول تثبيت Compose، اتبع الخطوة الأولى من كيفية تثبيت Docker Compose على أوبونتو 18.04.
- اسم نطاق مسجل. سيستخدم هذا البرنامج التعليمي example.com طوال الوقت. يمكنك الحصول على نطاق مجاني من Freenom ، أو استخدام مسجل النطاقات الذي تختاره. سجلّا DNS التاليين المعدّين لخادمك. يمكنك متابعة هذه المقدمة إلى DNS في DigitalOcean للحصول على تفاصيل حول كيفية إضافتها إلى حساب DigitalOcean، إذا كنت تستخدمه:
- سجل A يتضمن example.com يشير إلى عنوان IP العام لخادمك.
- سجل A يتضمن www.example.com يشير إلى عنوان IP العام لخادمك.
الخطوة الأولى: استنساخ واختبار تطبيق Node
سوف نبدأ أولًا باستنساخ المستودع الذي يحتوي على شيفرة التطبيق Node، والذي يتضمن الملف Dockerfile
الذي سنستخدمه لإنشاء صورة تطبيقنا اعتمادًا على Compose. ويمكننا البدء باختبار التطبيق عبر بنائه وتنفيذه باستخدام الأمر docker run
دون وكيل عكسي أو شهادة SSL.
في المجلّد الرئيسي للمستخدم غير الجذري، استنسخ مستودع nodejs-image-demo
من حساب DigitalOcean Community GitHub. يتضمن
مستودع التخزين هذا شيفرة الإعداد الموضح في كيفية إنشاء تطبيق Node.js باستخدام Docker.
انسخ المستودع في مجلّد يسمى node_project:
git clone https://github.com/do-community/nodejs-image-demo.git node_project
انتقل إلى المجلّد node_project
:
cd node_project
يوجد في هذا المجلّد ملفّ Dockerfile يحتوي على إرشادات حول بناء تطبيق Node باستخدام صورة Docker node:10 أضافة إلى محتويات مجلّد مشروعك الحالي. يمكنك إلقاء نظرة على محتويات Dockerfile بكتابة مايلي:
cat Dockerfile
المخرجات:
FROM node:10-alpine RUN mkdir -p /home/node/app/node_modules && chown -R node:node /home/node/app WORKDIR /home/node/app COPY package*.json ./ USER node RUN npm install COPY --chown=node:node . . EXPOSE 8080 CMD [ "node", "app.js" ]
تبني هذه التعليمات صورة Node عبر نسخ شيفرة المشروع من المجلّد الحالي إلى الحاوية وتثبيت الاعتماديات باستخدام npm install
. كما أنها تستخدم أيضًا التخزين المؤقت وطبقات الصور في Docker عبر فصل نسخة من package.json
و package-lock.json
، التي تحتوي على اعتماديات المشروع المدرجة، عن نسخة باقي شيفرة التطبيق. وتحدد هذه التعليمات كذلك أن تشغيل الحاوية سيكون عبر مستخدم Node غير الجذري بالأذونات المناسبة المعينة على شيفرة التطبيق والمجلّدات node_modules
.
لمزيد من المعلومات حول أفضل ممارسات Dockerfile و Node image ، يرجى الاطلاع على التوضيحات في الخطوة 3 حول كيفية بناء تطبيق Node.js باستخدام Docker.
لاختبار التطبيق بدون SSL، يمكنك بناء الصورة وتعليمها باستخدام Docker والراية t-
. سوف نسمّي الصورة node-demo
، ولكن تبقى لك الحرية في إعطائها اسمًا آخر:
docker build -t node-demo .
بمجرد اكتمال عملية البناء، يمكنك عرض قائمة صورك باستخدام docker images
:
docker images
سيظهر لك الإخراج التالي مؤكّدًا بناء صورة التطبيق:
REPOSITORY TAG IMAGE ID CREATED SIZE node-demo latest 23961524051d 7 seconds ago 73MB node 10-alpine 8a752d5af4ce 3 weeks ago 70.7MB
بعد ذلك، أنشئ الحاوية باستخدام docker run
. سوف نستخدم ثلاث رايات مع هذا الأمر:
-
p-
: ينشر هذا المنفذ على الحاوية ويوجّهه إلى منفذٍ على مضيفنا. سنستخدم المنفذ 80 على المضيف، ولكن يمكنك تعديل هذا عند الضرورة إذا كان لديك عملية أخرى تشغَل هذا المنفذ. لمزيد من المعلومات، راجع هذه التوضيحات في توثيق Docker حول ربط المنافذ. -
d-
: يشغّل هذا الحاوية في الخلفية. -
name-
: يتيح لنا هذا إعطاء الحاوية اسمًا سهل التذكّر.
نفّذ الأمر التالي لإنشاء الحاوية:
docker run --name node-demo -p 80:8080 -d node-demo
تفقّد الحاويات قيد التشغيل باستخدام docker ps
:
docker ps
سترى الإخراج التالي الذي يؤكد أن حاوية تطبيقك قيد التشغيل:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4133b72391da node-demo "node app.js" 17 seconds ago Up 16 seconds
يمكنك الآن زيارة عنوان نطاقك لاختبار إعداداتك: http://example.com. لا تنس تعويض example.com باسم نطاقك الخاص. سيعرض تطبيقك صفحة الهبوط التالية:
الآن وبعد اختبار التطبيق، يمكنك إيقاف الحاوية وحذف الصور. استخدم docker ps
مرة أخرى للحصول على معرّف الحاويات CONTAINER ID:
docker ps
المخرجات:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4133b72391da node-demo "node app.js" 17 seconds ago Up 16 seconds
أوقف الحاوية باستخدام docker stop
. تأكد من تعويض المعرِّف CONTAINER ID المدرج هنا بمعرّف تطبيقك CONTAINER ID:
docker stop 4133b72391da
يمكنك الآن حذف الحاوية المتوقفة وجميع الصور، بما في ذلك الصور غير المستخدمة والمعلّقة، باستخدام docker system prune
والراية a-
:
docker system prune -a
اكتب y في الإخراج عند ما تطلب منك الكتابة لتأكيد رغبتك في حذف الحاوية والصور المتوقّفة. يرجى العلم أن هذا سيؤدي أيضًا إلى حذف ذاكرة التخزين المؤقت للبناء.
بعد اختبار صورة تطبيقك، يمكنك الانتقال إلى بناء بقية الإعداد باستخدام Docker Compose
.
الخطوة الثانية: تحديد تكوين خادم الويب
يمكننا بعد إنشاء Dockerfile لتطبيقنا، إنشاء ملف تكوين لتشغيل حاوية Nginx الخاصة بنا. سنبدأ بالتكوين ذي الحد الأدنى الذي سيتضمن اسم نطاقنا، و الملف الجذري، ومعلومات الوكيل، وكتلة الموقع (Location block) لتوجيه طلبات Certbot إلى المجلّد well-known
. إذ سيضع ملفًا مؤقتًا للتحقق من أن معلومات DNS لنطاقنا توجّه نحو خادمنا.
أنشئ أولاً مجلّدًا في مجلّد المشروع الحالي لملف التكوين:
mkdir nginx-conf
افتح الملف باستخدام nano أو المحرر المفضل لديك:
nano nginx-conf/nginx.conf
أضف كتلة الخادم التالية لطلبات المستخدم الوكيل إلى حاوية تطبيقك Node ولتوجيه طلبات Certbot إلى المجلّد well-known
. لا تنس تعويض example.com باسم نطاقك الخاص:
server { listen 80; listen [::]:80; root /var/www/html; index index.html index.htm index.nginx-debian.html; server_name example.com www.example.com; location / { proxy_pass http://nodejs:8080; } location ~ /.well-known/acme-challenge { allow all; root /var/www/html; } }
تسمح لنا كتلة الخادم هذه بتشغيل حاوية Nginx كبديل عكسي، والذي سيمرر الطلبات إلى حاوية تطبيقنا Node. سيسمح لنا أيضًا باستخدام المكوّن الإضافي webroot الخاص بـ Certbot للحصول على شهادات لنطاقنا. يعتمد هذا المكوّن الإضافي على طريقة التحقق من HTTP-01، والتي تستخدم طلب HTTP لإثبات أن Certbot يمكنه الوصول إلى الموارد من خادمٍ يوافق اسمَ نطاق معين.
احفظ الملف وأغلقه بمجرد الانتهاء من التحرير.
لمعرفة المزيد حول خوارزميات Nginx لخادم المواقع وكتلها، يرجى الرجوع إلى هذه المقالة حول فهم خوارزميات Nginx للخادم وحظر المواقع.
بعد تحديد تفاصيل تكوين خادم الويب، يمكننا الانتقال إلى إنشاء ملف docker-compose.yml، والذي سيتيح لنا إنشاء خدمات التطبيقات الخاصة بنا وحاوية Certbot التي سنستخدمها للحصول على شهاداتنا.
الخطوة الثالثة: إنشاء ملف Docker Compose
سيحدد ملف docker-compose.yml
خدماتنا، بما في ذلك تطبيق Node وخادم الويب. سوف يحدد تفاصيل مثل وحدات التخزين المسماة، والتي ستكون ضرورية لمشاركة بيانات اعتماد SSL بين الحاويات، وكذلك معلومات الشبكة والمنفذ. سوف يسمح لنا أيضًا بتحديد أوامر محددة لتنفيذها عند إنشاء حاوياتنا. هذا الملف هو المورد المركزي الذي سيحدّد كيف ستعمل خدماتنا معًا.
افتح الملف في مجلّدك الحالي:
nano docker-compose.yml
حدد خدمة التطبيق أولًا:
version: '3' services: nodejs: build: context: . dockerfile: Dockerfile image: nodejs container_name: nodejs restart: unless-stopped
يتضمن تعريف خدمة nodejs ما يلي:
- Build: يحدّد هذا خيارات التكوين، بما في ذلك context وdockerfile، والتي ستطبّق عندما ينشئ Docker صورة التطبيق. إذا كنت ترغب في استخدام صورة موجودة من سجلٍّ مثل Docker Hub، فيمكنك استخدام التعليمة image عوض ذلك، مع معلومات حول اسم المستخدم والمستودع وعلامة الصورة.
- Context: يعرّف هذا سياق البناء لصورة التطبيق. وهو في هذه الحالة مجلّد المشروع الحالي.
- Dockerfile: يحدّد هذا ملف Dockerfile الذي سيستخدمه Compose للبناء وهو الملف Dockerfile الذي رأيناه في الخطوة الأولى.
- Image و container_name: تعطي هذه أسماء للصورة والحاوية.
- restart : هذا يحدّد سياسة إعادة التشغيل. تكون قيمته الافتراضية هي "لا"، لكننا عيّننا الحاوية لإعادة تشغيل ما لم يتم إيقافها.
لاحظ أننا لا نُضمّن وصلات الربط (bind mounts) مع هذه الخدمة، وذلك لأن إعدادنا يركز على النشر بدلاً من التطوير. لمزيد من المعلومات، يرجى الاطلاع على توثيق Docker على وصلات الربط والحجوم.
لتمكين الاتصال بين التطبيق وحاويات خادم الويب، سنضيف أيضًا شبكة جسرية (bridge network) تسمى app-network
أسفل تعريف إعادة التشغيل:
services: nodejs: ... networks: - app-network
تتيح الشبكة الجسرية التي يعرّفها المستخدم الاتصالَ بين الحاويات على مضيف Docker نفسه. ويعمل ذلك على تبسيط حركة المرور والاتصالات داخل التطبيق، لأنه يفتح جميع المنافذ بين الحاويات على نفس الشبكة الجسرية، مع عدم تعريض أي منافذ للعالم الخارجي. وبالتالي، يمكنك الاختيار في فتح المنافذ التي تحتاجها فقط لعرض خدمات واجهتك الأمامية.
بعد ذلك، حدّد خدمة خادم الويب:
... webserver: image: nginx:mainline-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - web-root:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt - certbot-var:/var/lib/letsencrypt depends_on: - nodejs networks: - app-network
تظل بعض الإعدادات التي حددناها لخدمة nodejs كما هي، لكننا أجرينا أيضًا التغييرات التالية:
- image: يطلب هذا من Compose سحب أحدث صورة ألبية Nginx (Alpine-based Nginx image) من Docker Hub. لمزيد من المعلومات حول الصور الألبية، يرجى الاطلاع على الخطوة الثالثة من كيفية إنشاء تطبيق Node.js باستخدام Docker.
- ports: هذا يعرض المنفذ 80 لتفعيل خيارات التكوين التي حددناها في تكوين Nginx.
لقد حددنا أيضًا وحدات التخزين المسماة ووصلات الربط التالية:
- web-root:/var/www/html: سيؤدي ذلك إلى إضافة الأصول الثابتة لموقعنا ، المنسوخة إلى وحدة تخزين تسمى web-root ، إلى مجلّد /var/www/html على الحاوية.
- ./nginx-conf:/etc/nginx/conf.d: سيؤدي هذا إلى ربط دليل تكوين Nginx على المضيف بالمجلّد ذي الصلة على الحاوية، مع التأكد من أن أي تغييرات نجريها على الملفات الموجودة على المضيف ستنعكس في الحاوية.
- certbot-etc:/etc/letsencrypt : سيؤدي ذلك إلى ربط شهادات ومفاتيح Let’s Encrypt لنطاقنا على المجلّد المناسب على الحاوية.
- certbot-var:/var/lib/letsencrypt: يؤدي هذا إلى تحديث مجلّد العمل الافتراضي الخاص بـ Let's Encrypt إلى المجلّد المناسب على الحاوية.
بعد ذلك، أضف خيارات التكوين لحاوية certbot. تأكد من تعويض النطاق ومعلومات البريد الإلكتروني باسم نطاقك وبريدك الإلكتروني للاتصال:
... certbot: image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - certbot-var:/var/lib/letsencrypt - web-root:/var/www/html depends_on: - webserver command: certonly --webroot --webroot-path=/var/www/html --email sammy@example.com --agree-tos
يطلب هذا التعريف من Compose سحب صورة certbot/certbot
من Docker Hub. كما أنّه يستخدم وحدات التخزين المسمّاة لمشاركة الموارد مع حاوية Nginx، بما في ذلك شهادات النّطاق والمفتاح في certbot-etc، ومجلّد عمل Let's Encrypt في certbot-var
، وشيفرة التطبيق في web-root.
مرة أخرى، لقد استخدمنا depends_on
لتحديد أن حاوية certbot يجب أن تشتغل بمجرد تشغيل الخدمة webserver.
لقد أضفنا أيضًا خيار command
يحدد الأمر الذي سيتم تنفيذه عند بدء تشغيل الحاوية. وهو يتضمن الأمر الفرعي certonly مع الخيارات التالية:
- webroot--: هذا يطلب من Certbot استخدام البرنامج المساعد webroot لوضع الملفات في مجلد webroot للتصديق.
- webroot-path--: يحدد مسار المجلّد webroot.
- email--: بريدك الإلكتروني المفضل للتسجيل والاسترداد.
- agree-tos--: هذا يحدد أنك توافق على اتفاقية المشتركين في ACME.
- no-eff-email--: هذا يخبر Certbot أنك لا ترغب في مشاركة بريدك الإلكتروني مع مؤسسة الحدود الإلكترونية Electronic Frontier Foundation (EFF). لا تتردد في حذف هذا إذا كنت تفضل ذلك.
- staging--: هذا يخبر Certbot أنك ترغب في استخدام بيئة تشغيل Let's Encrypt للحصول على شهادات الاختبار. يتيح لك استخدام هذا الخيار اختبار خيارات التكوين وتفادي حدود طلبات النطاق المحتملة. لمزيد من المعلومات حول هذه الحدود، يرجى الاطلاع على التوثيق الخاص بمعدّل الحدود في Let's Encrypt.
- d-: يتيح لك ذلك تحديد أسماء النطاق التي ترغب في تطبيقها على طلبك. في هذه الحالة، ضمّننا example.com و www.example.com. لا تنس تعويضها بتفضيلات النطاق الخاصة بك.
كخطوة أخيرة، أضف تعريفات وحدة التخزين والشبكة. وتأكد من تعويض اسم المستخدم هنا بمستخدمك غير الجذري:
... volumes: certbot-etc: certbot-var: web-root: driver: local driver_opts: type: none device: /home/sammy/node_project/views/ o: bind networks: app-network: driver: bridge
تتضمن وحدات التخزين المسماة لدينا شهادات Certbot ووحدات تخزين مجلّد العمل، ووحدة تخزين الأصول الثابتة لموقعنا، web-root. في معظم الحالات، يكون برنامج التشغيل الافتراضي لوحدات تخزين Docker هو برنامج التشغيل المحلي، والذي يقبل على Linux خيارات مماثلة للأمر mount. ونستطيع بفضل هذا تحديد قائمة خيارات برنامج التشغيل باستخدام driver_opts الذي يربط مجلّد views على المضيف، والذي يحتوي على أصول ثابتة للتطبيق، مع وحدة التخزين في وقت التشغيل. يمكن بعد ذلك مشاركة محتويات المجلّد بين الحاويات. لمزيد من المعلومات حول محتويات المجلّد views، يرجى الاطلاع على الخطوة الثانية من كيفية إنشاء تطبيق Node.js باستخدام Docker.
سيبدو ملف docker-compose.yml بهذا الشكل عند الانتهاء:
version: '3' services: nodejs: build: context: . dockerfile: Dockerfile image: nodejs container_name: nodejs restart: unless-stopped networks: - app-network webserver: image: nginx:mainline-alpine container_name: webserver restart: unless-stopped ports: - "80:80" volumes: - web-root:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt - certbot-var:/var/lib/letsencrypt depends_on: - nodejs networks: - app-network certbot: image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - certbot-var:/var/lib/letsencrypt - web-root:/var/www/html depends_on: - webserver command: certonly --webroot --webroot-path=/var/www/html --email sammy@example.com --agree-tos --no-eff-email --staging -d example.com -d www.example.com volumes: certbot-etc: certbot-var: web-root: driver: local driver_opts: type: none device: /home/sammy/node_project/views/ o: bind networks: app-network: driver: bridge
بوضعك لتعريفات الخدمة في مكانها الصحيح، ستكون مستعدًّا لبدء تشغيل الحاويات واختبار طلبات الشهادة الخاصة بك.
الخطوة الرابعة: الحصول على شهادات SSL وبيانات الاعتماد
يمكننا أن نبدأ تشغيل حاوياتنا باستخدام docker-compose up
، وهو الأمر الذي سيؤدي إلى إنشاء وتشغيل حاوياتنا وخدماتنا بالترتيب الذي حددناه. إذا كانت طلبات النطاق ناجحة، فستظهر حالة الخروج الصحيحة في الإخراج والشهادات الملائمة موصولة بالمجلد etc/letsencrypt/live/
على حاوية webserver.
أنشئ الخدمات باستخدام docker-compose up
والراية d-
التي ستشغّل حاويات nodejs و webserver في الخلفية:
docker-compose up -d
سيظهر لك الإخراج التالي الذي يؤكد أن خدماتك أُنشِئت:
Creating nodejs ... done Creating webserver ... done Creating certbot ... done
تحقق من حالة خدماتك باستخدام docker-compose ps:
docker-compose ps
إذا كان كل شيء على ما يرام، فيجب أن تكون خدماتك nodejs و webserver في الحالة "Up" وستكون حاوية certbot في الحالة "0":
Name Command State Ports ------------------------------------------------------------------------ certbot certbot certonly --webroot ... Exit 0 nodejs node app.js Up 8080/tcp webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp
إذا رأيت شيءًا آخر غير Up في عمود الحالة لخدمات node وwebserver، أو قيمة أخرى غير الصفر 0 في حالة الخروج للحاوية certbot، فاحرص على التحقق من سجلات الخدمة باستخدام الأمر docker-compose logs:
docker-compose logs service_name
يمكنك الآن التحقق من تركيب بيانات الاعتماد على حاوية webserver باستخدام docker-compose exec:
docker-compose exec webserver ls -la /etc/letsencrypt/live
إذا كان الطلب ناجحًا، فسترى في الإخراج ما يلي:
total 16 drwx------ 3 root root 4096 Dec 23 16:48 . drwxr-xr-x 9 root root 4096 Dec 23 16:48 .. -rw-r--r-- 1 root root 740 Dec 23 16:48 README drwxr-xr-x 2 root root 4096 Dec 23 16:48 example.com
الآن بعد تأكّدك من نجاح طلبك، يمكنك تحرير تعريف خدمة certbot من أجل حذف الراية staging--
.
افتح docker-compose.yml
:
nano docker-compose.yml
ابحث في الملف عن الجزء الذي يتضمن تعريف خدمة certbot، وعوّض الراية staging--
في الخيار command بالراية force-renewal--
، والتي ستخبر Certbot أنك تريد طلب شهادة جديدة بنفس النطاقات التي في الشهادة الحالية. يجب أن يبدو تعريف خدمة certbot الآن كما يلي:
... certbot: image: certbot/certbot container_name: certbot volumes: - certbot-etc:/etc/letsencrypt - certbot-var:/var/lib/letsencrypt - web-root:/var/www/html depends_on: - webserver command: certonly --webroot --webroot-path=/var/www/html --email sammy@example.com --agree-tos
يمكنك الآن تنفيذ docker-compose up لإعادة إنشاء حاوية certbot ووحدات التخزين ذات الصلة. سنضمّن هنا أيضًا الخيار no-deps--
لنطلب من Compose تخطي تشغيل خدمة webserver، لأنها قيد التشغيل بالفعل:
docker-compose up --force-recreate --no-deps certbot
سوف تشير المخرجات التي ستظهر لك إلى نجاح طلبك للشهادة:
certbot | IMPORTANT NOTES: certbot | - Congratulations! Your certificate and chain have been saved at: certbot | /etc/letsencrypt/live/example.com/fullchain.pem certbot | Your key file has been saved at: certbot | /etc/letsencrypt/live/example.com/privkey.pem certbot | Your cert will expire on 2019-03-26. To obtain a new or tweaked certbot | version of this certificate in the future, simply run certbot certbot | again. To non-interactively renew *all* of your certificates, run certbot | "certbot renew" certbot | - Your account credentials have been saved in your Certbot certbot | configuration directory at /etc/letsencrypt. You should make a certbot | secure backup of this folder now. This configuration directory will certbot | also contain certificates and private keys obtained by Certbot so certbot | making regular backups of this folder is ideal. certbot | - If you like Certbot, please consider supporting our work by: certbot | certbot | Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate certbot | Donating to EFF: https://eff.org/donate-le certbot | certbot exited with code 0
بحصولك على الشهادات اللازمة، يمكنك الانتقال إلى تعديل تكوين Nginx لتضمين SSL.
الخطوة الخامسة: تعديل تكوين خادم الويب وتعريف الخدمة
سيتطلب تفعيل SSL في تكوين Nginx الخاص بنا إضافة إعادة توجيه HTTP إلى HTTPS وتحديد شهادة SSL والمواقع الرئيسية. سيتضمن أيضًا تحديد مجموعتنا Diffie-Hellman
، والتي سنستخدمها في Perfect Forward Secrecy
.
ونظرًا لأنك ستعيد إنشاء خدمة webserver لتضمين هذه الإضافات، فيمكنك إيقافها الآن:
docker-compose stop webserver
أنشئ بعد ذلك مجلّدًا في مجلّد المشروع الحالي من أجل مفتاحك Diffie-Hellman:
mkdir dhparam
ثم أنشئ مفتاحك باستخدام الأمر openssl
:
sudo openssl dhparam -out /home/sammy/node_project/dhparam/dhparam-2048.pem 2048
سوف يستغرق الأمر بضع دقائق لإنشاء المفتاح.
لإضافة معلومات Diffie-Hellman و SSL ذات الصلة إلى تكوين Nginx، احذف أولاً ملفّ تكوين Nginx الذي أنشأته مسبقًا:
rm nginx-conf/nginx.conf
افتح نسخة أخرى من الملف:
nano nginx-conf/nginx.conf
أضف الشيفرة التالية إلى الملف لإعادة توجيه HTTP إلى HTTPS ولإضافة بيانات اعتماد SSL والبروتوكولات وترويسات الأمان (security headers). لاتنس تعويض example.com بنطاقك الخاص:
server { listen 80; listen [::]:80; server_name example.com www.example.com; location ~ /.well-known/acme-challenge { allow all; root /var/www/html; } location / { rewrite ^ https://$host$request_uri? permanent; } } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name example.com www.example.com; server_tokens off; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; ssl_buffer_size 8k; ssl_dhparam /etc/ssl/certs/dhparam-2048.pem; ssl_protocols TLSv1.2 TLSv1.1 TLSv1; ssl_prefer_server_ciphers on; ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5; ssl_ecdh_curve secp384r1; ssl_session_tickets off; ssl_stapling on; ssl_stapling_verify on; resolver 8.8.8.8; location / { try_files $uri @nodejs; } location @nodejs { proxy_pass http://nodejs:8080; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer-when-downgrade" always; add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always; # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # enable strict transport security only if you understand the implications } root /var/www/html; index index.html index.htm index.nginx-debian.html; }
تحدد هذه الكتلة الخاصة بالخادم HTTP هوية الخادم webroot المستخدم لطلبات تجديد Certbot على الملف .well-known/acme-challenge. وتتضمن أيضًا توجيهًا لإعادة الكتابة (rewrite directive) يوجه طلبات HTTP إلى المجلّد الجذري إلى HTTPS.
أما الكتلة الخاصة بخادم HTTPS فيفعّل SSL و HTTP2. لقراءة المزيد حول كيفية تكرار HTTP/2 على بروتوكولات HTTP والمزايا التي يمكن أن يوفرها لتحسين أداء موقع الويب، يرجى الاطلاع على مقدمة كيفية إعداد Nginx مع دعم HTTP/2 على أوبونتو 18.04. يتضمن هذا الجزء أيضًا سلسلة من الخيارات للتأكد من أنك تستخدم أحدث بروتوكولات SSL والتشفيرات وأن تدبيس OSCP) OSCP stapling) قيد التشغيل. ويسمح لك تدبيس OSCP بتقديم استجابة ذات ختم زمني (time-stamped) من سلطة الإشهاد الخاصة بك أثناء عملية إنشاء الاتصال TLS الأولي، والتي يمكنها تسريع عملية المصادقة.
يحدّد الجزء أيضًا بيانات اعتماد SSL و Diffie-Hellman والمواقع الرئيسية.
ختامًا، لقد نقلنا معلومات مرور الوكيل إلى هذه الكتلة، بما في ذلك كتلة موقع تتضمّن توجيه try_files، لتوجيه الطلبات إلى حاوية تطبيق Node.js ذات تسمية بديلة، وكتلة موقع لتلك التسمية البديلة، والتي تتضمن ترويسات الأمان التي ستمكننا من الحصول على تقييمات حول أشياء مثل مواقع اختبار خادم SSL Labs ومواقع الأمان. تتضمن هذه الترويسات خيارات X-Frame-Options
و X-Content-Type-Options
وسياسة الإحالة وسياسة أمان المحتوى و X-XSS-Protection
. يتم التصريح علنًا بالترويسة HSTS (اختصار للعبارة HTTP Strict Transport Security)، فعّل هذه فقط إذا فهمت الآثار المترتبة على ذلك وعملت على تقييم الوظيفة "التحميل المسبق" (preload).
احفظ الملف وأغلقه عند الانتهاء من التحرير.
قبل إعادة إنشاء خدمة webserver، ستحتاج إلى إضافة بعض الأشياء إلى تعريف الخدمة في ملف docker-compose.yml ، بما في ذلك معلومات المنفذ ذات الصلة لـ HTTPS وتعريف وحدة تخزين Diffie-Hellman.
افتح الملف:
nano docker-compose.yml
أضف في تعريف خدمة webserver تعيين المنفذ التالي ووحدة التخزين المسماة dhparam:
... webserver: image: nginx:latest container_name: webserver restart: unless-stopped ports: - "80:80" - "443:443" volumes: - web-root:/var/www/html - ./nginx-conf:/etc/nginx/conf.d - certbot-etc:/etc/letsencrypt - certbot-var:/var/lib/letsencrypt - dhparam:/etc/ssl/certs depends_on: - nodejs networks: - app-network
أضف بعد ذلك وحدة تخزين dhparam إلى تعريفات وحدات التخزين الخاصة بك:
... volumes: ... dhparam: driver: local driver_opts: type: none device: /home/sammy/node_project/dhparam/ o: bind
على غرار وحدة التخزين web-root، ستركّب وحدة تخزين dhparam مفتاح Diffie-Hellman المخزن على المضيف في حاوية webserver.
احفظ الملف وأغلقه عند الانتهاء من التحرير.
ثم أعد إنشاء خدمة webserver:
docker-compose up -d --force-recreate --no-deps webserver
وتحقق من خدماتك باستخدام docker-compose ps:
docker-compose ps
يجب أن تشاهد الإخراج يشير إلى أن العقدة وخدمات خادم الويب تعمل:
Name Command State Ports ---------------------------------------------------------------------------------------------- certbot certbot certonly --webroot ... Exit 0 nodejs node app.js Up 8080/tcp webserver nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
ختامًا، يمكنك زيارة عنوان نطاقك لضمان عمل كل شيء على النحو المنتظر. انتقل في متصفحك إلى https://example.com، مع الحرص على تعويض example.com باسم نطاقك. ستظهر لك صفحة الهبوط التالية:
وينبغي أن تشاهد أيضًا رمز القفل في مؤشر أمان متصفحك. إذا كنت ترغب في ذلك، يمكنك الانتقال إلى صفحة الهبوط لاختبار SSL Labs Server أو صفحة اختبار خادم ترويسات الأمان. يجب أن تمنح خيارات التكوين التي أدرجناها لموقعك تصنيفًا على كليهما.
الخطوة السادسة: تجديد الشهادات
تكون شهادات Let’s Encrypt صالحة لمدة 90 يومًا، لذلك ستحتاج إلى إعداد عملية تجديد تلقائية حرصًا على عدم انقضاء صلاحيتها. إحدى الطرق للقيام بذلك هي إنشاء وظيفة باستخدام أداة جدولة cron. في هذه الحالة، سنقوم بجدولة مهمة cron باستخدام سكربتٍ لتجديد شهاداتنا وإعادة تحميل تكوين Nginx الخاص بنا.
افتح سكربتًا بالاسم ssl_renew.sh
في مجلّد مشروعك:
nano ssl_renew.sh
أضف الشيفرة التالية إلى السكربت لتجديد شهاداتك وإعادة تحميل تكوين خادم الويب الخاص بك:
#!/bin/bash /usr/local/bin/docker-compose -f /home/sammy/node_project/docker-compose.yml run certbot renew --dry-run \ && /usr/local/bin/docker-compose -f /home/sammy/node_project/docker-compose.yml kill -s SIGHUP webserver
بالإضافة إلى تحديد موقع ملف docker-compose الثنائي، فإننا نحدد أيضًا موقع ملف docker-compose.yml الخاص بنا من أجل تشغيل أوامر docker-compose. في هذه الحالة، نستخدم docker-compose run لتشغيل حاوية certbot ولإبطال الأمر command المقدم في تعريف خدمتنا بأمر آخر: وهو الأمر الفرعي renew، والذي سيقوم بتجديد الشهادات التي تكون على وشك الانتهاء. لقد قمنا بتضمين خيار dry-run-- هنا لاختبار السكربت.
ثم يستخدم السكربت kill docker-compose
لإرسال إشارة SIGHUP إلى حاوية خادم الويب لإعادة تحميل تكوين Nginx. لمزيد من المعلومات حول استخدام هذه العملية لإعادة تحميل تكوين Nginx، يرجى الاطلاع على منشور مدونة Docker هذا عن نشر صورة Nginx الرسمية باستخدام Docker.
أغلق الملف عند الانتهاء من التحرير. ثم اجعله قابلًا للتنفيذ:
chmod +x ssl_renew.sh
بعد ذلك، افتح ملف الجذر crontab الخاص بك لتنفيذ سكربت التجديد في مجال زمني محدد:
sudo crontab -e
إذا كانت هذه هي المرة الأولى التي تقوم فيها بتحرير هذا الملف، فسيُطلب منك اختيار محرّر:
no crontab for root - using an empty one Select an editor. To change later, run 'select-editor'. 1. /bin/ed 2. /bin/nano <---- easiest 3. /usr/bin/vim.basic 4. /usr/bin/vim.tiny Choose 1-4 [2]: ...
أضف السطر التالي في الجزء السفلي من الملف:
... */5 * * * * /home/sammy/node_project/ssl_renew.sh >> /var/log/cron.log 2>&1
سيعيّن ذلك المجال الزمني للوظيفة على كل خمس دقائق، إذ يمكنك اختبار ما إذا كان طلبك للتجديد يعمل على النحو المنشود. لقد أنشأنا أيضًا ملف سجل، cron.log، لتسجيل المخرجات ذات الصلة من الوظيفة.
بعد خمس دقائق، تحقق من cron.log لمعرفة ما إذا كان طلب التجديد قد نجح أم لا:
tail -f /var/log/cron.log
يجب أن يظهر لك الإخراج التالي مؤكِّدًا نجاح التجديد:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates below have not been saved.) Congratulations, all renewals succeeded. The following certs have been renewed: /etc/letsencrypt/live/example.com/fullchain.pem (success) ** DRY RUN: simulating 'certbot renew' close to cert expiry ** (The test certificates above have not been saved.) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Killing webserver ... done
يمكنك الآن تعديل ملف crontab لتعيين مجال زمني يومي. لتنفيذ السكربت كل يوم عند الظهر، على سبيل المثال، يمكنك تعديل السطر الأخير من الملف ليبدو كما يلي:
... 0 12 * * * /home/sammy/node_project/ssl_renew.sh >> /var/log/cron.log 2>&1
ستحتاج أيضًا إلى حذف الخيار dry-run--
من السكربت ssl_renew.sh:
#!/bin/bash /usr/local/bin/docker-compose -f /home/sammy/node_project/docker-compose.yml run certbot renew \ && /usr/local/bin/docker-compose -f /home/sammy/node_project/docker-compose.yml kill -s SIGHUP webserver
ستضمن مهمة cron ألا تنقضي صلاحية شهاداتك " Let’s Encrypt" عبر تجديدها عند الاقتضاء. يمكنك أيضًا إعداد تدوير السجل باستخدام الأداة المساعدة Logrotate لتدوير وضغط ملفات السجل.
خاتمة
لقد استخدمت حاوياتٍ لإعداد وتشغيل تطبيق Node باستخدام وكيل Nginx عكسي. كما حصلت أيضًا على شهادات SSL لنطاق تطبيقك وأعددت وظيفة cron لتجديد هذه الشهادات عند الضرورة.
إذا كنت مهتمًا بمعرفة المزيد عن Let's Encrypt Plugins، فيرجى الاطلاع على مقالاتنا حول استخدام المكون الإضافي Nginx أو المكون الإضافي المستقل.
يمكنك أيضًا معرفة المزيد حول Docker Compose من خلال الاطلاع على الموارد التالية:
- كيفية تثبيت Docker Compose على أوبونتو 18.04.
- كيفية تكوين بيئة اختبار تكامل مستمر مع تكوين Docker و Docker Compose على أوبونتو 16.04.
- كيفية إعداد Laravel وNginx وMySQL باستخدام Docker. ويعدّ توثيق Docker أيضًا مورداً رائعًا لمعرفة المزيد حول التطبيقات متعددة الحاويات.
ترجمة -وبتصرف- للمقال How To Secure a Containerized Node.js Application with Nginx, Let's Encrypt, and Docker Compose لصاحبته Kathleen Juell
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.