
به اشتراک بگذارید

به اشتراک بگذارید
خطای 403 هنگام docker pull روی سرور ایران، نتیجه تحریم داکر است: Docker Hub درخواست IP ایران را رد میکند و ایمیج دانلود نمیشود. راه پایدار، معرفی یک میرور داخلی Docker Hub در فایل /etc/docker/daemon.json، سنجیدن ایمیج با digest رسمی و نگهداشتن نسخه آفلاین ایمیجهای حیاتی است.
| نشانه روی سرور | علت | راهحل کوتاه |
|---|---|---|
| پیام pull access denied همراه با 403 Forbidden | مسدود بودن IP ایران در Docker Hub | تنظیم registry-mirrors در daemon.json |
| پیام toomanyrequests با کد 429 | تمام شدن سهمیه pull در بازه ۶ ساعته | صبر، ورود به حساب یا رجیستری خصوصی داخلی |
| ایمیج ghcr.io یا quay.io دانلود نمیشود | میرور فقط ایمیجهای Docker Hub را پوشش میدهد | تست دسترسی با curl و انتقال فایل tar |
| نیاز به استقرار در زمان قطعی | وابستگی به رجیستری بیرونی | نسخه آفلاین با docker save |
💡 نکته کلیدی
میرور رجیستری سروری است که ایمیجهای Docker Hub را از طرف شما دریافت و تحویل میدهد.
✅ راه سریع: کلید registry-mirrors را در daemon.json اضافه و سرویس را با systemctl reload docker بارگذاری کنید (بخش دوم).
✅ این مسدودی به ارائهدهنده ربطی ندارد و روی هر VPS ایران با IP داخلی دیده میشود؛ برای ghcr.io و quay.io هم راه جداگانه لازم است.
بیشتر راهنماهای فارسی به یک آدرس میرور ختم میشوند؛ اما وقتی میرور یک روز از دسترس خارج شود یا ایمیج مشکوکی تحویل دهد، صاحب سرور نمیداند ایراد از کجاست. ترتیب این راهنما همان ترتیب کار روی سرور است: اول نوع خطا را با یک دستور تشخیص میدهید، بعد میرور را تنظیم و بدون خاموش کردن کانتینرها اعمال میکنید. سپس اصالت ایمیج را میسنجید و آخر سر برای روز قطعی، نسخه پشتیبان محلی میسازید.
📌 آنچه در این مقاله میخوانید
◀️ علت خطای 403 و toomanyrequests
◀️ تنظیم registry-mirrors در فایل daemon.json
◀️ امنیت میرورهای داخلی و دریافت ایمیج از GHCR و Quay
◀️ نگهداری آفلاین ایمیجها و چکلیست استقرار کانتینر

