ورود به پنل ثبت‌ نام

امن‌سازی سرور لینوکس با کلید SSH، فایروال UFW و Fail2ban

راهنمای عملی امن‌سازی سرور لینوکس؛ ورود با کلید SSH، بستن ورود روت، فایروال UFW، مسدودسازی حمله‌های brute-force با Fail2ban و به‌روزرسانی خودکار امنیتی.

تیم ابر سپهر 13 دقیقه مطالعه
امن‌سازی سرور لینوکس با کلید SSH، فایروال UFW و Fail2ban
در این مقاله

هر سروری که یک آی‌پی عمومی داشته باشد، از همان دقیقه‌ی اول هدف اسکن‌های خودکار قرار می‌گیرد. اگر لاگ یک سرور تازه‌نصب را بعد از چند ساعت ببینید، ده‌ها تلاش ناموفق ورود با نام‌های root، admin و ubuntu در آن پیدا می‌کنید. این ربات‌ها شما را نمی‌شناسند؛ کل فضای آی‌پی را جارو می‌کنند و دنبال سروری می‌گردند که رمز ساده یا سرویس فراموش‌شده داشته باشد. امن‌سازی سرور لینوکس یعنی بستن همین درهای ساده، پیش از آن‌که کسی آن‌ها را امتحان کند.

خبر خوب این است که بخش بزرگی از این کار با پنج تصمیم انجام می‌شود و بیش از نیم‌ساعت وقت نمی‌گیرد: ورود فقط با کلید، بستن ورود مستقیم روت، فایروالی که به‌صورت پیش‌فرض همه‌چیز را می‌بندد، ابزاری که آی‌پی‌های مهاجم را موقتاً بلاک می‌کند و به‌روزرسانی خودکار وصله‌های امنیتی. هیچ‌کدام از این‌ها به دانش تخصصی امنیت نیاز ندارند.

در این راهنما همه‌ی این مراحل را روی Ubuntu 24.04/26.04 و Debian 13 انجام می‌دهیم. دستورها با کاربر root اجرا می‌شوند؛ اگر با کاربر عادی کار می‌کنید، پیش از هر دستور sudo بگذارید.

پیش‌نیازها

  • یک سرور ابری با Ubuntu 24.04/26.04 یا Debian 13 و دسترسی root.
  • یک جفت کلید SSH روی کامپیوتر خودتان (در گام ۲ می‌سازیم).
  • یک ترمینال دوم که همین حالا به سرور وصل باشد. تمام تغییرهای این مقاله روی دسترسی SSH و فایروال اثر می‌گذارند؛ داشتن یک نشست باز و سالم، تفاوت میان «اشتباه کردم و برگشتم» و «از سرور خودم بیرون ماندم» است.
  • دسترسی به کنسول تحت وب کنترل پنل ابر سپهر به‌عنوان راه نجات، اگر با وجود همه‌ی احتیاط‌ها SSH قطع شد.

گام ۱: به‌روزرسانی سیستم و ساخت کاربر غیرروت

اول از همه بسته‌ها را به‌روز می‌کنیم. بسیاری از رخنه‌ها نه از راه پیکربندی اشتباه، که از راه یک بسته‌ی وصله‌نشده اتفاق می‌افتند:

apt update && apt upgrade -y

سپس یک کاربر عادی می‌سازیم و او را عضو گروه sudo می‌کنیم:

adduser deploy
usermod -aG sudo deploy

adduser رمز و چند اطلاعات اختیاری می‌پرسد و خودش پوشه‌ی خانگی و شل را تنظیم می‌کند. دلیل این کار فقط «رعایت اصول» نیست: وقتی ورود مستقیم روت بسته باشد، مهاجم باید هم نام کاربری درست را حدس بزند و هم کلید داشته باشد. ضمناً هر دستور حساس با sudo در لاگ ثبت می‌شود و می‌دانید چه کسی چه کاری کرده است.

گام ۲: ورود با کلید SSH به‌جای رمز عبور

روی کامپیوتر خودتان (نه سرور) یک کلید ed25519 بسازید:

ssh-keygen -t ed25519 -C "deploy@my-laptop"

ed25519 نسبت به RSA کوتاه‌تر، سریع‌تر و امن‌تر است و همه‌ی نسخه‌های امروزی OpenSSH از آن پشتیبانی می‌کنند. وقتی پرسید passphrase بگذارید یا نه، بگذارید؛ اگر کسی به لپ‌تاپ شما دسترسی پیدا کند، کلید بدون passphrase یعنی دسترسی مستقیم به سرور.

حالا کلید عمومی را روی سرور بگذارید:

ssh-copy-id deploy@SERVER_IP

اگر ssh-copy-id در دسترس نیست، همان کار را دستی انجام دهید:

ssh deploy@SERVER_IP "mkdir -p ~/.ssh && chmod 700 ~/.ssh"
cat ~/.ssh/id_ed25519.pub | ssh deploy@SERVER_IP "cat >> ~/.ssh/authorized_keys"
ssh deploy@SERVER_IP "chmod 600 ~/.ssh/authorized_keys"

دسترسی‌های 700 و 600 اختیاری نیستند؛ اگر پوشه یا فایل برای دیگران قابل نوشتن باشد، خودِ OpenSSH به‌دلایل امنیتی کلید را نادیده می‌گیرد و شما بدون هیچ پیام روشنی دوباره سراغ رمز فرستاده می‌شوید.

پیش از رفتن به گام بعد، در یک ترمینال جدید ورود با کلید را امتحان کنید:

ssh deploy@SERVER_IP

اگر بدون پرسیدن رمز وارد شدید، کار درست انجام شده است.

گام ۳: سخت‌کردن پیکربندی SSH

روی توزیع‌های امروزی، فایل /etc/ssh/sshd_config در ابتدای خود یک Include دارد که فایل‌های داخل /etc/ssh/sshd_config.d/ را می‌خواند. بهترین کار این است که فایل اصلی را دست‌نخورده بگذاریم و تنظیم‌های خودمان را در یک فایل جدا بنویسیم:

nano /etc/ssh/sshd_config.d/10-hardening.conf

با این محتوا:

PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
X11Forwarding no
AllowUsers deploy

چند نکته که ترتیب اهمیتشان از بالا به پایین است:

  • PasswordAuthentication no مهم‌ترین خط این مقاله است. با بستن ورود با رمز، حمله‌ی brute-force عملاً بی‌معنا می‌شود؛ مهاجم چیزی برای حدس‌زدن ندارد.
  • PermitRootLogin no ورود مستقیم روت را می‌بندد. از این پس با deploy وارد می‌شوید و با sudo کارهای مدیریتی را انجام می‌دهید.
  • AllowUsers deploy فهرست سفید کاربران مجاز است. اگر بعداً کاربر دیگری ساختید و یادتان رفت اینجا اضافه کنید، آن کاربر نمی‌تواند وارد شود.
  • KbdInteractiveAuthentication no راه دور دیگری برای ورود با رمز را می‌بندد؛ بدون آن، بستن PasswordAuthentication روی برخی پیکربندی‌ها کامل نیست.

نکته‌ی ظریفی که خیلی‌ها را گرفتار می‌کند: در OpenSSH اولین مقداری که برای یک گزینه خوانده شود برنده است، نه آخرین. فایل‌های sshd_config.d/ هم به ترتیب حروف الفبا خوانده می‌شوند. ایمیج‌های ابری معمولاً فایلی مثل 50-cloud-init.conf دارند که در آن PasswordAuthentication yes نوشته شده است؛ اگر نام فایل شما 99-… باشد، دیرتر خوانده می‌شود و تنظیم‌تان بی‌اثر می‌ماند. به همین دلیل نام 10-hardening.conf را انتخاب کردیم.

به‌جای حدس‌زدن، پیکربندی نهایی و تفسیرشده را از خود sshd بپرسید:

sshd -t
sshd -T | grep -E "^(permitrootlogin|passwordauthentication|pubkeyauthentication)"

sshd -t خطای نگارشی را پیش از راه‌اندازی مجدد پیدا می‌کند و sshd -T مقدار واقعی و مؤثر هر گزینه را چاپ می‌کند. اگر خروجی passwordauthentication no بود، تنظیم شما برنده شده است. حالا سرویس را دوباره راه‌اندازی کنید:

systemctl restart ssh

ترمینال فعلی خود را نبندید. یک ترمینال جدید باز کنید و ورود را امتحان کنید. تا وقتی از نشست تازه مطمئن نشده‌اید، نشست قدیمی تنها راه بازگشت شماست. اگر هر دو بسته شد، از کنسول تحت وب کنترل پنل ابر سپهر وارد سرور شوید و فایل را اصلاح کنید.

گام ۴: فایروال UFW با سیاست پیش‌فرضِ بستن

فایروال درست، فایروالی است که به‌صورت پیش‌فرض همه‌چیز را می‌بندد و فقط چیزی را که لازم دارید باز می‌کند:

apt install -y ufw
ufw default deny incoming
ufw default allow outgoing
ufw allow OpenSSH

دو خط default قلب ماجرا هستند: ترافیک ورودی جز مواردی که صریحاً اجازه داده‌اید مسدود می‌شود، ولی سرور همچنان می‌تواند به بیرون وصل شود (برای apt، DNS و به‌روزرسانی). ufw allow OpenSSH هم یک پروفایل آماده است که پورت ۲۲ را باز می‌کند.

