
وقتی یک تیم چند نفره روی چند پروژه کار میکنه، هر docker pull یعنی دانلود مجدد از اینترنت: هم کند، هم مصرف پهنای باند، هم گیر کردن روی محدودیتهای شبکه و rate limit داکرهاب. از طرف دیگه ایمیجهایی که خودمون میسازیم باید جایی نگهداری بشن که تحت کنترل ما باشه.
خب حالا میخوایم از نکسوس به عنوان mirror رجیستری داکر استفاده کنیم. مثلا ریپوی پروکسیای ساختیم به اسم arvan-miror که به میرور لیارا وصل میشه. آدرسی که UI بهمون میده اینه:
http://<server-ip>:8081/repository/arvan-mirror/
اما اگر این آدرس رو جایی به داکر بدیم کار نمیکنه! چرا؟ چون API رجیستری داکر نمیتونه روی یک مسیر زیرشاخهای (path-based) سرو بشه؛ داکر همیشه منتظر API روی root یک host:port هست.
راه حل : باید نوع connector سرویس nexus رو از path based به other connectors و در نهایت یک پورت http (یا https) انتخاب کنیم
سه نوع ریپازیتوری در نکسوس
قبل از ادامه این سه نوع رو باید خوب بفهمیم:
| Type | وظیفه | مثال |
|---|---|---|
| proxy | واسط بین ما و یک رجیستری remote؛ اولین درخواست رو از اینترنت میگیره و روی سرور کش میکنه؛ درخواستهای بعدی از کش جواب داده میشن | پروکسی Docker Hub |
| hosted | ریپوی خصوصی خودمون؛ ایمیجهایی که خودمون build کردیم رو اینجا push میکنیم | ایمیجهای داخلی تیم |
| group | یک URL واحد که چند ریپوی دیگه (proxy و hosted) رو کنار هم قرار میده؛ به ترتیب چک میکنه و از اولین منبعی که آرتیفکت رو داشته جواب میده | یک پورت برای همه چیز |

ترتیب اعضا در group مهمه
اعضای group به ترتیب اولویت چک میشن؛ همیشه hosted رو بالاتر از proxy بذارید تا ایمیجهای داخلی خودتون اولویت داشته باشن. ضمنا group خودش چیزی ذخیره نمیکنه؛ فقط یک روتر هوشمنده.
ساخت ریپوی proxy (کش داکرهاب)
از settings → Repository → Repositories → Create repository نوع docker (proxy) رو انتخاب کنید.

Name: docker-proxy
فیلد Repository Connectors: ابتدا other connectors رو انتخاب کنید بعد تیک HTTP رو بزنید و پورت 8082 رو وارد کنید. این پورت آدرس رجیستری این ریپو میشه.
فیلد Allow anonymous docker pull: اگر میخواید کلاینتها بدون docker login بتونن pull کنن، تیکش رو بزنید.
Remote storage: (به عنوان مثال مخزن اروان رو استفاده میکنیم)
https://docker.arvancloud.ir
فیلد Docker Index: گزینهی Use proxy registry رو انتخاب کنید. این تنظیم مسئول جستوجوی ایمیجهاست و اگر برای پروکسی داکرهاب روی Custom بمونه، بعضی pull ها با خطاهای گمراهکننده میشکنن. برای پروکسی رجیستریهای دیگه (مثل ghcr.io یا میرورهای داخلی) این گزینه رو روی Use proxy registry بذارید.
فیلد Authentication (اختیاری ولی توصیهشده): در بخش HTTP → Authentication نوع Username رو انتخاب و یک اکانت داکرهاب وارد کنید. سهمیهی pull اکانتدار خیلی بیشتر از IP ناشناسه و برای تیم چندنفره تفاوت محسوسی داره.
ساخت ریپوی hosted (رجیستری خصوصی)
ریپوری خصوصی و لوکال تنظیمات نوع پروکسی رو نداره و تنها چیزی که میشه بهش توجه کرد Deployment policy هست که دو حالت داره allow redeploy اجازه میده که تگ های ایمیج ها قابلیت بازنویسی داشته باشن و در صورت disable این اجازه داده نمیشه
روش امنتر: دو ریپوی hosted جدا بسازید، یکی docker-snapshots با redeploy آزاد و یکی docker-releases با redeploy بسته.
ساخت ریپوی group (آدرس واحد)
Create repository → docker (group)
Name: docker-group
Repository Connectors: HTTP روی پورت 8084
Member repositories: به این ترتیب اضافه کنید:
- docker-hosted
- docker-proxy
از این به بعد کلاینتها فقط با پورت 8084 (و بعد از Nginx، فقط با یک دامنه) کار میکنن و نمیدونن ایمیج از کش اومده یا از انبار داخلی.
سیستم push به group: ریپوی group بهصورت پیشفرض فقط خواندنیه. در نسخههای جدید نکسوس فیلد
Writable memberبرای group وجود داره که با ست کردنش میتونید push رو هم از همون آدرس انجام بدید. اگر این فیلد رو در نسخهی خودتون دیدید،docker-hostedرو انتخاب کنید؛ در غیر این صورت مثل نمونهی این مقاله، آدرس push رو جدا نگه دارید.
همچنین ترتیب مخزن ها در group مهمه و نکسوس هنگام pull گرفتن به ترتیب موجود بودن اون ایمیج رو چک میکنه پس بهتره که نمونه hosted در اولویت اول قرار بگیره تا همیشه در صورت امکان از مخزن لوکال ایمیج ها دانلود بشن