خطای 403 یعنی Docker Hub به دلیل مقررات صادراتی آمریکا، درخواست را بر اساس موقعیت IP رد کرده است. پیام toomanyrequests با کد 429 موضوع دیگری است: سهمیه pull در بازه ۶ ساعته تمام شده است. اولی با میرور حل میشود و دومی با مدیریت سهمیه.
صفحهای که Docker Hub برای IPهای مسدود برمیگرداند، طبق متنی که یکی از کاربران در انجمن Docker نقل کرده، میگوید Docker شرکتی آمریکایی است و باید از مقررات کنترل صادرات پیروی کند. ایران هم در فهرست مناطق مسدود آمده است. فایل NOTICE پروژه Moby هم صریحاً میگوید استفاده و انتقال Docker ممکن است تابع محدودیتهای دولت آمریکا باشد.
روی سرور، این مسدودی معمولاً با پیامی شبیه خطای «نام اشتباه ایمیج» ظاهر میشود. نشانه اصلی، عبارت 403 Forbidden در انتهای پیام است:
Error response from daemon: pull access denied for nginx, repository does not exist or may require 'docker login'
... denied: <html><body><h1>403 Forbidden</h1> ...
پیش از هر تغییری، مستقیم از خود رجیستری بپرسید چه جوابی میدهد. طبق مشخصات OCI Distribution، نقطه پایانی /v2/ در حالت موفق 200 برمیگرداند و اگر رجیستری احراز هویت بخواهد 401. از IP خارج از ایران، هر سه رجیستری زیر پاسخ 401 میدهند.
curl -s -o /dev/null --max-time 10 -w "%{http_code}\n" https://registry-1.docker.io/v2/
curl -s -o /dev/null --max-time 10 -w "%{http_code}\n" https://ghcr.io/v2/
curl -s -o /dev/null --max-time 10 -w "%{http_code}\n" https://quay.io/v2/
| خروجی دستور | معنا | اقدام بعدی |
|---|---|---|
| پاسخ 200 | رجیستری باز است و احراز هویت نمیخواهد | معمولاً رجیستری داخلی خودتان؛ pull را امتحان کنید |
| پاسخ 401 | سرور API در دسترس است و توکن میخواهد | با یک docker pull واقعی تأیید کنید؛ توکن و لایهها از میزبانهای دیگری میآیند |
| پاسخ 403 | نشانی IP سرور در فهرست مسدود است | تنظیم میرور برای Docker Hub یا انتقال فایل tar |
| پاسخ 429 | سهمیه pull تمام شده است | صبر تا پایان بازه ۶ ساعته یا کش داخلی |
| کد 000 | پاسخی نیامد؛ مسیر شبکه یا DNS قطع است | بررسی resolv.conf و دسترسی بینالملل سرور |
طبق مستندات سهمیه Docker Hub (بهروزرسانی سپتامبر 2026)، کاربر بدون ورود ۱۰۰ pull در هر ۶ ساعت به ازای هر IPv4 یا هر زیرشبکه IPv6 با پیشوند /64 دارد. سقف حساب Personal هم ۲۰۰ pull است. پس از عبور از سقف، Docker Hub پاسخ 429 همراه با متن «You have reached your pull rate limit» برمیگرداند.
روی سرور ایران معمولاً اول 403 دیده میشود، چون درخواست اصلاً به مرحله شمارش نمیرسد. اگر بعد از تنظیم میرور پیام 429 ظاهر شد، احتمالاً سهمیه خود میرور پر شده است؛ صفحه میرور در مستندات Docker تأکید میکند که میرورهای Docker Hub هم تابع سیاست استفاده منصفانه هستند. در این حالت کش داخلی، که در بخش سوم میآید، تعداد درخواستها را کم میکند.

برای رفع خطا در سطح سرور، آدرس میرور را در کلید registry-mirrors فایل /etc/docker/daemon.json بنویسید، فایل را با dockerd --validate بررسی کنید و سرویس را reload کنید. از آن به بعد هر docker pull برای ایمیجهای Docker Hub اول سراغ میرور میرود.
مسیر پیشفرض این فایل در لینوکس، طبق مرجع dockerd، همان /etc/docker/daemon.json است. اگر فایل از قبل وجود دارد (مثلاً برای log-driver یا data-root)، آن را بازنویسی نکنید؛ کلید جدید را با jq ادغام کنید. اگر فایل وجود ندارد، حالت دوم را اجرا کنید.
# هشدار: tee فایل موجود را کامل بازنویسی میکند و تنظیمات قبلی (مثل data-root) از دست میرود
test -f /etc/docker/daemon.json && echo "exists: merge" || echo "missing: create"
# حالت ۱: فایل وجود دارد؛ ادغام با jq (نصب: sudo apt install jq)
sudo cp -a /etc/docker/daemon.json /etc/docker/daemon.json.bak
sudo jq '. + {"registry-mirrors": ["https://registry.docker.ir"]}' /etc/docker/daemon.json.bak | sudo tee /etc/docker/daemon.json > /dev/null
# حالت ۲: فایل وجود ندارد
sudo mkdir -p /etc/docker
echo '{"registry-mirrors": ["https://registry.docker.ir"]}' | sudo tee /etc/docker/daemon.json > /dev/null
آدرس https://registry.docker.ir نمونهای است که سایت docker.ir برای عبور از تحریم داکر منتشر کرده است. این سایت نام گرداننده میرور را اعلام نکرده و صفحه قوانین فعالی ندارد. پس پیش از استفاده در محیط اصلی، digest ایمیجها را طبق بخش سوم راستیآزمایی کنید. docker.ir برای اعمال تنظیم، ریاستارت سرویس را پیشنهاد میدهد، اما همانطور که پایینتر میآید reload کافی است.
بسیاری از راهنماها دستور systemctl restart docker را پیشنهاد میکنند. طبق مستندات live-restore، توقف daemon بهطور پیشفرض کانتینرهای در حال اجرا را خاموش میکند؛ کانتینرهای دارای restart policy بعداً بالا میآیند، اما وقفه پیش میآید. جدول «Configuration reload behavior» در مرجع dockerd گزینه registry-mirrors را جزو تنظیماتی آورده که با سیگنال SIGHUP و بدون ریاستارت پروسه بارگذاری میشوند. فایل سرویس systemd پروژه Moby هم برای reload همین سیگنال را میفرستد.
sudo dockerd --validate --config-file /etc/docker/daemon.json
sudo systemctl reload docker
docker info | grep -A2 "Registry Mirrors"
خروجی سالم دستور اول configuration OK است و دستور آخر باید آدرس میرور را زیر عنوان Registry Mirrors نشان دهد. اگر dockerd با فلگ --registry-mirror اجرا شده باشد، reload به دلیل تعارض اعمال نمیشود ولی سرویس هم متوقف نمیشود؛ پس خروجی docker info را حتماً ببینید. اگر خطای JSON گرفتید، علامت " یا کامای جاافتاده رایجترین علت است؛ با فایل .bak برگردید و دوباره ادغام کنید.
گاهی دسترسی root برای ویرایش daemon.json ندارید یا میخواهید فقط یک ایمیج را امتحان کنید. در این حالت نام میرور را جلوی ایمیج بنویسید و بعد آن را با نام استاندارد تگ کنید تا فایلهای compose بدون تغییر کار کنند. ایمیجهای رسمی Docker Hub در مسیر library/ قرار دارند.
docker pull registry.docker.ir/library/nginx:alpine
docker tag registry.docker.ir/library/nginx:alpine nginx:alpine
⚠️ محدودیت مهم
طبق صفحه Mirror the Docker Hub library، فعلاً فقط Docker Hub مرکزی را میشود میرور کرد و رجیستری خصوصی دیگری قابل میرور نیست. پس تنظیم بالا هیچ اثری روی ایمیجهایی مثل ghcr.io/... یا quay.io/... ندارد.

