مشروع مصغر: سكربت Ansible يجهز سيرفر Ubuntu خام بالكامل كخادم ويب جاهز

دقائق القراءة: 6

مشروع مصغر: سكربت Ansible يجهز سيرفر Ubuntu خام بالكامل كخادم ويب جاهز

عندما تستلم سيرفر Ubuntu جديداً من مزود سحابي، فأنت عملياً تبدأ من بيئة غير مكتملة: تحديثات نظام غير مطبقة، حزم أساسية ناقصة، جدار ناري غير مضبوط، ومستخدمون وصلاحيات قد لا تتوافق مع معايير الإنتاج. هنا تظهر القيمة الحقيقية لـ ما هو Ansible؟ وكيف تتحكم في 100 سيرفر Linux من حاسوبك المكتبي؟ لأنه يحول الإعداد اليدوي المتكرر إلى عملية موحدة، قابلة للإعادة، ويمكن تدقيقها بسهولة.

في هذا المشروع المصغر سنبني Playbook متقدماً يجهز السيرفر ليعمل كخادم ويب جاهز عبر تثبيت Nginx، تأمين الوصول، ضبط UFW، وإنشاء صفحة اختبار. الأهم أننا سنفكر بعقلية هندسية تجعل هذا الملف لاحقاً جزءاً من CI/CD Pipeline متكامل بدلاً من كونه مجرد سكربت عابر.

لماذا هذا المشروع مهم عملياً؟

الإعداد اليدوي لسيرفر واحد قد يبدو بسيطاً، لكن عند تكرار المهمة على عدة بيئات مثل staging وproduction تبدأ الفروقات الصغيرة في التراكم. نتيجة ذلك قد تواجه مشكلة اختلاف الإعدادات، أو خدمة تعمل في بيئة وتتوقف في أخرى، أو منافذ مفتوحة بلا داعٍ.

هذا النوع من الأتمتة يرتبط مباشرة بمفاهيم ما هو DevOps؟ ولماذا تدفع الشركات ثروات لمهندسي الأتمتة السحابية؟ لأن الهدف ليس فقط تنفيذ أوامر أسرع، بل بناء بيئة يمكن الوثوق بها. أي تغيير يصبح موثقاً داخل ملف YAML بدل أن يبقى معرفة شفوية داخل رأس مسؤول النظام.

المعمارية التي سنطبقها

سنفترض وجود جهاز تحكم محلي مثبت عليه Ansible، وسيرفر Ubuntu خام يمكن الوصول إليه عبر SSH. إذا لم تكن جهزت الاتصال مسبقاً فراجع إعداد الاتصال الآمن (SSH Keys) بدون كلمات مرور بين جهازك والخوادم لأن تشغيل الأتمتة بمفاتيح آمنة أفضل كثيراً من الاعتماد على كلمات المرور.

سنبني المشروع على ثلاثة مكونات أساسية:

  • ملف inventory لتعريف الخادم.
  • ملف playbook لتنفيذ المهام.
  • ملف قالب لصفحة ويب اختبارية للتأكد أن الخادم جاهز للخدمة.

ملف الجرد وتعريف الخادم

إذا كنت تريد فهماً أعمق لبناء ملفات الجرد فمقال كتابة ملفات الجرد (Inventory) لتعريف وتصنيف الخوادم يشرح الفكرة من الأساس. في مشروعنا سنستخدم ملفاً بسيطاً يكفي لسيرفر واحد، مع إمكانية توسعه لاحقاً لمجموعة كاملة.

all:
  hosts:
    web-01:
      ansible_host: 192.0.2.10
      ansible_user: ubuntu
      ansible_ssh_private_key_file: ~/.ssh/id_rsa

هذا التوصيف يفصل اسم الخادم المنطقي عن عنوانه الحقيقي. وهذه نقطة مهمة جداً عند العمل ضمن فرق أو داخل بيئات متعددة، لأن اسم web-01 سيبقى ثابتاً حتى لو تغيرت البنية السحابية أو عنوان IP.

الـ Playbook الكامل لتجهيز السيرفر

الملف التالي يمثل قلب المشروع. وهو يجمع بين تحديث النظام، تثبيت الحزم، إنشاء مستخدم إداري، ضبط الجدار الناري، نشر صفحة ويب، وضمان تشغيل الخدمة تلقائياً بعد الإقلاع. إذا كنت جديداً نسبياً على بناء ملفات المهام فاطلع أيضاً على أول Playbook لك: تثبيت البرامج (مثل Nginx و Node) آلياً بلغة YAML.

---
- name: Prepare raw Ubuntu server as ready web server
  hosts: all
  become: true

  vars:
    new_admin_user: deploy
    web_root: /var/www/html
    allowed_ssh_port: 22

  handlers:
    - name: restart nginx
      service:
        name: nginx
        state: restarted

  tasks:
    - name: Update apt cache
      apt:
        update_cache: true
        cache_valid_time: 3600

    - name: Upgrade all packages
      apt:
        upgrade: dist

    - name: Install required packages
      apt:
        name:
          - nginx
          - ufw
          - fail2ban
          - curl
          - git
        state: present

    - name: Ensure admin group sudo exists
      group:
        name: sudo
        state: present

    - name: Create deploy user
      user:
        name: "{{ new_admin_user }}"
        groups: sudo
        append: true
        shell: /bin/bash
        create_home: true

    - name: Add authorized key for deploy user
      authorized_key:
        user: "{{ new_admin_user }}"
        state: present
        key: "{{ lookup('file', lookup('env','HOME') + '/.ssh/id_rsa.pub') }}"

    - name: Allow OpenSSH in UFW
      ufw:
        rule: allow
        name: OpenSSH

    - name: Allow HTTP in UFW
      ufw:
        rule: allow
        port: "80"
        proto: tcp

    - name: Allow HTTPS in UFW
      ufw:
        rule: allow
        port: "443"
        proto: tcp

    - name: Enable UFW
      ufw:
        state: enabled
        policy: deny

    - name: Deploy custom index page
      copy:
        dest: "{{ web_root }}/index.html"
        content: |
          
          
          
            
            
            Ansible Provisioned Server
          
          
            