تنظیمات مخزن های داکر
برای هر مخزن داکر علاوه بر اسم و مقدار url که خود nexus بهمون برای دسترسی سریعتر و راحت تر به ادرس اختصاصی اون مخزن میده. مقداری تنظیمات برای مشخص کردن رفتار اون مخزن هم در اختیار میزاره. به عنوان مثال نوع connector رو در بخش قبلی عوض کردیم.
یا برای مخزن داکر از نوع proxy باید ادرس مخزن اصلی که قراره nexus از اون ایمیج هارو دریافت کنه رو وارد میکنیم
دو متغیر دیگری که مخزن های داکر دارن متغیر های maximum component age و maximum metadata age هست
- maximum component age
نشان دهنده مقدار زمانی هست که nexus برای دریافت یک ایمیج از cache خودش استفاده میکنه و برای دریافت اون ایمیج به مخزن proxy مراجعه نمیکنه که با مقدار -1 معنی بی نهایت رو میده - maximum metadata age
معنی مشابهی داره اما برای metadata انجام میشه. به عنوان مثال اگر ایمیج با تگ latest در cache سرور ذخیره شده باشه بعد از تایم مشخص شده در این متغیر اون ایمیج دوباره بررسی میشه که ایا ورژن جدیدی منتشر شده یا نه
تست پراکسی
اول چک میکنیم connector درسته:
curl http://<server-ip>:8082/v2/
اگر جواب {} یا کد 200 بود یعنی درسته. حالا pull:
docker pull <server-ip>:8082/alpine
اما دو تا خطای رایج این مرحله:
خطای اول — HTTPS client به سرور HTTP:
http: server gave HTTP response to HTTPS client
داکر به صورت پیشفرض سعی میکنه با HTTPS وصل بشه، ولی کانکتور ما HTTP هست. باید به داکر بگیم این رجیستری رو به عنوان insecure قبول کنه. در لینوکس فایل /etc/docker/daemon.json:
{
"insecure-registries": ["<server-ip>:8082"]
}
sudo systemctl restart docker
و در ویندوز (Docker Desktop) این تنظیم از داخل برنامه میشه: Settings → Docker Engine → همون JSON رو اضافه میکنیم → Apply & Restart.
خطای دوم no basic auth credentials:
pull access denied ... may require authorization: no basic auth credentials
یعنی نکسوس احراز هویت میخواد. دو راه داریم:
راه اول (برای mirror عمومی راحتتره):
فعال کردن دسترسی anonymous. در Server administration → Security → Anonymous فعالش میکنیم و در تنظیمات خود ریپو هم anonymous access رو Allow میکنیم.
راه دوم: login با کاربر نکسوس:
docker login <server-ip>:8082
تست hosted و group
فرض کنیم hosted رو روی پورت 8083 و group (شامل hosted + proxy) رو روی پورت 8084 بردیم. هر سه پورت رو به insecure-registries اضافه میکنیم و برای push حتما login میکنیم:
docker login <server-ip>:8083
docker tag alpine <server-ip>:8083/my-alpine:test
docker push <server-ip>:8083/my-alpine:test
و تست group که باید هر دو رو سرو کنه:
docker pull <server-ip>:8084/my-alpine:test # از hosted جواب میگیره
docker pull <server-ip>:8084/nginx # از proxy میگیره و کش میکنه
یک برداشت اشتباه رایج درباره group
شاید فکر کنیم وقتی از group ایمیج عمومی میگیریم، چون ایمیج در hosted نیست، از proxy گرفته میشه و داخل hosted ذخیره میشه. اینطور نیست! ایمیج در کش خود ریپوی proxy ذخیره میشه و hosted دستنخورده میمونه. یعنی:
- pull از group → کش میشه در proxy → pull های بعدی از همون کش
- group هیچوقت چیزی داخل hosted نمیریزه
نکته خوب اینه که کش proxy به صورت پیشفرض دائمی هست؛ چیزی پاک نمیشه مگه اینکه خودمون Cleanup Policy تعریف کنیم. پس برای اکثر موارد اصلا نیازی به کپی کردن داخل hosted نیست.
مرحله اخر HTTPS کردن رجیستری (حذف insecure-registries)
تنظیم insecure-registries روی همه کلاینتها اذیتکنندهست و راه درستش گذوندن رجیستری روی HTTPS با گواهی معتبره
مسیر اول (بدون نیاز به nginx) استفاده از TLS داخلی خود نکسوسه:
1. گرفتن گواهی با certbot (پورت 80 باید آزاد باشه):
sudo apt install -y certbot
sudo certbot certonly --standalone -d nexus.yourdomain.com
# خروجی: /etc/letsencrypt/live/nexus.yourdomain.com/
2. ایمپورت در نکسوس: در UI مسیر Security → TLS certificates → افزودن گواهی جدید؛ محتوای privkey.pem به عنوان کلید خصوصی و fullchain.pem به عنوان زنجیره گواهی.
3. تغییر Docker Connector ها به HTTPS: در تنظیمات هر ریپو، به جای HTTP گزینه HTTPS رو با پورت جدید (مثلا 8442 و 8443 و 8444) فعال میکنیم و گواهی ایمپورت شده رو انتخاب میکنیم.
4. باز کردن پورتها در فایروال و بعد از اطمینان، حذف insecure-registries از همه کلاینتها و restart داکر. از این به بعد همه چیز بدون هیچ تنظیم اضافهای کار میکنه:
docker pull nexus.yourdomain.com:8444/alpine
docker login nexus.yourdomain.com:8443
تمدید گواهی فراموش نشه
گواهیهای Let's Encrypt هر ۹۰ روز منقضی میشن. بعد از هر بار certbot renew باید گواهی جدید در نکسوس هم آپدیت بشه (دستی از UI یا با اسکریپت REST API) — وگرنه یک روز داکر کلاینتها خطای گواهی میگیرن.
راه جایگزین: گذاشتن nginx به عنوان reverse proxy با TLS termination جلوی نکسوس؛ مزیتش اینه که certbot --nginx تمدید رو خودکار میکنه و UI خود نکسوس هم HTTPS میشه. برای راه اندازی nginx میتونید مقالهی ریورس پروکسی nginx رو ببینید.
برای انجام دادن این روش دو مقاله راه اندازی ریورس پروکسی در nginx و نحوه فعال کردن https در nginx رو میتونید مطالعه کنید
نکات تکمیلی برای محیط عملیاتی
- تغییر پسورد admin بعد از اولین login و فعال کردن anonymous فقط در حد لازم — اگر رجیستری روی اینترنت عمومیه، anonymous رو محدود به خواندن از ریپوهای proxy/group کنید.
- مدیریت رم: تنظیمات heap در فایل
bin/nexus.vmoptions(یاnexus.vmoptionsدر data dir) قابل تغییره؛ روی سرورهای کمرم میشه-Xmsو-Xmxرو دستی کم کرد. - Cleanup Policy: برای اینکه کش proxy و ریپوهای hosted بینهایت بزرگ نشن، از Administration → Repository → Cleanup policies میتوانیم قانون حذف بر اساس آخرین دسترسی یا تاریخ دانلود تعریف و به ریپوها متصل کنیم.
- Blob Store: داده هر ریپو در یک blob store ذخیره میشه؛ میشه برای هر ریپو blob store جدا (حتی روی دیسک جدا) تعریف کرد.
- بکاپ: سادهترین راه بکاپ گیری از کل دایرکتوری
/opt/sonatype-workدر زمانی که سرویس down یا حداقل بیکاره. - ثبت در UI چه اتفاقی افتاد: برای دیدن اینکه واقعا ایمیجها از کش سرو شدن یا نه، بخش Browse هر ریپو لیست کامپوننتهای کش شده رو نشون میده.
مدیریت کاربر ها و تنظیم سطح دسترسی
برای ایجاد کاربر های بیشتر و مدیریت سطح دسترسی هر کاربر به عملیاتی که روی هر repository بتونه انجام بده باید به بخش settings -> security -> user بریم و گزینه ایجاد کاربر رو بزنیم
قبل از اون باید role همراه با دسترسی های مورد نظر رو ایجاد کنیم تا بشه این role رو به هر user که مدنظرمونه وصل کنیم
انواع role ها
برای ساخت role هم به مسیر settings -> security -> roles
توی nexus دو دسته کلی از Privilege ها داریم(جزییات دسترسی که به یک role تخصیص داده میشن)nx-repository-view و `nx-repository-admin
که نقش view برای مدیریت محتوای درون repository هاست و admin برای مدیریت خود repository ها

دسترسی ها برای view
| Action | What it allows |
|---|---|
browse | See the repo in the UI and list/navigate components (tree, search, metadata) — but not open/download files |
read | Download the actual artifact (HTTP GET, pull packages) |
add | Upload/deploy new components |
edit | Overwrite/modify existing components (redeploy) |
delete | Remove components |
دسترسی ها برای admin
| Action | What it allows |
|---|---|
browse | See the repo listed under Administration/server config |
read | View its settings page (URL, storage, connectors) |
edit | Change its configuration (change settings, blob store, policies) |
add | Create new repositories |
delete | Delete the whole repository |
به عنوان مثال برای درست کردن یک role برای دسترسی فقط به push و pull از سرور hosted میتونیم فقط دسترسی های read و edit و add و browse از گروه view رو برای اون مخزن خاص رو باز کنیم
نگهداری
Cleanup Policy
کش ریپوی proxy سقف رشد نداره و بزرگترین علت پر شدن دیسک سرور نکسوسه. حتماً سیاست پاکسازی تعریف کنید.
settings → Repository → Cleanup Policies → Create Cleanup Policy
| فیلد | مقدار پیشنهادی برای proxy |
|---|---|
| Name | docker-proxy-cleanup |
| Format | docker |
| Component usage — last downloaded before | 30 روز |
این یعنی هر ایمیجی که ۳۰ روز pull نشده حذف میشه. برای کش پروکسی کاملاً بیخطره چون در صورت نیاز دوباره از داکرهاب گرفته میشه.
برای docker-hosted محافظهکارتر باشید و بهجای معیار دانلود، از Component age با بازهی بلندتر (مثلاً ۹۰ روز) استفاده کنید، و ریپوی release رو معمولاً بهتره کلاً از سیاست پاکسازی خارج نگه دارید.
سیاست رو در تب Cleanup تنظیمات هر ریپو انتخاب کنید. بعد سه تسک زمانبندیشده در Administration → System → Tasks بسازید:
| تسک | کارکرد |
|---|---|
Admin - Cleanup repositories using their associated policies | اجرای سیاستهای پاکسازی |
Admin - Cleanup tags یا حذف مانیفستهای بلااستفادهی داکر | پاک کردن مانیفستها و لایههای بیارجاع |
Admin - Compact blob store | آزاد کردن واقعی فضای دیسک |
نکتهی مهم: تا وقتی Compact blob store اجرا نشه، فضای دیسک آزاد نمیشه. حذف در نکسوس اول soft delete هست. تسکها رو در ساعت کمترافیک شبانه زمانبندی کنید.
جمع بندی
مسیر کلی چیزی که ساختیم:
docker hub ←→ proxy (8082) ←┐
├── group (8084) ←→ کلاینتها (pull)
private imgs → hosted (8083) ←┘ ↑
(push ایمیجهای خودمون)
الان یک رجیستری داکر عملیاتی دارید: docker.example.com برای pull (که پشت صحنه هم کش داکرهابه هم انبار خصوصی)، docker-push.example.com برای انتشار ایمیجهای خودتون، هر دو روی HTTPS معتبر، با دسترسیهای تفکیکشده و سیاست پاکسازی خودکار.