میرورهای داخلی رایجترین پاسخ به تحریم داکر هستند، اما هر میرور واسطهای است که میتواند محتوای دیگری تحویل دهد. پس اصالت ایمیج را با digest رسمی راستیآزمایی کنید و ایمیجهای GHCR و Quay را جداگانه بیازمایید؛ بیشتر آموزشها این مرحله را ندارند، در حالی که خطر اصلی همینجاست.
هر ایمیج یک digest از نوع sha256 دارد که از محتوای آن ساخته میشود؛ اگر حتی یک بایت عوض شود، digest هم عوض میشود. مخزن docker-library/repo-info در GitHub برای هر تگ رسمی، فایلی با دستور pull بر اساس digest نگه میدارد؛ مثلاً فایل repos/nginx/remote/alpine.md. GitHub هم طبق اعلامیه رسمی ژانویه 2021 با مجوز دولت آمریکا برای توسعهدهندگان ایرانی باز است.
docker image inspect --format '{{json .RepoDigests}}' nginx:alpine
# digest را با خط docker pull nginx@sha256:... در فایل زیر مقایسه کنید:
# https://github.com/docker-library/repo-info/blob/master/repos/nginx/remote/alpine.md
اگر ایمیج را با نام میرور گرفته باشید، RepoDigests همان digest را با پیشوند registry.docker.ir/library/nginx نشان میدهد و فقط بخش sha256 مهم است. تگها با هر انتشار تازه به digest جدیدی اشاره میکنند، پس عدم تطابق همیشه به معنی دستکاری نیست. راه قطعی این است که در فایل compose بهجای تگ، خود digest را بنویسید. در این حالت Docker محتوای دریافتی از میرور را با همان hash مقایسه میکند و ایمیج تغییرکرده را نمیپذیرد.
docker pull nginx@sha256:<digest-from-repo-info>
# در compose.yaml:
# services:
# web:
# image: nginx@sha256:<digest-from-repo-info>
ایمیجهای ghcr.io و quay.io از مسیر میرور Docker Hub عبور نمیکنند. اول با همان دستور curl بخش اول وضعیت هر رجیستری را از روی سرور خودتان بررسی کنید. پاسخ 401 فقط یعنی API در دسترس است؛ نتیجه نهایی را با یک docker pull واقعی بگیرید. اگر 403 آمد یا pull شکست خورد، ایمیج را روی سیستمی بیرون از ایران (مثلاً runner یک سرویس CI) بگیرید، با docker save آرشیو کنید و با scp به سرور بفرستید.
وقتی چند سرور دارید، بهتر است هر ایمیج یک بار دریافت شود و بقیه سرورها از نسخه داخلی بخوانند. ایمیج رسمی registry:3 طبق مستندات پروژه Distribution با یک دستور بالا میآید. در مثال زیر پورت فقط روی 127.0.0.1 باز است و ایمیجهای GHCR یا Quay را پس از انتقال با tag و push در آن نگه میدارید.
docker run -d -p 127.0.0.1:5000:5000 --restart=always --name registry registry:3
docker tag ghcr.io/OWNER/APP:1.0 localhost:5000/app:1.0
docker push localhost:5000/app:1.0
برای ایمیجهای Docker Hub، همین ایمیج را میشود در حالت pull-through cache اجرا کرد. مستندات Distribution کلید proxy.remoteurl را با Docker Hub مثال میزنند، ولی مقدار آن قابل تنظیم است؛ اگر upstream را میرور داخلی بگذارید، 403 پیش نمیآید. پیش از تکیه بر این کش، با یک pull آزمایشی آن را بیازمایید.
docker run -d -p 127.0.0.1:5001:5000 --restart=always --name hub-cache \
-e REGISTRY_PROXY_REMOTEURL=https://registry.docker.ir registry:3
⚠️ هشدار امنیتی رجیستری
مستندات Distribution میگویند این پیکربندیهای اولیه فقط برای آزمایش مناسباند و رجیستری تولیدی باید با TLS محافظت شود و بهتر است کنترل دسترسی داشته باشد. طبق مستندات شبکه Docker، پورت منتشرشده قوانین ufw را دور میزند؛ پس رجیستری بدون احراز هویت را هرگز روی 0.0.0.0 باز نگذارید. برای سرورهای دیگر، آن را پشت TLS و احراز هویت روی شبکه خصوصی بگذارید و آدرسش را در registry-mirrors آن سرورها بنویسید. کلید insecure-registries فقط برای آزمایش در شبکه خصوصی است.
🔶 نکته درباره سرور مجازی ایران وبداده
هر سرور مجازی ایران وبداده IP مستقیم دارد که از اینترنت بینالملل هم در دسترس است. پس رجیستری یا کشی که روی آن راه میاندازید باید به 127.0.0.1 یا شبکه خصوصی محدود باشد، یا TLS و احراز هویت داشته باشد.

ایمیجهای حیاتی را با docker save به فایل tar تبدیل کنید و روی دیسک یا سرور دیگری نگه دارید تا اگر میرور یا اینترنت بینالملل قطع شد، تحریم داکر استقرار شما را متوقف نکند. این روش به هیچ سرویس بیرونی وابسته نیست و با docker load برمیگردد.
طبق مرجع docker image save، خروجی این دستور یک آرشیو tar است و میشود آن را برای کم کردن حجم از gzip عبور داد. در یک فایل میتوانید چند ایمیج را با هم ذخیره کنید؛ docker load هم فایل فشرده با gzip را مستقیم میخواند.
docker save nginx:alpine postgres:16 | gzip > stack-images.tar.gz
scp stack-images.tar.gz user@backup-host:/srv/images/
docker load -i stack-images.tar.gz
گزینه --platform فقط یک معماری را ذخیره میکند (مثلاً linux/amd64) و حجم آرشیو را کم میکند. این گزینه به API نسخه 1.48 یا بالاتر نیاز دارد.
docker save --platform linux/amd64 -o nginx-amd64.tar nginx:alpine
dockerd --validate بررسی کنید و سرویس را reload کنید، نه restart.docker save بگیرید.اگر خود Docker Engine هنوز نصب نشده است، مراحل نصب را در آموزش نصب Docker روی اوبونتو 24.04 ببینید؛ آن راهنما به نصب میپردازد و این مقاله به دریافت ایمیج بعد از نصب. برای انتخاب توزیع مناسب، راهنمای خرید سرور مجازی لینوکس معیارهای منابع و سیستمعامل را مرور میکند.