Server is ready

This Ubuntu web server was provisioned automatically using Ansible.

owner: www-data group: www-data mode: '0644' notify: restart nginx - name: Ensure nginx is enabled and running service: name: nginx state: started enabled: true - name: Ensure fail2ban is enabled and running service: name: fail2ban state: started enabled: true

كيف نفهم هذا الملف هندسياً؟

1) مبدأ Idempotency

أهم ما يميز Ansible أنه لا يعيد تنفيذ التغييرات دون حاجة. إذا كان Nginx مثبتاً بالفعل فلن تتم إعادة تثبيته، وإذا كان المستخدم موجوداً فلن يُنشأ من جديد. هذا يتيح تشغيل الملف عشرات المرات بأمان نسبي، وهي خاصية محورية عند ربطه مع ما هو الـ CI/CD؟ ولماذا نؤتمت عمليات اختبار ونشر الأكواد؟.

2) المعالجات الذكية Handlers

لاحظ أن إعادة تشغيل Nginx لا تحدث إلا عند تغيير الصفحة فعلاً. هذه الممارسة تقلل الانقطاعات غير الضرورية، ويمكنك التوسع فيها أكثر عبر مقال المعالجات (Handlers): إعادة تشغيل الخدمات فقط عند حدوث تغيير في السيرفر.

3) الحماية ليست خطوة لاحقة

الكثيرون يثبتون الخدمة أولاً ثم يفكرون بالأمان لاحقاً، وهذه مقاربة خطرة. داخل هذا المشروع تم تضمين UFW وfail2ban منذ البداية لأن الأمان الجيد يجب أن يكون جزءاً من عملية provisioning نفسها.

لا تفعّل الجدار الناري على السيرفرات البعيدة قبل التأكد أن منفذ SSH المسموح صحيح، وإلا قد تعزل نفسك عن الخادم بالكامل. اختبر دائماً على بيئة تجريبية أو استخدم جلسة احتياطية مفتوحة قبل تطبيق القواعد النهائية.

تشغيل المشروع واختباره

بعد حفظ الملفين، نفذ أمر الفحص أولاً ثم أمر التطبيق. هذه الممارسة تقلل المفاجآت وتكشف مبكراً عن أخطاء المسارات أو المفاتيح أو البنية.

ansible-inventory -i inventory.yml --graph
ansible all -i inventory.yml -m ping
ansible-playbook -i inventory.yml webserver.yml

إذا نجح التنفيذ، افتح عنوان السيرفر في المتصفح وستظهر صفحة الاختبار. كما يمكنك فحص الخدمة يدوياً عبر curl للتأكد من أن طبقة الويب تستجيب خارجياً.

curl http://192.0.2.10

كيف نطوره إلى مسار إنتاج حقيقي؟

هذا المشروع هو نواة ممتازة لتوسعات أكبر. يمكنك مثلاً إضافة قوالب Jinja2 لملفات المواقع، أو تقسيم المهام إلى roles مستقلة، أو ربطه مع مقدمة في GitHub Actions: كتابة أول مسار عمل (Workflow) بحيث يُشغّل تلقائياً بعد مراجعة الكود.

وفي البيئات الحديثة قد لا يكون Nginx هو التطبيق النهائي، بل مجرد طبقة أمامية تستقبل حركة المرور قبل تمريرها إلى تطبيقات تعمل داخل حاويات. عندها يصبح من المفيد الربط مع مفاهيم مثل مشكلة “الكود يعمل على جهازي فقط” وكيف يحلها Docker نهائياً؟ ثم بناء مسار أوسع يشمل التحزيم والنشر والتهيئة.

في بيئات الإنتاج الحقيقية، لا تضع المفاتيح العامة والخاصة أو الأسرار الحساسة مباشرة داخل المستودع. استخدم آليات تخزين آمنة مثل Vault أو أسرار منصات الأتمتة، وراجع أيضاً إدارة الأسرار (GitHub Secrets) لحماية كلمات المرور ومفاتيح الـ API في الأتمتة.

خلاصة هندسية

قيمة هذا المشروع لا تكمن في تثبيت Nginx فقط، بل في تحويل إعداد السيرفر من مهمة يدوية معرضة للنسيان والخطأ إلى وصف بنيوي يمكن تتبعه وتكراره. هذا هو جوهر البنية التحتية ككود: أن يصبح الخادم نفسه قابلاً للنسخ، والمراجعة، والتحسين المستمر.

ومتى أتقنت هذا النمط، ستصبح قادراً على بناء سلاسل نشر أكثر نضجاً تشمل إنشاء الخوادم، تهيئتها، نشر التطبيقات، ثم اختبارها تلقائياً. عندها لا يعود السيرفر “خاماً” إلا لدقائق معدودة، لأن الأتمتة ستتكفل بتحويله إلى بيئة ويب جاهزة بثقة وسرعة واتساق.

2 comments

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *