إدارة أنظمة لينكس

مشروع: تقوية خادم إنتاجي وتشغيله

45 دقيقة الدرس 10 من 28

مشروع: تقوية خادم إنتاجي وتشغيله

كل ما تعلمته في هذا الفصل — systemd وjournald والتخزين والمراقبة وتحليل الأداء والشبكة وتقوية SSH والمهام المجدولة — يتقاطع هنا. يأخذك هذا المشروع الختامي خطوةً خطوةً في إعداد خادم Ubuntu 24.04 LTS جديد من حالة "تسجيل الدخول كـroot مسموح، كل الإعدادات افتراضية" إلى نظام إنتاجي مُقوَّى وقابل للرصد وقادر على صيانة نفسه. كل خطوة تعكس ما يفعله مهندسو SRE الكبار في اليوم الأول لأي خادم جديد في الشركات الحقيقية.

ما يغطيه هذا المشروع: سنُهيِّئ حساب مسؤول غير جذر مع SSH محكم، ونُقوِّي النواة وسطح الخدمة، ونُعِدّ خدمة تطبيق نموذجية تحت systemd مع حدود موارد، ونُهيِّئ مراقبة الأقراص مع تنبيهات آلية، ونُرسي جمع سجلات مركزياً، ونربط جدول صيانة كامل بـcron — ثم نتحقق من كل طبقة.

المرحلة الأولى: الوصول المبدئي وإعداد المستخدمين

تحصل على مثيل سحابي بصلاحية root فقط. الخطوة الأولى هي إنشاء حساب مسؤول مخصص بصلاحيات sudo، وتقوية SSH، وتعطيل تسجيل دخول root نهائياً.

# على الخادم الجديد بصفة root: # 1. إنشاء مستخدم عمليات useradd -m -s /bin/bash -G sudo opsadmin passwd opsadmin # ضبط عبارة مرور قوية — مطلوبة فقط لأوامر sudo # 2. قفل كلمة مرور root (sudo هو مسار الرفع الوحيد) passwd -l root # 3. نسخ مفتاحك العام إلى الحساب الجديد mkdir -p /home/opsadmin/.ssh chmod 700 /home/opsadmin/.ssh # الصق المفتاح العام من محطة عملك: # cat ~/.ssh/id_ed25519.pub (نفِّذ هذا على جهازك المحلي أولاً) echo "ssh-ed25519 AAAA...your-public-key... ops@workstation" \ >> /home/opsadmin/.ssh/authorized_keys chmod 600 /home/opsadmin/.ssh/authorized_keys chown -R opsadmin:opsadmin /home/opsadmin/.ssh

المرحلة الثانية: تقوية SSH

عدِّل /etc/ssh/sshd_config بالكتلة التالية. كل سطر هنا موجود في إعدادات الإنتاج في كل شركة تقنية من الدرجة الأولى — ليست بارانويا اختيارية، بل معيار أساسي:

# /etc/ssh/sshd_config — استبدل أو أضف هذه التوجيهات Port 2222 # منفذ غير افتراضي يقلل ضجيج الماسحات الآلية Protocol 2 # SSHv1 معطوب؛ أجبر v2 فقط PermitRootLogin no # لا تسمح بـSSH للجذر مطلقاً PasswordAuthentication no # المصادقة بالمفتاح فقط؛ كلمات المرور قابلة للاختراق بالقوة PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys MaxAuthTries 3 # قفل بعد 3 محاولات فاشلة LoginGraceTime 30 # إنهاء الاتصالات غير المصادق عليها بعد 30 ثانية ClientAliveInterval 300 # يرسل الخادم keepalive كل 5 دقائق ClientAliveCountMax 2 # قطع الاتصال بعد 2 keepalive فائت (10 دقائق خمول) AllowUsers opsadmin # قائمة بيضاء — فقط المستخدمون المسمَّون صراحةً يمكنهم تسجيل الدخول X11Forwarding no # لا نقل نافذة رسومية على خادم AllowTcpForwarding no # منع استخدام SSH كبروكسي SOCKS (إلا إن احتجت) Banner /etc/ssh/ssh_banner # عرض تحذير قانوني قبل المصادقة
# إنشاء لافتة قانونية (تظهر قبل المصادقة — متطلب مسؤولية في كثير من الشركات) cat > /etc/ssh/ssh_banner <<'EOF' *********************************************************************** Authorised access only. All connections are monitored and logged. Disconnect immediately if you are not an authorised user. *********************************************************************** EOF # التحقق من الإعداد قبل إعادة التشغيل (خطوة حاسمة — خطأ مطبعي يُغلق عليك الباب) sshd -t echo "Exit code: $?" # يجب أن يكون 0 # التطبيق systemctl restart ssh # افتح المنفذ الجديد قبل قطع الاتصال (خذل أمان: ابق الجلسة القديمة مفتوحة) ufw allow 2222/tcp ufw enable
تحذير إنتاجي — تحقق دائماً قبل إعادة تشغيل sshd: تشغيل sshd -t يُنفِّذ تحليل جاف للإعداد. خطأ مطبعي في sshd_config سيُخرج غير صفري؛ إن شغَّلت systemctl restart ssh بدون هذا الفحص، سيرفض sshd البدء وستُقفَل خارج الخادم — مما يتطلب وصولاً عبر وحدة تحكم الاسترداد أو منفذ التسلسل للمثيل السحابي. هذا أحد أكثر الانقطاعات الذاتية شيوعاً بين المهندسين المبتدئين.

المرحلة الثالثة: تقوية النواة ونظام التشغيل

قوِّ مكدس شبكة النواة وعطِّل الخدمات غير المستخدمة. هذه الإعدادات مأخوذة مباشرةً من معيار CIS Ubuntu 24.04 LTS — المرجع المستخدم في Google وMeta وكل مؤسسة مالية كبرى:

# /etc/sysctl.d/99-hardening.conf # تحميل بالأمر: sysctl --system (أو إعادة التشغيل) # --- تقوية الشبكة --- net.ipv4.ip_forward = 0 # ليس موجه شبكة؛ تعطيل إعادة توجيه الحزم net.ipv4.conf.all.rp_filter = 1 # تصفية المسار العكسي (منع انتحال IP) net.ipv4.conf.default.rp_filter = 1 net.ipv4.conf.all.accept_redirects = 0 # تجاهل إعادة توجيه ICMP (ثغرة MITM) net.ipv4.conf.default.accept_redirects = 0 net.ipv6.conf.all.accept_redirects = 0 net.ipv4.conf.all.accept_source_route = 0 # تجاهل الحزم ذات التوجيه المصدري net.ipv4.icmp_echo_ignore_broadcasts = 1 # تجاهل ping البث (تضخيم smurf) net.ipv4.tcp_syncookies = 1 # حماية من فيضان SYN # --- تقوية النواة --- kernel.randomize_va_space = 2 # ASLR الكامل (تعشية تخطيط فضاء العناوين) kernel.dmesg_restrict = 1 # غير الجذر لا يمكنه قراءة حلقة النواة kernel.sysrq = 0 # تعطيل SysRq (لا حاجة له على خادم بدون شاشة) fs.protected_hardlinks = 1 fs.protected_symlinks = 1
# تطبيق إعدادات sysctl فوراً (لا حاجة لإعادة تشغيل) sysctl --system # تعطيل وإخفاء الخدمات غير المستخدمة (تقليل سطح الهجوم) for svc in avahi-daemon cups bluetooth ModemManager; do systemctl disable --now "$svc" 2>/dev/null systemctl mask "$svc" 2>/dev/null done # التحقق من عدم وجود استماع غير متوقع ss -tulnp | grep -v '127.0.0.1\|::1' # عرض المستمعين غير المحليين فقط

المرحلة الرابعة: نشر خدمة وإدارتها بـsystemd

يجب أن تعمل خدمة الإنتاج تحت مستخدم غير مميز مخصص، مع حدود موارد صارمة، وإعادة تشغيل تلقائية عند الفشل، وإرسال سجلات عبر journald. هذا المثال ينشر واجهة برمجية بسيطة بلغة Python للتحقق من الصحة — النمط ينطبق على أي daemon:

# إنشاء حساب خدمة غير مميز (بدون shell تسجيل دخول، بدون مجلد منزلي) useradd -r -s /sbin/nologin -d /opt/healthapi healthapi # تثبيت تطبيق بسيط mkdir -p /opt/healthapi cat > /opt/healthapi/server.py <<'EOF' from http.server import HTTPServer, BaseHTTPRequestHandler import json, time class Handler(BaseHTTPRequestHandler): def log_message(self, fmt, *args): print(fmt % args, flush=True) # journald يلتقط stdout def do_GET(self): if self.path == '/health': self.send_response(200) self.send_header('Content-Type','application/json') self.end_headers() self.wfile.write(json.dumps({'status':'ok','ts':time.time()}).encode()) else: self.send_response(404) self.end_headers() HTTPServer(('127.0.0.1', 8080), Handler).serve_forever() EOF chown -R healthapi:healthapi /opt/healthapi
# /etc/systemd/system/healthapi.service [Unit] Description=Health Check API Documentation=https://wiki.internal/healthapi After=network.target [Service] Type=simple User=healthapi Group=healthapi WorkingDirectory=/opt/healthapi ExecStart=/usr/bin/python3 /opt/healthapi/server.py Restart=on-failure RestartSec=5s StandardOutput=journal # كل stdout -> journald (قابل للبحث، يُدار تلقائياً) StandardError=journal # حدود الموارد (منع عملية مفلتة من إسقاط المضيف) LimitNOFILE=65536 # الحد الأقصى لمواصفات الملفات المفتوحة MemoryMax=256M # إيقاف الخدمة إن تجاوزت 256 ميجابايت CPUQuota=20% # لا تستهلك أكثر من 20% من معالج واحد # تأمين صندوق الرمل NoNewPrivileges=yes PrivateTmp=yes # الخدمة تحصل على /tmp خاص بها ProtectSystem=strict ReadWritePaths=/opt/healthapi [Install] WantedBy=multi-user.target
# التحميل والتفعيل والتشغيل والتحقق systemctl daemon-reload systemctl enable --now healthapi systemctl status healthapi # متابعة سجل الخدمة في الوقت الفعلي journalctl -u healthapi -f # اختبار نقطة النهاية من المضيف المحلي للتأكد من عملها curl -s http://127.0.0.1:8080/health

المرحلة الخامسة: مراقبة القرص والتنبيهات الآلية

تتسبب حوادث امتلاء القرص في تلف صامت للبيانات، وأعطال قواعد البيانات، وتعليق التطبيقات — كل ذلك بدون رسالة خطأ واضحة. أعِدّ مراقبة آلية لاصطياد هذا قبل وقوعه:

# /usr/local/bin/disk-alert.sh #!/usr/bin/env bash # إرسال تنبيه إلى ملف سجل وjournald إن تجاوز أي نظام ملفات العتبة % THRESHOLD=80 ALERT_LOG=/var/log/disk-alert.log df -h --output=target,pcent | tail -n +2 | while read -r mount pct; do usage="${pct%\%}" # إزالة علامة % if [[ "$usage" -ge "$THRESHOLD" ]]; then msg="[DISK ALERT] $(date -Iseconds) ${mount} is at ${pct} (threshold: ${THRESHOLD}%)" echo "$msg" | tee -a "$ALERT_LOG" # في الإنتاج: استبدل echo بـcurl لـPagerDuty/Slack webhook أو sendmail logger -t disk-alert -p user.crit "$msg" # يُرسل أيضاً لـjournald عبر syslog fi done
chmod +x /usr/local/bin/disk-alert.sh # ربطه بـcron كل 15 دقيقة: echo "*/15 * * * * root /usr/local/bin/disk-alert.sh" \ > /etc/cron.d/disk-alert # اختبار يدوي فوري: /usr/local/bin/disk-alert.sh && echo "Script executed cleanly"