اگر روی سرور وب‌سرور دارید، پورت‌های آن را هم باز کنید:

ufw allow 'Nginx Full'

و در پایان فایروال را فعال کنید:

ufw enable
ufw status verbose

ufw enable را هرگز پیش از افزودن قاعده‌ی OpenSSH اجرا نکنید. این تنها اشتباهی است که در همان لحظه شما را از سرور بیرون می‌اندازد و تنها راه بازگشت، کنسول تحت وب پنل است.

اگر سرویسی مثل پایگاه داده دارید که فقط باید از یک آی‌پی مشخص در دسترس باشد، به‌جای باز کردن پورت برای همه، آن را محدود کنید:

ufw allow from 203.0.113.10 to any port 5432 proto tcp

این الگو برای اتصال امن به پایگاه داده از بیرون هم به‌کار می‌آید؛ جزئیات بیشتر در راهنمای نصب PostgreSQL روی اوبونتو آمده است.

چرا فایروال به‌تنهایی جلوی کانتینرهای داکر را نمی‌گیرد؟

اگر روی سرور داکر دارید، بدانید که داکر قواعد خودش را مستقیم در iptables می‌نویسد و پورت‌هایی که با -p 8080:8080 منتشر می‌کنید از کنار UFW رد می‌شوند؛ یعنی با وجود deny incoming از اینترنت در دسترس‌اند. راه‌حل ساده این است که کانتینرها را فقط روی لوکال‌هاست منتشر کنید:

docker run -d -p 127.0.0.1:8080:8080 ...

و دسترسی بیرونی را از مسیر پراکسی معکوس بدهید. همین الگو در راهنمای نصب داکر روی اوبونتو هم توضیح داده شده است.

گام ۵: مسدودسازی حمله‌های brute-force با Fail2ban

Fail2ban لاگ‌ها را می‌خواند و آی‌پی‌هایی را که پشت‌سرهم شکست می‌خورند، برای مدتی بلاک می‌کند:

apt install -y fail2ban python3-systemd

بسته‌ی python3-systemd برای خواندن لاگ از journald لازم است. روی Debian 13 و نصب‌های کم‌حجم اوبونتو، فایل /var/log/auth.log لزوماً وجود ندارد و لاگ‌ها فقط در ژورنال systemd هستند؛ اگر این نکته را نادیده بگیرید، Fail2ban بالا می‌آید ولی هیچ‌وقت چیزی پیدا نمی‌کند.

فایل پیکربندی محلی را بسازید (فایل‌های jail.conf با هر به‌روزرسانی بازنویسی می‌شوند، پس هرگز آن‌ها را ویرایش نکنید):

nano /etc/fail2ban/jail.local

با محتوای زیر:

[DEFAULT]
backend = systemd
bantime = 1h
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 ::1

[sshd]
enabled = true

معنی این اعداد ساده است: اگر یک آی‌پی در بازه‌ی ۱۰ دقیقه (findtime) پنج بار (maxretry) شکست بخورد، یک ساعت (bantime) بلاک می‌شود. در ignoreip می‌توانید آی‌پی ثابت دفتر خودتان را هم اضافه کنید تا در اثر یک اشتباه، خودتان بلاک نشوید.

سرویس را فعال و وضعیت را بررسی کنید:

systemctl enable --now fail2ban
fail2ban-client status sshd

خروجی این دستور تعداد تلاش‌های ناموفق و فهرست آی‌پی‌های بلاک‌شده را نشان می‌دهد. اگر آی‌پی‌ای را اشتباهی بلاک کردید:

fail2ban-client set sshd unbanip 203.0.113.10

شاید بپرسید وقتی ورود با رمز بسته است، Fail2ban چه فایده‌ای دارد. دو فایده: حجم تلاش‌های بی‌فایده و مصرف منابع را کم می‌کند و لاگ‌ها را تمیز نگه می‌دارد، به‌طوری که وقتی اتفاق غیرعادی افتاد، آن را میان هزاران خط نویز گم نمی‌کنید.

گام ۶: به‌روزرسانی خودکار وصله‌های امنیتی

بیشتر سرورهایی که هک می‌شوند، با یک آسیب‌پذیری شناخته‌شده و وصله‌شده هک می‌شوند که کسی وصله را نصب نکرده است. این کار را به سیستم بسپارید:

apt install -y unattended-upgrades
dpkg-reconfigure -plow unattended-upgrades

دستور دوم فایل /etc/apt/apt.conf.d/20auto-upgrades را می‌سازد و به‌روزرسانی روزانه را فعال می‌کند. برای اطمینان از این‌که همه‌چیز درست کار می‌کند، یک اجرای آزمایشی بگیرید:

unattended-upgrade --dry-run --debug

