WIUNIX ACADEMY
پورت کانتینر باز مانده، با اینکه UFW فعال است؛ علت و راهحل
صفحهٔ 3 از 3؛ مراحل قبلی و پیشنیازها را پیش از ادامه مرور کن.
آموزش متناسب با محیط تو
کجا اجرا میکنی؟
سیستمعامل و نسخه را انتخاب کن تا مراحل، دستورها و راهحلها برای همان محیط نمایش داده شوند.
آموزش متناسب با مقادیر تو
تنظیمات این آموزش
مقادیر نمونه را برای محیط خودت تنظیم کن؛ متن و دستورهای مرتبط با هم تغییر میکنند. رمز، کلید خصوصی و توکن وارد نکن. مقادیر فقط در همین زبانه نگهداری میشوند و به سرور یا لینک اشتراکگذاری فرستاده نمیشوند. پیش از اجرا، DNS، گواهیها و سیاست شبکهٔ واقعی را بررسی کن.
آیپی، دامنه یا پورت مثالها با محیط تو فرق دارد؟ دکمهٔ زیر را باز کن، مقادیر را تغییر بده و «اعمال در آموزش» را بزن؛ سپس دستورهای بهروزشده را کپی کن.
تنظیم مقادیر برای محیط من8 مقدار قابلتغییر
قدم بعدی
همان آزمایش بیرونی را دوباره انجام دهید
از همان کامپیوتر و شبکهٔ مرحلهٔ قبل درخواست بفرستید. دسترسی مستقیم IPv4 باید قطع شده باشد، در حالی که درخواست روی خود سرور همچنان پاسخ میگیرد. دریافت ۴۰۱ یا ۴۰۳ به معنی بستهشدن پورت نیست. اگر سرور IPv6 عمومی دارد، هر آدرس را جداگانه بررسی کنید؛ نتیجهٔ IPv4 دربارهٔ IPv6 چیزی ثابت نمیکند.
فقط با دیدن timeout کار را تمامشده ندانید. نگاشت واقعی Docker، پاسخ محلی، مسیر اصلی پروکسی و آزمایش بیرونی باید نتیجهای سازگار بدهند. سرویس دیگری روی میزبان، نمونهٔ اضافهٔ اپلیکیشن یا مسیر مستقیم به شبکهٔ کانتینر ممکن است خارج از محدودهٔ این مثال همچنان باز باشد.
IPv6 عمومی را هنگام درخواست ترمینال، بدون کروشه وارد کنید. اگر ندارید Enter بزنید و اگر چند آدرس دارید، آزمایش را برای هرکدام تکرار کنید. این مقدار در ترمینال میماند و در مرورگر ذخیره نمیشود.
کامپیوتر مستقل
curl --noproxy '*' --connect-timeout 3 --max-time 5 -sS -o /dev/null -w 'HTTP %{http_code}\n' 'http://203.0.113.10:8080/'
printf "IPv6 عمومی، بدون کروشه؛ اگر ندارید Enter بزنید: "
IFS= read -r public_ipv6
if [ -n "$public_ipv6" ]; then
curl --noproxy '*' --connect-timeout 3 --max-time 5 -sS -o /dev/null -w 'HTTP %{http_code}\n' "http://[$public_ipv6]:8080/"
fi
اتصال مستقیم بیرونی دیگر پاسخ HTTP نمیگیرد، اما دسترسی محلی و مسیر اصلی امن سالماند. اگر IPv6 دارید، نتیجهٔ آن هم جدا ثبت شده است.
قدم بعدی
در صورت نیاز، از تونل SSH به بکاند محلی وصل شوید
روی کامپیوتر خودتان و با حساب SSH مجاز فعلی، تونل را فقط روی آدرس محلی باز کنید. کلید میزبان را طبق روال معمول بررسی کنید و اعتبارسنجی آن را غیرفعال نکنید. تا وقتی به تونل نیاز دارید این ترمینال باید باز بماند. کاربران دیگر همان کامپیوتر هم ممکن است به پورت محلی دسترسی داشته باشند؛ تونل جای احراز هویت اپلیکیشن را نمیگیرد.
کامپیوتر مستقل
ssh -N -o ExitOnForwardFailure=yes -L '127.0.0.1:18080:127.0.0.1:8080' -p '22' 'admin@203.0.113.10'نشست SSH باز مانده و تونل فقط روی آدرس محلی گوش میدهد. اگر پورت اشغال باشد، خطا نمایش داده میشود.
قدم بعدی
از ترمینال دوم، مسیر تونل را امتحان کنید
در حالی که نشست SSH باز است، در ترمینال دیگری روی همان کامپیوتر درخواست بفرستید. پس از پایان کار، نشست تونل را با Ctrl+C ببندید. اگر درخواست جواب نمیگیرد، علت را در تونل پیدا کنید؛ برای رفع اشکال، بکاند را دوباره در اینترنت باز نکنید.
کامپیوتر مستقل
curl --noproxy '*' --connect-timeout 3 --max-time 5 -sS -o /dev/null -w 'HTTP %{http_code}\n' 'http://127.0.0.1:18080/'درخواست از تونل به همان بکاند میرسد. این آزمایش بهتنهایی درستی تنظیمات Host یا Origin اپلیکیشن را تأیید نمیکند.
قدم بعدی
اگر نتیجهها جور درنمیآیند، نگاشت و مسیر را دوباره بررسی کنید
باقیماندن نگاشت عمومی ممکن است به انتخاب پروژه یا کانتینر اشتباه، یا انتشار پورت اضافه مربوط باشد. اگر بکاند سالم است ولی پروکسی کانتینری به آن نمیرسد، اتصال شبکهٔ بین آنها را بررسی کنید. در حالت شبکهٔ host یا مسیریابی مستقیم، خالیبودن فهرست پورت به معنی جداشدن کانتینر از شبکه نیست.
خروجی خالی ss هم بهتنهایی کافی نیست؛ انتشار پورت با NAT همیشه به صورت یک پردازش در حال گوشدادن دیده نمیشود. اطلاعات واقعی Docker را هم بخوانید. مدیریت فایروال Docker را خاموش نکنید و قواعد DOCKER-USER مخصوص iptables را بدون بررسی روی بکاند nftables به کار نبرید؛ روش کنترل ترافیک در این دو یکسان نیست.
میزبان Docker
cd '/srv/myapp' || exit 1
sudo docker compose -f compose.yaml ps
sudo docker ps --format 'table {{.Names}}\t{{.Ports}}'
sudo ss -lntp
cid=$(sudo docker compose -f compose.yaml ps -q 'web')
test -n "$cid" || exit 1
sudo docker inspect "$cid" --format '{{json .HostConfig.PortBindings}}'
علت اختلاف نتیجهها را پیش از تغییر بعدی پیدا کردهاید. خروجی کامل لاگ یا تنظیمات حاوی اطلاعات ورود را در اختیار دیگران نگذارید.
قدم بعدی
اگر سرویس درست کار نمیکند، دسترسی ناخواسته را دوباره باز نکنید
اگر مشکل اپلیکیشن در فرصت نگهداری حل نشد، میتوانید فقط همان سرویس را متوقف کنید تا وضعیت ناامن ادامه پیدا نکند. دستور زیر اختیاری است و باعث قطعی همان سرویس میشود. سپس نگاشت خصوصی را اصلاح کنید، سرویس را از روال اصلی استقرار برگردانید و آزمایش محلی و بیرونی را تکرار کنید.
نسخهٔ قبلی Compose برای برگرداندن تنظیمات در دسترس است، اما بازگرداندن نگاشت عمومی قبلی ممکن است مشکل امنیتی را هم برگرداند. چنین تصمیمی باید با آگاهی مسئول سرویس گرفته شود. برای بازیابی، دادههای ماندگار را حذف نکنید و فایروال میزبان را از نو تنظیم نکنید.
میزبان Docker
cd '/srv/myapp' || exit 1
sudo docker compose -f compose.yaml stop 'web'اگر توقف را انتخاب کردهاید، فقط همان سرویس متوقف شده و دادههای ماندگار حفظ شدهاند. پیش از پایان بازیابی، سلامت دسترسی محلی و مسیر مجاز را تأیید کنید.
چه نتیجهای را باید ثبت کنید؟
نسخهٔ Docker، نام پروژه و سرویس، نگاشت پیش و پس از تغییر، پاسخ محلی و نتیجهٔ اتصال بیرونی را ثبت کنید. IPv4 و IPv6 را جداگانه بنویسید و سالمبودن مسیر اصلی ورود به اپلیکیشن را هم تأیید کنید. بعد از تغییرهای مرتبط با شبکه و پورت در استقرارهای بعدی، این بررسی را تکرار کنید.
منابع رسمی این راهنما در ۲۸ اکتبر ۲۰۲۶ بازبینی شدهاند. فرمانها هنگام نگارش روی سرویس عملیاتی اجرا نشدهاند. نتیجهٔ این بررسی به همین سرویس و مسیرهای آزمایششده مربوط است و جای ارزیابی امنیت کل استقرار را نمیگیرد.
پشتوانهٔ این آموزش
منابع رسمی
وضعیت بررسی هر محیط بالای صفحه مشخص است؛ بررسی مستندات به معنی اجرای عملی همهٔ نسخهها نیست.
- ارتباط Docker با فایروال و UFW
- انتشار پورت و محدودیتهای آدرس محلی در Docker
- مشاهدهٔ نگاشت پورتهای کانتینر
- نحوهٔ نوشتن ports در Compose
- بررسی تنظیم نهایی Compose
- رفتار Compose هنگام بازسازی سرویس
- فیلتر ترافیک Docker با iptables
- بکاند nftables در Docker
- نصب و پیشنیازهای Docker Engine روی RHEL
- zoneها و سیاستهای firewalld در مستندات Red Hat
ادامهٔ مسیر