المرحلة السادسة: إدارة السجلات وسجل التدقيق

هيِّئ journald للتخزين الدائم والاحتفاظ المنطقي، ثم ربط logrotate لأي سجلات نصية تكتبها سكريبتاتك:

# /etc/systemd/journald.conf.d/99-production.conf [Journal] Storage=persistent # الاستمرار بعد إعادة التشغيل Compress=yes SystemMaxUse=2G # لا تستهلك أكثر من 2 جيجابايت SystemKeepFree=500M # اترك دائماً 500 ميجابايت حرة MaxRetentionSec=90day # حذف تلقائي للإدخالات الأقدم من 90 يوماً MaxFileSec=1week # تدوير ملفات اليومية أسبوعياً ForwardToSyslog=no # لا كتابة مزدوجة لـrsyslog (يوفر I/O)
# إعادة تشغيل journald لتطبيق الإعداد systemctl restart systemd-journald # فحص استخدام القرص الحالي لليوميات journalctl --disk-usage # تفريغ يدوي بحجم مستهدف: journalctl --vacuum-size=1G journalctl --vacuum-time=90d # إعداد logrotate لسجل التنبيه المخصص cat > /etc/logrotate.d/disk-alert <<'EOF' /var/log/disk-alert.log { daily rotate 30 compress delaycompress missingok notifempty create 640 root adm } EOF # اختبار إعداد logrotate (تشغيل جاف) logrotate -d /etc/logrotate.d/disk-alert

المرحلة السابعة: مهام الصيانة المجدولة

يحتاج كل خادم إنتاجي إلى مجموعة من مهام الصيانة الدورية. نستخدم cron للأوامر البسيطة وsystemd timers للمهام التي تحتاج تتبع تبعيات أو حدود موارد:

# /etc/cron.d/server-maintenance # جميع الأوقات بـUTC (يجب دائماً تشغيل الخوادم بـUTC — المناطق الزمنية المحلية مصدر أخطاء) # تصحيحات الأمان: بلا رقابة يومياً (التحديثات الأمنية فقط) 0 3 * * * root unattended-upgrades -d >> /var/log/unattended-upgrades/unattended-upgrades.log 2>&1 # تحديث كامل للحزم أسبوعياً (راجع قبل التطبيق على الأنظمة الحرجة) 0 4 * * 0 root apt-get update -qq && apt-get upgrade -y -q >> /var/log/apt-weekly.log 2>&1 # فحص القرص يومياً كل 15 دقيقة */15 * * * * root /usr/local/bin/disk-alert.sh # حذف ملفات /tmp القديمة (منع امتلاء القرص) 0 2 * * * root find /tmp -type f -mtime +7 -delete 2>/dev/null # التحقق من استجابة healthapi كل 5 دقائق (مراقبة بسيطة) */5 * * * * root curl -sf http://127.0.0.1:8080/health >/dev/null || systemctl restart healthapi

المرحلة الثامنة: قائمة التحقق النهائية

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

Production server hardening checklist layers Control Layer Verification Command SSH Hardening Port 2222, key-only, no root, whitelist sshd -T | grep -E 'permitroot|passauth' ss -tlnp | grep sshd Minimal Service Surface Only required services running systemctl list-units --state=running ss -tulnp | grep -v 127 Kernel Hardening sysctl settings applied and persistent sysctl net.ipv4.tcp_syncookies sysctl kernel.randomize_va_space Application Service Unprivileged user, resource limits, restarts systemctl status healthapi curl http://127.0.0.1:8080/health Disk Monitoring & Logging Alerts, rotation, journal limits /usr/local/bin/disk-alert.sh journalctl --disk-usage Scheduled Tasks Cron jobs, unattended upgrades, probes crontab -l -u root systemctl list-timers Firewall (UFW) Only port 2222 (SSH) open externally ufw status verbose nmap -sV -p 1-1024 <server-ip>
طبقات التحكم السبع لخادم إنتاجي مُقوَّى مع أوامر التحقق المقابلة لها.
# تنفيذ جميع فحوصات التحقق بالتسلسل echo "=== SSH config ===" sshd -T | grep -E "permitrootlogin|passwordauthentication|port|allowusers" echo "=== Listening ports (external) ===" ss -tulnp | grep -v '127.0.0.1\|::1' echo "=== Kernel sysctl (key values) ===" sysctl net.ipv4.tcp_syncookies net.ipv4.conf.all.rp_filter kernel.randomize_va_space echo "=== healthapi service ===" systemctl is-active healthapi && curl -sf http://127.0.0.1:8080/health echo "=== Journal disk usage ===" journalctl --disk-usage echo "=== Cron jobs ===" crontab -l -u root echo "=== Firewall ===" ufw status numbered echo "=== All services (running) ===" systemctl list-units --type=service --state=running --no-pager
نصيحة احترافية — البنية التحتية كرمز: بمجرد بناء هذا الخادم والتحقق منه يدوياً، التقط كل قرار إعداد في playbooks Ansible أو قالب Terraform + cloud-init. الخادم التالي يجب أن يُعاد إنتاجه بشكل متطابق في أقل من عشر دقائق. في Google وMeta، لا يُهيَّأ أي خادم إنتاجي يدوياً — كل شيء بالتحكم بالإصدارات ومراجعة الكود وتطبيق الأتمتة. الإعداد اليدوي هو دين تقني يتراكم بصمت حتى يُستدعى أحدهم الساعة الثانية صباحاً بسبب خادم "ثلج" يتصرف بشكل مختلف عن كل خادم آخر في الأسطول.

ما بنيته

في هذه المرحلة، لديك خادم متوافق مع الممارسة الإنتاجية في أي شركة من الدرجة الأولى:

  • الهوية: لا SSH للجذر، مصادقة بالمفتاح فقط، مستخدم غير مميز مخصص، لافتة قانونية.
  • سطح الشبكة: جدار حماية رفض افتراضي؛ المنفذ 2222 فقط مفتوح؛ النواة محمية ضد هجمات الشبكة الشائعة.
  • صحة الخدمة: التطبيق يعمل كحساب خدمة أقل امتيازاً تحت systemd، مع حدود للذاكرة والمعالج، وإعادة تشغيل تلقائية، وتسجيل كامل عبر journald.
  • الرصد: يوميات دائمة بحدود احتفاظ؛ تنبيهات القرص مربوطة بـcron كل 15 دقيقة.
  • الصيانة الذاتية: تحديثات أمنية بلا رقابة، تحديثات حزم أسبوعية، تنظيف الملفات المؤقتة، واستعادة الخدمة الآلية — كلها تعمل بجدول منتظم.
الخطوات التالية في منظمة حقيقية: يغطي هذا المشروع الأساس على مستوى نظام التشغيل. في الممارسة العملية ستُضيف: شحن سجلات مركزياً (Loki أو Splunk أو CloudWatch Logs)، كشف اختراق قائم على المضيف (AIDE وFalco)، مراقبة وقت تشغيل خارجية (Prometheus Blackbox Exporter أو خدمة SaaS)، إدارة الأسرار (Vault)، وأتمتة إدارة الإعداد (Ansible أو Chef أو Puppet). تلك المواضيع مغطاة في فصول لاحقة في مسار DevOps هذا.