به‌صورت پیش‌فرض فقط بسته‌های مخزن امنیتی نصب می‌شوند، یعنی احتمال شکستن سرویس‌های شما بسیار کم است. اگر می‌خواهید سرور پس از به‌روزرسانی‌هایی که نیاز به ریبوت دارند خودش ریبوت شود، در فایل /etc/apt/apt.conf.d/50unattended-upgrades این دو خط را از حالت کامنت خارج و تنظیم کنید:

Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "04:00";

ریبوت خودکار برای سرورهای وب معمولاً پذیرفتنی است، اما اگر روی سرور سرویس حساس یا پایگاه داده‌ی بزرگ دارید، بهتر است ریبوت را دستی و در زمان مناسب انجام دهید.

گام ۷ (اختیاری): تغییر پورت SSH

تغییر پورت SSH امنیت واقعی اضافه نمی‌کند اما حجم نویز لاگ را به‌شدت کم می‌کند. روی Ubuntu 24.04 و Debian 13 نکته‌ای هست که خیلی‌ها را سردرگم می‌کند: SSH با socket activation بالا می‌آید و در این حالت دستور Port در sshd_config نادیده گرفته می‌شود. پورت را باید در خود سوکت عوض کنید:

systemctl edit ssh.socket

و در بخش ویرایش‌پذیر این را بنویسید:

[Socket]
ListenStream=
ListenStream=2222

خط خالی ListenStream= مقدار پیش‌فرض (پورت ۲۲) را پاک می‌کند؛ بدون آن، سرویس روی هر دو پورت گوش می‌دهد. سپس پورت جدید را در فایروال باز و سرویس را راه‌اندازی کنید:

ufw allow 2222/tcp
systemctl daemon-reload
systemctl restart ssh.socket

پیش از بستن پورت ۲۲ (ufw delete allow OpenSSH) حتماً ورود روی پورت جدید را با ssh -p 2222 deploy@SERVER_IP امتحان کنید.

نگهداری: به‌روزرسانی و بک‌آپ

امن‌سازی یک کار یک‌باره نیست؛ چند دقیقه بازبینی در ماه، بیشتر از هر ابزار گران‌قیمتی ارزش دارد. سه عادت ساده کافی است: سرکشی به لاگ ورودها، بررسی قواعد فایروال بعد از هر تغییر، و گرفتن اسنپ‌شات از کنترل پنل ابر سپهر پیش از هر تغییر پرخطر.

برای دیدن ورودهای اخیر و تلاش‌های ناموفق:

journalctl -u ssh --since "24 hours ago" | grep -Ei "accepted|failed"
last -n 20

journalctl تصویر دقیقی از تلاش‌های ورود می‌دهد و last فهرست آخرین ورودهای موفق را نشان می‌دهد. اگر ورودی موفق از آی‌پی ناآشنا دیدید، آن را جدی بگیرید.

کار دستور چه زمانی
بررسی تنظیم مؤثر SSH sshd -T | grep passwordauthentication پس از هر تغییر پیکربندی
وضعیت فایروال ufw status verbose پس از افزودن هر سرویس
آی‌پی‌های بلاک‌شده fail2ban-client status sshd هفتگی
بسته‌های قابل ارتقا apt list --upgradable ماهانه
بررسی ورودهای اخیر journalctl -u ssh --since "24 hours ago" هنگام مشاهده رفتار مشکوک
بک‌آپ کامل اسنپ‌شات کنترل پنل پیش از هر تغییر پرخطر

فراموش نکنید که فایروال و Fail2ban جای بک‌آپ را نمی‌گیرند. اگر هنوز برنامه‌ی مشخصی برای بک‌آپ ندارید، راهنمای بک‌آپ خودکار سرور با Restic مکمل مستقیم همین مقاله است.

جمع‌بندی

امن‌سازی سرور لینوکس با همین شش گام، سرور شما را از دسترس ۹۹ درصد حمله‌های خودکار خارج می‌کند: کاربر غیرروت، ورود فقط با کلید SSH، فایروال با سیاست پیش‌فرضِ بستن، Fail2ban و به‌روزرسانی خودکار امنیتی.

سه تصمیمی که بیشترین تفاوت را می‌سازند: بستن PasswordAuthentication، اطمینان از مؤثر بودن آن با sshd -T (نه فقط نوشتنش در فایل) و منتشر نکردن پورت کانتینرها روی اینترنت. بقیه‌ی موارد لایه‌های بعدی دفاع‌اند.

اگر می‌خواهید همین پیکربندی را روی یک سرور تازه پیاده کنید، از صفحه خرید سرور ابری شروع کنید؛ کنسول تحت وب و اسنپ‌شات، دو ابزاری هستند که هنگام آزمون‌وخطا با فایروال و SSH بیشترین کاربرد را دارند.

مقالات مرتبط