تغيير منفذ SSH على Rocky Linux مع SELinux وfirewalld
تعلّم تغيير منفذ SSH بأمان على Rocky Linux وAlmaLinux: استخدم firewalld وتسمية SELinux وsshd_config بالترتيب لتجنب فقدان جلستك الحالية.
لماذا يتطلب تغيير منفذ SSH ثلاث خطوات هنا
لتغيير منفذ SSH على Rocky Linux أو AlmaLinux أو CentOS Stream أو Fedora، لا يكفي تعديل واحد. تتحكم ثلاثة أنظمة منفصلة في نجاح الاتصال عبر المنفذ الجديد. يحدد firewalld ما إذا كانت الحزمة ستصل إلى الجهاز. ويحدد SELinux ما إذا كان sshd مسموحاً له بربط رقم المنفذ هذا أساساً. ويحدد sshd_config المنفذ الذي يطلبه البرنامج الخدمي. إذا تخطيت خطوة SELinux، يرفض البرنامج الخدمي بدء التشغيل. وإذا تخطيت خطوة firewalld، يبدأ البرنامج الخدمي ويستمع، لكن لا يستطيع أحد الوصول إليه.
على Ubuntu، تتطلب العملية نفسها تعديلاً واحداً وإعادة تشغيل، لأن Ubuntu يستخدم AppArmor بدلاً من SELinux، ولا يأتي بملف تعريف يقيّد المنافذ التي يمكن لـ sshd ربطها. إذا كان ufw قيد التشغيل هناك، فأضف قاعدة واحدة. هذا هو الفرق كله. تأتي عائلة RHEL مع firewalld قيد التشغيل وSELinux في وضع enforcing عند التثبيت الجديد، وكلاهما يتعامل مع أرقام المنافذ.
نفّذ العمل بالترتيب التالي، وستظل جلستك الحالية عاملة خلال كل خطوة:
- افتح المنفذ الجديد في firewalld، واترك المنفذ 22 مفتوحاً في الوقت الحالي.
- أضف تسمية SELinux للمنفذ الجديد باستخدام
semanage. - اضبط المنفذ في إعدادات sshd.
- أعد تشغيل
sshd، ثم سجّل الدخول عبر المنفذ الجديد من طرفية ثانية قبل إغلاق الطرفية الأولى.
اعثر على وحدة التحكم على الويب التي يوفرها مزودك (VNC أو serial) قبل البدء، وتحقق من إمكانية تسجيل الدخول من خلالها. هذه الوحدة هي وسيلتك للعودة إلى الخادم إذا حدث خطأ أثناء التغيير. يُعد تغيير المنفذ أحد أكثر الأسباب شيوعاً لفقدان المستأجر إمكانية الوصول إلى خادم دفع تكلفته للتو.
ثبّت semanage أولاً
semanage هي الأداة التي تعدّل إعدادات سياسة SELinux، ولا يتضمنها تثبيت Rocky Linux أو AlmaLinux بالحد الأدنى. توجد هذه الأداة في policycoreutils-python-utils.
sudo dnf install -y policycoreutils-python-utilsيعرض تشغيل الأمر قبل تثبيت تلك الحزمة الرسالة sudo: semanage: command not found، وعندها يقرر كثير من القراء أن SELinux غير مثبت ويتجاوزون هذه الخطوة. SELinux مثبت بالفعل. الأداة الإدارية فقط هي المفقودة. إذا كانت صيغة dnf جديدة عليك، فستعيدك المكافئات بين أمري dnf وapt إلى الصيغة التي تعرفها.
اختيار منفذ والتحقق من عدم استخدام أي خدمة له
يمكن استخدام أي منفذ TCP غير مستخدم من 1024 إلى 65535. أجرِ عمليتي التحقق التاليتين قبل اعتماده:
sudo ss -tlnp | grep -w 2222
sudo semanage port -l | grep -w 2222يوضح الفحص الأول ما إذا كانت إحدى العمليات تستمع على هذا الرقم. ويوضح الفحص الثاني ما إذا كانت سياسة SELinux قد خصصته مسبقاً لنوع خدمة آخر. لا يعرض المنفذ غير المستخدم أي نتيجة في أي من الفحصين. إذا كانت السياسة قد خصصته مسبقاً، يفشل semanage port -a في الخطوة 2 بالخطأ ValueError: Port tcp/2222 already defined، والحل هو اختيار رقم مختلف.
يُستخدم 2222 مثالاً في هذا الدليل بالكامل. وهو أيضاً أول منفذ يحاول الماسح فحصه بعد 22، لذلك اختر رقماً أقل وضوحاً على خادم فعلي.
الخطوة 1: افتح المنفذ في firewalld
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --list-portsيكتب --permanent القاعدة في ملف المنطقة على القرص، ولا يغيّر جدار الحماية قيد التشغيل. يحمّل --reload الإعدادات الموجودة على القرص إلى جدار الحماية قيد التشغيل. إذا تخطيت إعادة التحميل، فستوجد القاعدة لكنها لن تؤدي أي وظيفة حتى يُعاد تشغيل firewalld. وهذا من أكثر الأسباب شيوعاً لظهور فشل الإجراء بأكمله دون سبب واضح.
اترك إدخال الخدمة ssh كما هو الآن. فهذا الإدخال هو الذي يُبقي المنفذ 22 مفتوحاً، وهو وسيلة الرجوع التي تستخدمها أثناء الاختبار.
تحقق أيضاً من لوحة تحكم مزود الخدمة. يشغّل العديد من المضيفين جدار حماية شبكياً أمام VPS وخارج نظام التشغيل، لذلك قد يستمر إسقاط المنفذ الذي فتحته في firewalld عند مستوى الشبكة upstream. يشرح دليل أساسيات firewalld لـ VPS المناطق والفصل بين الإعدادات الفورية والدائمة إذا كان هذا النموذج جديداً عليك.
الخطوة 2: ضع تسمية للمنفذ في SELinux
sudo semanage port -a -t ssh_port_t -p tcp 2222
sudo semanage port -l | grep ssh_port_tيضيف -a تعييناً جديداً للمنفذ. ويمثّل -t ssh_port_t النوع الذي تحمله منافذ SSH. يسرد الأمر الثاني كل ما يشمله ssh_port_t الآن، حتى تتأكد من إضافة رقم المنفذ قبل تعديل البرنامج الخدمي.
لماذا يحظر SELinux المنفذ أصلاً
يمنح SELinux (Linux المحسّن للأمان) كل كائن في النظام تسمية، وتُعد أرقام منافذ TCP كائنات مثل غيرها. يعمل برنامج SSH الخفي داخل نطاق مقيّد يسمى sshd_t. تسمح السياسة لـ sshd_t بربط منافذ TCP التي تحمل التسمية ssh_port_t، والمنفذ الوحيد الذي يحمل هذه التسمية افتراضياً هو 22. عند مطالبة البرنامج الخفي بربط المنفذ 2222، تتحقق النواة من التسمية، وتجد النوع العام الذي عيّنته السياسة لذلك الرقم، ثم ترفض إذن name_bind على المقبس.
لهذا السبب لا يبدو هذا الفشل كمشكلة في جدار الحماية. ترفض النواة العملية قبل إنشاء أي مقبس استماع، لذلك يعرض sshd الخطأ وينتهي. أما مشكلة جدار الحماية فهي الصورة المعاكسة: البرنامج الخفي يعمل بصورة سليمة، لكن الحزم تُسقط أثناء دخولها.
يخبرك getenforce بالوضع الذي يعمل به النظام. في Permissive، تُسجَّل حالات الرفض ولكن لا يجري فرضها، لذلك يبدو تغيير المنفذ ناجحاً، ثم يتعطل في اليوم الذي يشغّل فيه أحدهم setenforce 1 أو يعيد فيه النظام التشغيل إلى وضع الفرض. عيّن تسمية للمنفذ في كلتا الحالتين. يشرح دليل أساسيات SELinux للخادم الأوضاع والسياقات والقيم المنطقية بالتفصيل.
الخطوة 3: تعيين المنفذ في إعدادات sshd
في Rocky Linux 9 و10، وAlmaLinux 9 و10، وإصدارات Fedora الحالية، يبدأ /etc/ssh/sshd_config بسطر include، لذلك يكون ملف drop-in هو الموضع المنظم لإجراء التغيير. عندها لا تتعارض تحديثات الحزمة مع تعديلاتك.
grep -n '^Include' /etc/ssh/sshd_config
echo 'Port 2222' | sudo tee /etc/ssh/sshd_config.d/10-port.conf
sudo sshd -tإذا لم يعثر grep على سطر Include، كما يحدث في Rocky Linux 8 والصور الأقدم الأخرى، فأضف Port 2222 مباشرةً إلى /etc/ssh/sshd_config بدلاً من ذلك. يحلل sshd -t الإعداد بالكامل، بما في ذلك ملفات drop-in، ويعرض أخطاء الصياغة. أصلح كل ما يعرضه قبل إعادة التشغيل، لأن فشل تحليل الإعداد يعني أن daemon لن يعمل مجدداً.
قد يظهر Port أكثر من مرة، ويستمع sshd إلى كل منفذ مذكور. إن إبقاء Port 22 إلى جانب Port 2222 خلال اليوم الأول يوفر طبقة أمان بسيطة، ما دمت تتذكر إزالته.
هل يبدأ sshd بواسطة وحدة socket؟
تبدأ بعض الصور SSH عبر تفعيل socket في systemd بدلاً من تشغيله كخدمة طويلة الأمد. عند إعداد ذلك، يتولى systemd مقبس الاستماع ويمرّر الاتصالات إلى sshd، لذلك يتجاهل السطر Port في sshd_config بالكامل. تحقّق قبل إعادة تشغيل أي شيء:
systemctl is-enabled sshd.socketتعني إجابة enabled أن المنفذ محدد في وحدة socket، وليس في sshd_config:
sudo systemctl edit sshd.socket[Socket]
ListenStream=
ListenStream=2222يُعد ListenStream= المجرد مطلوباً. تتراكم القيم عبر ملفات drop-in، ولذلك يستمر المقبس في الاستماع على 22 إضافة إلى 2222 إذا لم تُعيّن قيمة فارغة لمسح القائمة أولاً. طبّق ذلك باستخدام sudo systemctl daemon-reload، ثم استخدم sudo systemctl restart sshd.socket. إذا كانت الوحدة معطّلة أو غير موجودة على خادمك، فلا ينطبق عليك هذا القسم.
الخطوة 4: أعد التشغيل، ثم اختبر من طرفية ثانية
sudo systemctl restart sshd
systemctl status sshd
sudo ss -tlnp | grep sshdأبقِ هذه الطرفية مفتوحة. لا تسجّل الخروج منها. افتح طرفية ثانية على جهازك واتصل بالمنفذ الجديد:
ssh -p 2222 youruser@203.0.113.10أغلق الجلسة الأولى فقط بعد نجاح تسجيل الدخول الثاني. إذا لم ينجح، فستظل لديك صدفة يمكنك التراجع منها عن كل التغييرات. هذه العادة وحدها تفصل بين تغيير يستغرق خمس دقائق وآخر يتطلب قضاء فترة بعد الظهر في وحدة تحكم مزود الخدمة.
جدار الحماية أسقط الحزمة أم أن SELinux رفضها؟ كيف تميّز بينهما
من حاسوبك المحمول، يبدو الفشلان متطابقين تقريباً. لكن على الخادم، لا يتشابهان إطلاقاً.
- إذا أظهر
systemctl status sshdأن الوحدة فشلت، فهذا يعني أن الخدمة لم تحصل على مقبسها. السبب خطأ في الإعداد أو رفض من SELinux. - إذا كانت الوحدة نشطة وأظهر
ss -tlnpأن sshd يستمع على المنفذ الجديد، فالمشكلة في مسار الشبكة: firewalld، أو جدار الحماية المنفصل لدى مزود الخدمة، أو العنوان والمنفذ اللذان اتصلت بهما.
في حالة SELinux، اقرأ سجل التدقيق بدلاً من التخمين:
sudo ausearch -m AVC -ts recent
sudo journalctl -u sshd -n 50 --no-pagerيسمي رفض name_bind على الفئة tcp_socket العملية في comm="sshd"، ورقم المنفذ في src=، والتسمية التي يحملها المنفذ فعلياً في tcontext=. هذا الحقل الأخير هو الإجابة. أي قيمة غير ssh_port_t تعني أن الخطوة 2 لم تُطبَّق على المنفذ الذي تستخدمه، ويكون السبب عادةً خطأً مطبعياً في الرقم أو استخدام البروتوكول الخطأ. ثبّت setroubleshoot-server إذا كنت تفضّل أن يحوّل sealert السجل إلى جملة مفهومة.
تظهر الرسالة التي يكتبها sshd نفسه عندما ترفض النواة عملية الربط بهذا الشكل:
error: Bind to port 2222 on 0.0.0.0 failed: Permission denied.يُعد Permission denied على منفذ أعلى من 1024، حيث لا تحتاج عملية الربط إلى امتيازات root، مؤشراً على رفض SELinux. أما Address already in use في السطر نفسه، فيشير إلى خطأ مختلف: عملية أخرى تستخدم المنفذ. ومن جهة العميل، يميّز الفرق بين رفض الاتصال وانتهاء مهلة الاتصال بين حالتي الشبكة، لأن الرفض يعني أن حزمتك وصلت إلى المضيف ولم تكن هناك خدمة تستمع، بينما يعني انتهاء المهلة أن أي جهة لم تُجب إطلاقاً.
أغلق المنفذ 22 وحدّث عملاءك
بعد نجاح عدة عمليات تسجيل دخول عبر المنفذ الجديد، أزل المنفذ 22:
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --reload
sudo firewall-cmd --list-allاترك وسم SELinux على المنفذ 22 كما هو. يأتي هذا الوسم من السياسة الأساسية، ولا يمنح أي وصول بعد أن يتوقف الجدار الناري عن السماح بدخول الحزم.
ثم حدّث إعدادات العملاء، لأن كل أداة افترضت المنفذ الافتراضي تحتاج الآن إلى تحديده. أضف الإعداد إلى ~/.ssh/config على جهازك مرة واحدة، بدلاً من كتابة -p في كل مرة:
Host myvps
HostName 203.0.113.10
Port 2222
User youruserتقرأ scp وsftp وrsync وAnsible هذا الملف. أما مهام النسخ الاحتياطي وفحوصات المراقبة ونصوص cron التي تحدد المنفذ 22 صراحةً فلا تقرؤه، لذلك ابحث عنها الآن ما دامت تفاصيل التغيير ما تزال واضحة.
ما الذي يحققه تغيير المنفذ وما لا يحققه
يقلل ذلك ضوضاء السجلات. تهاجم أدوات الفحص الآلية المنفذ 22 باستمرار، ونقل الخدمة منه يزيل معظم هذه الأسطر من journal، مما يسهّل رؤية الأحداث الفعلية. لكنه ليس إجراءً أمنياً. فأي أداة فحص تمسح نطاق المنافذ كاملاً ستعثر على خدمتك وتقرأ banner الإصدار الخاص بها على أي حال. اعتبر تغيير المنفذ إجراءً تنظيمياً، واجعل الحماية الفعلية تعتمد على المصادقة بالمفاتيح فقط مع تعطيل تسجيل الدخول بكلمات المرور. يشرح دليل تعزيز أمان SSH لخادم VPS ذلك خطوة بخطوة.
تعمل كل الخطوات السابقة بالطريقة نفسها على نسختي RHEL الرئيسيتين، لأنهما مبنيتان من المصادر نفسها. راجع مقارنة Rocky Linux وAlmaLinux إذا كنت لا تزال تختار بينهما. تحقّق من الإصدار الذي حصلت عليه فعلياً قبل اتباع أي دليل أقدم، باستخدام cat /etc/os-release. لا تزال الأدلة المكتوبة لـRocky Linux 8 تحظى بترتيب جيد، ولا تزال خطوتا semanage وfirewall-cmd فيها صحيحتين، لكن Rocky 8 لا يحتوي على سطر include sshd_config.d، ولا توجد فيه وحدة socket تحتاج إلى مراعاتها. لذلك لا يتطابق جزء sshd من تلك الأدلة مع خادم حالي.
يجب إبلاغ fail2ban بالمنفذ الجديد
لا يوجد fail2ban في المستودعات الأساسية. يأتي من EPEL (الحزم الإضافية لـ Enterprise Linux):
sudo dnf install -y epel-release
sudo dnf install -y fail2ban fail2ban-firewalldيجعل الحُزَيمة الفرعية fail2ban-firewalld fail2ban يكتب حالات الحظر عبر firewalld، وهذا هو الإعداد المطلوب على خادم يتولى فيه firewalld إدارة مجموعة القواعد.
تضبط jail الافتراضية sshd القيمة port = ssh، ويُحل هذا الاسم عبر /etc/services إلى 22. بعد تغييرك، تراقب jail منفذاً لا يستهدفه أحد، لذلك لا تحظر أي عنوان بينما تتراكم محاولات تسجيل الدخول الفاشلة على 2222. اضبط المنفذ رقميًا في /etc/fail2ban/jail.local:
[sshd]
enabled = true
port = 2222
backend = systemd
maxretry = 5
bantime = 3600يقرأ backend = systemd حالات الفشل من journal بدلاً من /var/log/secure، وهذا هو الخيار الأكثر أماناً في تثبيت minimal قد لا يكون فيه rsyslog متاحاً. شغّله باستخدام sudo systemctl enable --now fail2ban، وافحص jail باستخدام sudo fail2ban-client status sshd. صياغة jail هي نفسها المستخدمة في إعداد fail2ban لـ SSH على Ubuntu 24.04. يختلف فقط مصدر الحزمة وإجراء الحظر.
التحديثات الأمنية أهم من تغيير المنفذ
يكون الخادم الذي نُقل منفذ SSH فيه ولم تُطبَّق عليه تحديثات أمنية لمدة أربعة أشهر في حالة أسوأ من خادم يستخدم المنفذ 22 ويثبّت التحديثات تلقائياً كل ليلة. فعِّل التحديثات غير التفاعلية في الجلسة نفسها، ما دمت تعمل بحساب root: يشرح التحديثات التلقائية عبر dnf على Rocky Linux وAlmaLinux المؤقّت والاختيار بين تنزيل التحديثات وتطبيقها.
FAQ
لماذا يفشل sshd في البدء بعد تغيير المنفذ على Rocky Linux؟
السبب في معظم الحالات هو فقدان تسمية منفذ SELinux. يعمل sshd ضمن النطاق sshd_t المقيّد، ولا تسمح السياسة له بالارتباط إلا بالمنافذ التي تحمل التسمية ssh_port_t، وهي المنفذ 22 وحده افتراضياً. يرفض kernel عملية الارتباط، لذلك تتوقف الخدمة بدلاً من الاستماع، ويسجّل journalctl -u sshd سطراً بالصيغة error: Bind to port 2222 on 0.0.0.0 failed: Permission denied.. شغّل sudo semanage port -a -t ssh_port_t -p tcp 2222 مع رقم المنفذ الذي اخترته، ثم أعد تشغيل الخدمة. إذا لم يكن semanage موجوداً، فثبّت policycoreutils-python-utils أولاً.
هل ما زلت أحتاج إلى semanage إذا كان SELinux في وضع permissive؟
نعم. في وضع permissive، يُسجَّل الرفض ويُسمح بعملية الارتباط، لذلك يبدو أن التغيير نجح. لكن التسمية لا تزال مفقودة. وبمجرد تشغيل أي شخص للأمر setenforce 1، أو إقلاع الخادم مع ضبط SELINUX=enforcing على /etc/selinux/config، يتوقف sshd عن البدء على ذلك المنفذ. إضافة التسمية تحتاج إلى أمر واحد وتزيل عطلاً قد يظهر بعد أسابيع من دون سبب واضح.
المنفذ يحمل التسمية وsshd يعمل، فلماذا تنتهي مهلة الاتصال؟
يعني تشغيل الخدمة أن SELinux لا يمنعها، ولذلك تُسقط الحزمة أثناء دخولها. افحص sudo firewall-cmd --list-ports للمنفذ الذي اخترته، وتأكد من تشغيل firewall-cmd --reload بعد قاعدة --permanent، لأن القاعدة الدائمة وحدها لا تُطبَّق على جدار الحماية قيد التشغيل. ثم افحص لوحة التحكم الخاصة بالمضيف بحثاً عن جدار حماية شبكي منفصل أمام VPS. هذه هي النقطة الثانية التي قد تمنع الاتصال، ولن يظهر أي شيء داخل نظام التشغيل ليوضح ذلك.
أي منفذ ينبغي أن أستخدم بدلاً من 22؟
استخدم أي منفذ TCP غير مستخدم من 1024 إلى 65535. تجنّب 2222 و22222 على الخادم الفعلي، لأن أدوات الفحص تحاول الوصول إليهما مباشرة بعد 22. تأكد من أن الرقم غير مستخدم عبر sudo ss -tlnp، وتحقق من أن سياسة SELinux لم تحجزه مسبقاً عبر sudo semanage port -l، وتجنب أي منفذ مخصص لخدمة قد تثبتها لاحقاً. لا مشكلة في استخدام رقم مرتفع يصعب تذكره، لأنك ستكتبه مرة واحدة في ~/.ssh/config ولن تضطر إلى إدخاله مجدداً.