WIUNIX ACADEMY
پورت کانتینر باز مانده، با اینکه UFW فعال است؛ علت و راهحل
بررسی کنید درخواست اینترنتی از چه مسیری به کانتینر میرسد. سپس پورت یک سرویس HTTP موجود را فقط روی خود سرور در دسترس بگذارید و با آزمایش داخلی و بیرونی، نتیجه را بسنجید.
محیطت را انتخاب کنآموزش متناسب با محیط تو
کجا اجرا میکنی؟
سیستمعامل و نسخه را انتخاب کن تا مراحل، دستورها و راهحلها برای همان محیط نمایش داده شوند.
آموزش متناسب با مقادیر تو
تنظیمات این آموزش
مقادیر نمونه را برای محیط خودت تنظیم کن؛ متن و دستورهای مرتبط با هم تغییر میکنند. رمز، کلید خصوصی و توکن وارد نکن. مقادیر فقط در همین زبانه نگهداری میشوند و به سرور یا لینک اشتراکگذاری فرستاده نمیشوند. پیش از اجرا، DNS، گواهیها و سیاست شبکهٔ واقعی را بررسی کن.
آیپی، دامنه یا پورت مثالها با محیط تو فرق دارد؟ دکمهٔ زیر را باز کن، مقادیر را تغییر بده و «اعمال در آموزش» را بزن؛ سپس دستورهای بهروزشده را کپی کن.
تنظیم مقادیر برای محیط من8 مقدار قابلتغییر
از اینجا شروع کن
در پایان چه چیزی خواهی داشت؟
علت دسترسی مستقیم به پورت کانتینر را پیدا کنید، دسترسی اضافه را ببندید و مطمئن شوید مسیر اصلی ورود به اپلیکیشن همچنان سالم است.
سیستمعاملها و نسخههای پوششدادهشده
این راهنما بر پایهٔ مستندات Docker نوشته شده و برای Docker Engine نسخهٔ ۲۸ یا جدیدتر با دسترسی root، شبکهٔ bridge با NAT و پروژهٔ تکفایلی Compose نسخهٔ ۲ است. مسیرهای Ubuntu، Debian و RHEL جداگانه بررسی شدهاند؛ نصب و اجرای عملی روی همهٔ این سیستمها انجام نشده است.
قبل از شروع
- یک سرویس HTTP که هماکنون با Compose تکفایلی روی Docker Engine نسخهٔ ۲۸ یا جدیدتر اجرا میشود؛ Docker باید با دسترسی root کار کند و شبکه از نوع bridge با NAT باشد.
- دسترسی مسئول استقرار، ابزارهای curl، Python 3 و ویرایشگر روی سرور، یک کامپیوتر در شبکهای دیگر و فرصت هماهنگشده برای وقفهٔ کوتاه سرویس.
فعالبودن UFW برای اطمینان از بستهبودن پورت کافی نیست
ممکن است UFW فعال باشد، اما اپلیکیشن داخل کانتینر همچنان از اینترنت پاسخ بدهد. برای پیدا کردن علت، ابتدا نگاشت واقعی پورت را میخوانیم؛ بعد دسترسی یک سرویس موجود را محدود میکنیم و نتیجه را از دو سمت میسنجیم: خود سرور و کامپیوتری در شبکهای دیگر. برای این آزمایش نیازی نیست سرویس تازهای را در اینترنت باز کنید.
Docker توضیح میدهد که ترافیک پورتهای منتشرشده در شبکهٔ bridge ممکن است پیش از رسیدن به قواعد INPUT و OUTPUT مورد استفادهٔ UFW تغییر مسیر بدهد. البته نگاشت عمومی بهتنهایی اثبات نمیکند که پورت از همهجا در دسترس است؛ مسیریابی و فایروال بالادستی هم در نتیجه نقش دارند.
پیش از شروع، نوع استقرار را بررسی کنید
این روش برای یک سرور لینوکسی با Docker Engine نسخهٔ ۲۸ یا جدیدتر و Compose نسخهٔ ۲ نوشته شده است. Docker باید با دسترسی root اجرا شود، شبکهٔ کانتینر bridge با NAT معمول باشد و پروژه فقط یک فایل Compose داشته باشد. باید اجازهٔ بازسازی سرویس موردنظر را در زمان تعیینشده داشته باشید.
اگر استقرار با چند فایل Compose، فایل override، profile یا گزینههای اختصاصی پروژه انجام میشود، تغییر را از همان روال استقرار پیش ببرید. این دستورها برای Swarm، شبکههای host و macvlan/ipvlan، حالت rootless، Docker Desktop یا مسیریابی مستقیم کانتینرها مناسب نیستند. پروکسیای هم که داخل کانتینر دیگری اجرا میشود باید از شبکهٔ خصوصی مشترک به بکاند برسد؛ آدرس لوپبک آن به خود میزبان اشاره نمیکند.
نشست SSH را باز نگه دارید و مطمئن شوید از کنسول هم میتوانید به سرور برگردید. تغییر فقط به نگاشت پورت یک اپلیکیشن مربوط است. محدودکردن پورت به آدرس محلی، جای ورود امن، TLS یا کنترل دسترسی کاربران خود سرور را نمیگیرد.
مقدارهای واقعی را جای نمونهها بگذارید
تنظیمات ابتدای آموزش را باز کنید، آدرس و نام سرویس خودتان را بنویسید و دکمهٔ اعمال را بزنید. رمز، توکن و کلید خصوصی وارد نکنید. مقدارها فقط برای همین آموزش، زبان و سیستمعامل در همین تب مرورگر نگه داشته میشوند و به سرور فرستاده نمیشوند. IP پیشفرض متعلق به محدودهٔ نمونههای مستندات است.
سرویس باید روی پورت داخلی انتخابشده، HTTP بدون TLS ارائه کند. شمارهٔ پورت میزبان و کانتینر را مطابق وضعیت فعلی وارد کنید؛ در این راهنما شمارهٔ آنها را عوض نمیکنیم. پورت تونل SSH جداست و باید روی کامپیوتر خودتان آزاد باشد.
قدم بعدی
نسخهٔ Docker و پروژهٔ درست را پیدا کنید
این دستورها را روی سرور Docker و با حساب مسئول استقرار اجرا کنید. نسخهٔ سرور باید ۲۸ یا جدیدتر باشد و در SecurityOptions نشانهای از rootless نبینید. اگر فایل override یا متغیر اختصاصی Compose وجود دارد، ادامه ندهید تا روش اصلی استقرار مشخص شود.
میزبان Docker
cd '/srv/myapp' || exit 1
sudo docker version --format '{{.Server.Version}}'
sudo docker info --format '{{json .SecurityOptions}}'
sudo docker compose version
test -f compose.yaml || exit 1
find . -maxdepth 1 -type f \( -name '*compose*.yml' -o -name '*compose*.yaml' \) -print
printenv | sort | sed -n '/^COMPOSE_/p'
sudo docker compose -f compose.yaml config --services
sudo docker compose -f compose.yaml ps
پروژه و سرویس درست مشخص شدهاند؛ نسخهٔ Docker و نوع شبکه هم با پیشنیازهای آموزش مطابقت دارند.
قدم بعدی
ببینید کانتینر واقعاً روی کدام آدرسها پورت باز کرده است
روی سرور، فقط اطلاعات لازم را از کانتینر بخوانید. خروجی کامل inspect ممکن است رمز یا توکن موجود در متغیرهای محیطی را نشان بدهد. شبکههای متصل، نوع درایور و گزینههای gateway را هم بررسی کنید؛ مراحل بعدی فقط برای bridge با NAT معمول مناسباند.
میزبان Docker
cd '/srv/myapp' || exit 1
cid=$(sudo docker compose -f compose.yaml ps -q 'web')
test -n "$cid" || exit 1
sudo docker inspect "$cid" --format '{{json .HostConfig.NetworkMode}}'
sudo docker inspect "$cid" --format '{{json .NetworkSettings.Ports}}'
sudo docker port "$cid"
for net in $(sudo docker inspect "$cid" --format '{{range $name, $value := .NetworkSettings.Networks}}{{$name}} {{end}}'); do
sudo docker network inspect "$net" --format '{{.Name}} {{.Driver}} {{json .Options}}'
done
sudo ufw status verbose
80/tcp -> 0.0.0.0:8080
80/tcp -> [::]:8080آدرس و پورتهای فعلی را ثبت کردهاید. خروجی نمونه، نگاشت روی همهٔ آدرسهای IPv4 و IPv6 را نشان میدهد؛ دسترسی اینترنتی را باید در مرحلهٔ بعد جداگانه آزمایش کنید.
قدم بعدی
ابتدا مطمئن شوید اپلیکیشن روی خود سرور پاسخ میدهد
روی خود سرور، یک درخواست بدون رمز یا توکن بفرستید. هر کد HTTP، حتی ۴۰۱ یا ۴۰۳، نشان میدهد سرویسی پاسخ داده است. در این بررسی از HTTP بدون TLS استفاده میکنیم؛ بنابراین اطلاعات ورود اپلیکیشن را همراه درخواست نفرستید.
میزبان Docker
curl --noproxy '*' --connect-timeout 3 --max-time 5 -sS -o /dev/null -w 'HTTP %{http_code}\n' 'http://127.0.0.1:8080/'اپلیکیشن روی خود سرور پاسخ HTTP میدهد. اگر اتصال برقرار نمیشود، پیش از تغییر پورت، مشکل اپلیکیشن را برطرف کنید.