در پنل سرور مجازی ایران وبداده، پیش از تغییر daemon.json میتوانید اسنپشات بگیرید و اگر سرویس Docker بالا نیامد، همان حالت قبل را بازگردانید. اگر SSH هم قطع شد، کنسول VNC و حالت Rescue راه دسترسی به فایل را باز نگه میدارند. برای تمرین بازگردانی آرشیوها هم امکان تست ساعتی رایگان سرور وجود دارد.
پرسشهای رایج درباره دریافت ایمیج Docker در ایران:
سرویس Docker Hub برای پیروی از مقررات کنترل صادرات آمریکا، درخواست IPهای ایران را رد میکند. این خطا به نسخه Docker یا تنظیمات سیستمعامل ربطی ندارد و با تنظیم میرور در daemon.json برطرف میشود.
تغییر DNS معمولی کمکی نمیکند، چون مسدودسازی بر اساس IP مبدأ درخواست است، نه نام دامنه. راه پایدار، میرور داخلی و آرشیو محلی ایمیجهاست.
میرورهای Docker Hub هم تابع سیاست استفاده منصفانه Docker هستند و ممکن است سهمیهشان پر شود. ایمیجهای پرتکرار را در کش یا رجیستری داخلی نگه دارید و در CI بهجای pull مکرر از نسخه محلی استفاده کنید.
خیر. طبق مستندات Docker، کلید registry-mirrors فقط برای Docker Hub است. دسترسی این رجیستریها را با curl روی مسیر /v2/ بررسی کنید؛ پاسخ 401 یعنی API در دسترس است و باید با یک pull واقعی تأیید شود. پاسخ 403 یعنی باید ایمیج را به شکل فایل tar منتقل کنید.
دستور docker info را اجرا کنید؛ آدرس میرور باید زیر عنوان Registry Mirrors دیده شود. اگر نیست، فایل daemon.json را با dockerd –validate بررسی کنید و سرویس را reload کنید.
میرور واسطه است و در اصل میتواند محتوای تغییرکرده تحویل دهد. digest ایمیج را با فایل همان تگ در مخزن docker-library/repo-info مقایسه کنید و برای سرویسهای حساس، ایمیج را در compose با digest بنویسید تا Docker محتوای دیگر را نپذیرد.
روی سیستمی که به رجیستری دسترسی دارد، با docker save آرشیو بسازید و با scp یا rsync به سرور بفرستید. روی سرور مقصد docker load -i را اجرا کنید؛ این دستور فایل فشرده با gzip را هم میخواند.
جمعبندی؛ تحریم داکر در سه لایه مشکل دریافت ایمیج روی سرور ایران از IP سرور شروع میشود، نه از تنظیمات شما؛ پس راهحل هم باید مستقل از Docker Hub باشد. لایه اول، ادغام میرور در daemon.json است که با reload و بدون توقف کانتینرها اعمال میشود و با docker info قابل بررسی است. لایه دوم، راستیآزمایی ایمیج است: digest را با مخزن repo-info مقایسه کنید و ایمیجهای حساس را با digest بنویسید. برای چند سرور هم یک کش یا رجیستری داخلی بسازید و آن را به شبکه خصوصی محدود کنید. لایه سوم، آرشیو محلی با docker save است که در قطعی میرور یا اینترنت بینالملل، استقرار را ممکن نگه میدارد. ایمیجهای GHCR و Quay را هم فراموش نکنید؛ میرور Docker Hub روی آنها اثری ندارد و باید جداگانه آزموده شوند. قدم اول: دستور curl بخش اول را روی سرور اجرا کنید؛ راهحل مناسب از جواب آن معلوم میشود.
🚀 مشاهده پلنها و تست ساعتی رایگان
سرور مجازی ایران وبداده در دیتاسنتر تهران میزبانی میشود، با پنل اسنپشات و کنسول VNC مدیریت میشود و امکان تست ساعتی رایگان دارد.
اگر میرور دیگری را آزمودهاید یا با خطایی روبهرو شدید که اینجا نیامده، در بخش نظرات بنویسید تا راهنما را کاملتر کنیم.
منابع