WIUNIX ACADEMY
پورت کانتینر باز مانده، با اینکه UFW فعال است؛ علت و راهحل
صفحهٔ 2 از 3؛ مراحل قبلی و پیشنیازها را پیش از ادامه مرور کن.
آموزش متناسب با محیط تو
کجا اجرا میکنی؟
سیستمعامل و نسخه را انتخاب کن تا مراحل، دستورها و راهحلها برای همان محیط نمایش داده شوند.
آموزش متناسب با مقادیر تو
تنظیمات این آموزش
مقادیر نمونه را برای محیط خودت تنظیم کن؛ متن و دستورهای مرتبط با هم تغییر میکنند. رمز، کلید خصوصی و توکن وارد نکن. مقادیر فقط در همین زبانه نگهداری میشوند و به سرور یا لینک اشتراکگذاری فرستاده نمیشوند. پیش از اجرا، DNS، گواهیها و سیاست شبکهٔ واقعی را بررسی کن.
آیپی، دامنه یا پورت مثالها با محیط تو فرق دارد؟ دکمهٔ زیر را باز کن، مقادیر را تغییر بده و «اعمال در آموزش» را بزن؛ سپس دستورهای بهروزشده را کپی کن.
تنظیم مقادیر برای محیط من8 مقدار قابلتغییر
قدم بعدی
دسترسی اینترنتی را از شبکهای دیگر امتحان کنید
این دستورها را روی کامپیوتری جدا، بیرون از شبکهٔ سرور و کانتینرها اجرا کنید و فقط آدرس عمومی تحت اختیار خودتان را هدف بگیرید. اگر از خود سرور به IP عمومی همان سرور درخواست بفرستید، آزمایش بیرونی انجام ندادهاید.
پاسخ HTTP نشان میدهد سرویس از شبکهٔ فعلی شما در دسترس است. تمامشدن زمان انتظار ممکن است به فایروال بالادستی مربوط باشد؛ از آن نمیتوان نتیجه گرفت UFW ترافیک Docker را بسته است. زمان آزمایش، شبکهٔ مبدأ، مقصد و نتیجه را برای خودتان ثبت کنید.
ترمینال آدرس واقعی IPv6 عمومی را بدون کروشه میپرسد. اگر سرور 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
مشخص است اتصال از شبکهٔ آزمایش پاسخ گرفته، رد شده یا به پایان زمان انتظار رسیده است؛ مبدأ و مقصد هم ثبت شدهاند.
آیا این پورت اصلاً باید از بیرون باز باشد؟
اگر پروکسی معکوس روی خود سرور اجرا میشود، میتواند از آدرس محلی به بکاند وصل شود. اگر مصرفکننده کانتینر دیگری است، معمولاً باید نام سرویس و شبکهٔ خصوصی مشترک Docker را به کار ببرید و انتشار غیرضروری روی میزبان را حذف کنید. برای اپلیکیشن عمومی هم باید ورودی عمومیِ مشخص و کنترلشدهای در نظر گرفته باشید.
تغییر بعدی فقط برای بکاندی است که قرار است از خود میزبان در دسترس باشد. ابتدا تأیید کنید کاربران بیرونی نباید مستقیم به آن وصل شوند و پروکسی موجود هم از همین پورت محلی استفاده میکند. این تغییر را روی API عمومی یا پایگاهدادهای که کلاینت راه دور دارد، بدون بررسی معماری اعمال نکنید.
قدم بعدی
از فایل فعلی نسخه بگیرید، بعد فقط نگاشت پورت را تغییر دهید
در زمان هماهنگشدهٔ نگهداری، نسخهای خصوصی از فایل فعلی نگه دارید و همان فایل اصلی را باز کنید. اگر فایل پشتیبان از قبل وجود دارد، توقف کنید تا روی آن نوشته نشود. فقط فهرست ports سرویس انتخابشده را به یک نگاشت صریح روی آدرس لوپبک تغییر دهید. ایمیج، دادههای متصل، متغیرهای محیطی و سرویسهای دیگر باید دستنخورده بمانند. نمونهٔ YAML بعدی فقط بخشی از سرویس موجود است و نباید جای کل فایل قرار بگیرد.
میزبان Docker
cd '/srv/myapp' || exit 1
test ! -e compose.yaml.before-loopback || exit 1
(umask 077; cp --no-preserve=mode -- compose.yaml compose.yaml.before-loopback)
nano compose.yamlنسخهٔ قبلی فایل بهصورت خصوصی حفظ شده و فقط فهرست ports سرویس موردنظر تغییر کرده است.
نگاشت پورت سرویس را به آدرس محلی محدود کنید
شمارهٔ پورت میزبان و پورت داخل کانتینر را تغییر ندهید. آدرس لوپبک باید صریح باشد و نباید کنار آن، نگاشت عمومی یا IPv6 اضافه باقی بماند. در پروژههای چندفایلی ممکن است فهرست پورتها با فایل override ادغام شود؛ به همین دلیل این مثال فقط برای پروژهٔ تکفایلی است.
میزبان Docker
services:
web:
# ایمیج، دادههای متصل و تنظیمات دیگر سرویس را نگه دارید.
ports:
- "127.0.0.1:8080:80"
قدم بعدی
پیش از بازسازی، تنظیم نهایی Compose را بررسی کنید
روی سرور، ابتدا اعتبار فایل را بسنجید و بعد فقط فهرست پورت سرویس انتخابشده را ببینید. در خروجی باید یک نگاشت با host_ip محلی وجود داشته باشد. اگر آدرس عمومی یا پورت اضافه میبینید، هنوز کانتینر را بازسازی نکنید؛ اول فایل را اصلاح کنید. این روش از چاپ کامل تنظیمات و افشای ناخواستهٔ اطلاعات ورود جلوگیری میکند.
میزبان Docker
cd '/srv/myapp' || exit 1
sudo docker compose -f compose.yaml config --quiet || exit 1
sudo docker compose -f compose.yaml config --format json | python3 -c 'import json,sys; d=json.load(sys.stdin); print(json.dumps(d["services"]["web"].get("ports", []), indent=2))'
تنظیم نهایی فقط یک نگاشت روی آدرس محلی دارد و نگاشت عمومی یا پورت اضافهای در آن نیست.
قدم بعدی
تغییر را با بازسازی همان یک سرویس اعمال کنید
این مرحله برای سرویس انتخابشده وقفهٔ کوتاهی ایجاد میکند. کانتینر را با ایمیج فعلی و بدون راهاندازی دوبارهٔ سرویسهای وابسته بسازید. restart ساده نگاشت پورت را عوض نمیکند. اگر اپلیکیشن به مهاجرت داده یا استقرار هماهنگ نیاز دارد، تغییر را از روال خود آن انجام دهید.
بعد از بازسازی، نگاشت واقعی را دوباره بخوانید و پاسخ محلی اپلیکیشن را بررسی کنید. دادههای ماندگار و هویت پروژه باید حفظ شوند. این دستور از دادههای اپلیکیشن نسخهٔ پشتیبان تهیه نمیکند.
میزبان Docker
cd '/srv/myapp' || exit 1
sudo docker compose -f compose.yaml up -d --no-deps --force-recreate --pull never --no-build 'web' || exit 1
cid=$(sudo docker compose -f compose.yaml ps -q 'web')
test -n "$cid" || exit 1
sudo docker port "$cid"
sudo docker inspect "$cid" --format '{{json .NetworkSettings.Ports}}'
curl --noproxy '*' --connect-timeout 3 --max-time 5 -sS -o /dev/null -w 'HTTP %{http_code}\n' 'http://127.0.0.1:8080/'
پورت فقط روی آدرس محلی منتشر شده و اپلیکیشن پاسخ میدهد. مسیر واقعی پروکسی و کلاینت مجاز را هم بررسی کردهاید.