ایران‌ویا
مقالات آموزشی

رفع خطای npm install در ایران با میرور نوین کلاد

۹ دقیقه
رفع خطای npm install در ایران با میرور نوین کلاد

اگر دستور npm install در ایران با خطای ETIMEDOUT یا ECONNRESET متوقف می‌شود، مشکل از پروژه‌ی شما نیست؛ رجیستری رسمی npm از داخل ایران در دسترس نیست. راه‌حل، تغییر یک آدرس است: رجیستری را روی میرور نوین کلاد (Novin Cloud) تنظیم کنید تا پکیج‌ها از زیرساخت داخلی و بدون تحریم‌شکن دریافت شوند. این کار یک خط دستور است و برای npm، Yarn، pnpm و Bun یکسان جواب می‌دهد.

در ادامه دقیقاً می‌بینید چه خطایی چه معنایی دارد، رجیستری را در هر چهار پکیج‌منیجر چطور عوض کنید، فایل package-lock.json را چگونه اصلاح کنید تا دوباره سراغ سرور خارجی نرود، و چطور همین تنظیم را به Dockerfile و خط CI/CD خود ببرید.

چرا npm install در ایران شکست می‌خورد؟

رجیستری رسمی npm روی دامنه‌ی registry.npmjs.org میزبانی می‌شود. این سرویس از ایران یا اصلاً پاسخ نمی‌دهد، یا با تأخیر بالا و قطع‌های مکرر کار می‌کند. نتیجه این است که نصب یک وابستگی چندمگابایتی دقایق طول می‌کشد یا در میانه‌ی راه می‌شکند.

مشکل به همین‌جا ختم نمی‌شود. پکیج‌هایی مانند sharp، puppeteer و node-sass هنگام نصب، باینری‌های کامپایل‌شده را از GitHub Releases یا CDNهای خارجی دانلود می‌کنند. حتی اگر رجیستری اصلی پاسخ بدهد، این دانلودهای جانبی هم می‌توانند جداگانه شکست بخورند.

در محیط تولید وضعیت جدی‌تر است: وقتی خط CI/CD شما در هر بیلد به یک سرور خارج از کشور وابسته باشد، پایداری استقرار عملاً از کنترل شما خارج است. یک قطعی چنددقیقه‌ای در مسیر بین‌الملل، بیلد را قرمز می‌کند بدون آن‌که یک خط از کد شما تغییر کرده باشد.

خطاهای رایج و معنی واقعی‌شان

کد خطاچه اتفاقی افتاده استراه‌حل
ETIMEDOUTاتصال TCP به رجیستری در مهلت مقرر برقرار نشدتغییر رجیستری به میرور داخلی
ECONNRESETاتصال در میانه‌ی انتقال قطع شدتغییر رجیستری به میرور داخلی
ERR_SOCKET_TIMEOUTپاسخ در زمان تعیین‌شده کامل نشدتغییر رجیستری و افزایش fetch-timeout
403 Forbiddenدرخواست بر اساس موقعیت جغرافیایی رد شده استتغییر رجیستری به میرور داخلی
ENOTFOUNDنام دامنه به آی‌پی تبدیل نشدبررسی DNS و سپس تغییر رجیستری
EAI_AGAINخطای موقت در حل نام دامنهتنظیم DNS پایدار و تغییر رجیستری
EINTEGRITYچک‌سام فایل با مقدار ثبت‌شده در lock نمی‌خواندپاک‌کردن کش و بازسازی lock

نکته‌ی مشترک همه‌ی این خطاها یکی است: هیچ‌کدام ایراد کد شما نیستند. همه به مسیر شبکه تا رجیستری برمی‌گردند.

میرور npm نوین کلاد چیست؟

میرور یک نسخه‌ی آینه‌ای (mirror) از مخزن‌های عمومی نرم‌افزار است که داخل ایران میزبانی می‌شود. وقتی پکیجی درخواست می‌کنید، به‌جای مراجعه به سرور خارجی، همان فایل از زیرساخت داخلی به شما تحویل داده می‌شود. سرویس میرورهای نوین کلاد — که گاهی با املای «نوین کلود» یا «ابرنوین» هم نوشته می‌شود — بیش از ۷۹ مخزن عمومی را آینه کرده است؛ از توزیع‌های لینوکس و پکیج‌منیجرهای زبان‌های برنامه‌نویسی تا ایمیج‌های داکر، چارت‌های Helm و باینری‌های ابزارهای DevOps.

سه ویژگی این سرویس را برای توسعه‌دهنده‌ی ایرانی کاربردی می‌کند:

  • عمومی و رایگان — برای دریافت پکیج نیازی به حساب کاربری، کلید API یا لاگین نیست.
  • مخزن از نوع virtual — یک آدرس واحد که پشت صحنه هم کش محلی و هم مخزن بالادستی را پوشش می‌دهد. لازم نیست دنبال نام‌های -local یا -remote بگردید.
  • سازگار با ابزار استاندارد — میرور روی JFrog Artifactory اجرا می‌شود و مسیر API اختصاصی npm را ارائه می‌دهد، بنابراین همان دستورهای همیشگی npm بدون تغییر کار می‌کنند.

آدرس رجیستری npm که در تمام این مقاله استفاده می‌شود این است:

https://mirror.novin.cloud/artifactory/api/npm/npm/

پیکربندی npm در سه دقیقه

مسیر کامل از خطا تا نصب موفق، پنج قدم است:

  1. رجیستری فعلی را ببینید تا بدانید از کجا شروع می‌کنید:

    npm config get registry
  2. رجیستری را به میرور داخلی تغییر دهید. این دستور تنظیم را در فایل ~/.npmrc کاربر شما می‌نویسد و روی همه‌ی پروژه‌ها اعمال می‌شود:

    npm config set registry https://mirror.novin.cloud/artifactory/api/npm/npm/
  3. تنظیم را تأیید کنید. دستور دوم یک درخواست واقعی به رجیستری می‌زند؛ اگر شماره‌ی نسخه برگشت، مسیر سالم است:

    npm config get registry
    npm view express version
  4. کش و قفل قدیمی را پاک کنید. این قدم را اغلب فراموش می‌کنند و بعد تعجب می‌کنند که چرا هنوز خطا می‌گیرند:

    npm cache clean --force
    rm -rf node_modules
  5. نصب کنید:

    npm install

تنظیم در سطح پروژه به‌جای کل سیستم

اگر می‌خواهید این تنظیم فقط برای یک پروژه اعمال شود و همراه مخزن گیت برای هم‌تیمی‌هایتان هم برود، یک فایل .npmrc کنار package.json بسازید:

registry=https://mirror.novin.cloud/artifactory/api/npm/npm/

ترتیب اولویت در npm از بالا به پایین چنین است: پرچم خط فرمان، متغیر محیطی، فایل .npmrc پروژه، فایل .npmrc کاربر و در آخر پیش‌فرض‌های داخلی npm. یعنی فایل پروژه همیشه بر تنظیم کاربر غلبه می‌کند — جزئیات کامل در مستندات رسمی npm آمده است.

نکته‌ی مهم: فایل package-lock.json

این مهم‌ترین نکته‌ای است که در بیشتر راهنماها جا می‌افتد. فایل package-lock.json برای هر وابستگی یک آدرس کامل resolved ذخیره می‌کند که به registry.npmjs.org اشاره دارد. تا وقتی آن آدرس‌ها را اصلاح نکنید، npm ممکن است دوباره سراغ سرور خارجی برود — حتی با وجود تنظیم درست رجیستری.

دو راه دارید. راه اول، بازنویسی آدرس‌ها با یک دستور:

sed -i 's#https://registry.npmjs.org#https://mirror.novin.cloud/artifactory/api/npm/npm#g' package-lock.json

راه دوم، حذف فایل قفل و ساخت دوباره‌ی آن:

rm -f package-lock.json
npm install

راه اول امن‌تر است چون نسخه‌های دقیق وابستگی‌ها را دست‌نخورده نگه می‌دارد؛ راه دوم ساده‌تر است اما ممکن است نسخه‌های جزئی وابستگی‌ها را جابه‌جا کند. در پروژه‌های تیمی راه اول را انتخاب کنید و فایل اصلاح‌شده را کامیت کنید.

تنظیم Yarn، pnpm و Bun

هر سه پکیج‌منیجر دیگر اکوسیستم جاوااسکریپت از همان رجیستری استفاده می‌کنند؛ فقط محل نوشتن تنظیم فرق دارد.

Yarn

در Yarn نسخه‌ی یک (Classic):

yarn config set registry https://mirror.novin.cloud/artifactory/api/npm/npm/
yarn config get registry

در Yarn Berry (نسخه‌ی ۲ به بعد) تنظیم در فایل .yarnrc.yml پروژه نوشته می‌شود:

npmRegistryServer: "https://mirror.novin.cloud/artifactory/api/npm/npm/"

اگر پروژه‌ی شما از قبل فایل .npmrc با تنظیم registry دارد، همان کافی است و نیازی به تکرار تنظیم نیست.

pnpm

pnpm config set registry https://mirror.novin.cloud/artifactory/api/npm/npm/
pnpm config get registry
pnpm view express version

pnpm فایل .npmrc را هم می‌خواند، پس تنظیم سطح پروژه دقیقاً مثل npm عمل می‌کند.

Bun

در Bun تنظیم را در bunfig.toml پروژه (یا ~/.bunfig.toml برای حالت سراسری) می‌نویسید:

[install]
registry = "https://mirror.novin.cloud/artifactory/api/npm/npm/"

Bun هم فایل .npmrc را می‌خواند؛ بنابراین اگر پروژه از قبل .npmrc دارد، ساختن bunfig.toml ضروری نیست. برای بررسی:

bun add express --dry-run

راهنمای کامل هر چهار ابزار با جزئیات بیشتر در مستندات میرور npm نوین کلاد و صفحه‌های Yarn، pnpm و Bun در دسترس است.

استفاده در Docker و خط CI/CD

در ایمیج داکر به‌جای اجرای دستور npm config set بهتر است از متغیر محیطی استفاده کنید؛ هم یک لایه‌ی اضافه نمی‌سازد و هم در تمام مراحل بیلد اعمال می‌شود:

FROM node:22-alpine

ENV NPM_CONFIG_REGISTRY=https://mirror.novin.cloud/artifactory/api/npm/npm/

WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev

COPY . .
CMD ["node", "server.js"]

متغیر معادل برای سایر ابزارها:

ابزارمتغیر محیطی
npmNPM_CONFIG_REGISTRY
pnpmNPM_CONFIG_REGISTRY
Yarn ClassicYARN_REGISTRY
Yarn BerryYARN_NPM_REGISTRY_SERVER
BunBUN_CONFIG_REGISTRY

اگر ایمیج پایه‌ی شما هم از داخل ایران کشیده نمی‌شود، مشکل بعدی سر docker pull ظاهر می‌شود. برای آن باید رجیستری داکر را هم به میرور داخلی بسپارید؛ سرویس رجیستری داکر نوین کلاد دقیقاً همین کار را می‌کند و راهنمای آن در مستندات Docker و OCI آمده است.

برای بیلدهایی که روی کوبرنیتیز مدیریت‌شده اجرا می‌شوند، همین متغیر را در تعریف Job یا در ConfigMap مربوط به Runner قرار دهید تا همه‌ی Podهای بیلد از میرور داخلی استفاده کنند. اگر هنوز کلاستری ندارید، مقاله‌ی راه‌اندازی سریع کلاستر کوبرنیتیز نقطه‌ی شروع خوبی است.

عیب‌یابی مشکلات باقی‌مانده

اگر بعد از تغییر رجیستری هنوز خطا می‌گیرید، یکی از این چهار حالت رخ داده است.

هنوز آدرس رجیستری قبلی در لاگ دیده می‌شود

یعنی جایی یک تنظیم با اولویت بالاتر وجود دارد. با دستور زیر ببینید npm در نهایت چه چیزی را می‌خواند:

npm config list -l | grep registry

معمولاً مقصر یکی از این‌هاست: فایل .npmrc پروژه، فایل .npmrc کاربر، یا آدرس‌های resolved داخل package-lock.json که در بخش قبل درباره‌اش صحبت کردیم.

خطای EINTEGRITY

این خطا یعنی چک‌سام فایل دریافتی با مقداری که در فایل قفل ثبت شده هم‌خوانی ندارد. کش را پاک و قفل را بازسازی کنید:

npm cache clean --force
rm -rf node_modules package-lock.json
npm install

پاسخ ۵۰۲ از میرور

خطای ۵۰۲ معمولاً یک مشکل موقتی سمت سرویس است و با تلاش مجدد برطرف می‌شود. اگر ادامه داشت، از طریق تیکت پشتیبانی اطلاع دهید.

پکیج‌های خصوصی یا اسکوپ‌دار

اگر سازمان شما پکیج خصوصی روی رجیستری دیگری دارد، لازم نیست همه‌چیز را یکجا جابه‌جا کنید. می‌توانید فقط برای آن اسکوپ یک رجیستری جدا تعریف کنید و بقیه‌ی ترافیک از میرور برود:

registry=https://mirror.novin.cloud/artifactory/api/npm/npm/
@my-company:registry=https://npm.my-company.ir/

همین منطق برای انتشار پکیج هم صدق می‌کند: میرور یک مخزن خواندنی است. اگر قصد npm publish دارید، باید موقتاً رجیستری مقصد را در همان دستور مشخص کنید.

پکیج‌هایی که باینری جداگانه دانلود می‌کنند

بعضی پکیج‌ها پس از نصب، در مرحله‌ی postinstall سراغ دانلود باینری کامپایل‌شده از یک آدرس خارجی می‌روند. چون این دانلود از رجیستری npm انجام نمی‌شود، تغییر رجیستری به‌تنهایی آن را درست نمی‌کند. نمونه‌ی شناخته‌شده‌ی آن Puppeteer است که مرورگر Chromium را جداگانه می‌گیرد.

سه راه عملی دارید. اول، غیرفعال‌کردن دانلود خودکار و استفاده از نسخه‌ی نصب‌شده روی سیستم:

export PUPPETEER_SKIP_DOWNLOAD=true
npm install puppeteer

دوم، استفاده از یک ایمیج پایه‌ی داکر که مرورگر یا کتابخانه‌ی موردنیاز را از قبل دارد. سوم، اگر باینری روی GitHub Releases منتشر شده است، از میرور GitHub Releases نوین کلاد استفاده کنید که راهنمای آن در مستندات میرور GitHub Releases آمده است.

قاعده‌ی کلی این است: هر بار که نصب یک پکیج طولانی شد یا شکست، لاگ را بخوانید و ببینید آخرین آدرسی که تلاش کرده به آن وصل شود کدام دامنه است. اگر دامنه‌ی رجیستری نبود، مشکل از مرحله‌ی postinstall است نه از تنظیم رجیستری.

سؤالات متداول

آیا استفاده از میرور نوین کلاد هزینه دارد؟

خیر. میرور یک سرویس عمومی و رایگان است و برای دریافت پکیج نیازی به حساب کاربری، کلید API یا لاگین ندارید. کافی است آدرس رجیستری را تغییر دهید.

آیا پکیج‌هایی که از میرور می‌گیرم دقیقاً همان نسخه‌های اصلی هستند؟

بله. مخزن از نوع virtual است؛ یعنی همان فایل از مخزن بالادستی دریافت و کش می‌شود. چک‌سام فایل‌ها تغییر نمی‌کند و به همین دلیل است که npm ci با فایل قفل موجود بدون مشکل کار می‌کند.

اگر پکیجی هنوز در کش میرور نباشد چه اتفاقی می‌افتد؟

مخزن virtual پشت صحنه درخواست را به مخزن بالادستی می‌فرستد، فایل را دریافت و برای دفعات بعد کش می‌کند. اولین درخواست ممکن است کمی کندتر باشد؛ درخواست‌های بعدی از کش داخلی سرو می‌شوند.

آیا می‌توانم پکیج خودم را روی این میرور منتشر کنم؟

خیر. میرور برای دریافت پکیج طراحی شده است، نه انتشار. برای انتشار باید به رجیستری مقصد خودتان (رجیستری عمومی npm یا رجیستری خصوصی سازمان) متصل شوید.

آیا برای سرورهای خارج از ایران هم استفاده از میرور منطقی است؟

اگر سرور بیلد شما خارج از ایران است و دسترسی مستقیم دارد، تفاوت محسوسی نمی‌بینید. مزیت اصلی میرور برای توسعه‌دهنده یا سرور بیلدی است که داخل ایران قرار دارد.

جمع‌بندی

خطای npm install در ایران تقریباً همیشه یک مسئله‌ی مسیر شبکه است، نه مشکل کد. با تنظیم رجیستری روی میرور نوین کلاد (Novin Cloud)، اصلاح آدرس‌های resolved در فایل قفل، و بردن همان متغیر محیطی به Dockerfile و خط CI/CD، نصب پکیج از یک مانع روزمره به یک قدم قابل‌اتکا تبدیل می‌شود — بدون تحریم‌شکن و بدون ثبت‌نام.

قدم بعدی: صفحه‌ی سرویس میرورها و مخزن‌ها را ببینید تا بدانید کدام‌یک از بیش از ۷۹ مخزن موجود به کار پروژه‌ی شما می‌آید. اگر در حال طراحی زیرساخت یک تیم جدید هستید، مقاله‌های راهنمای انتخاب سرور مجازی و بهینه‌سازی هزینه‌های ابری و صفحه‌ی راهکار استارتاپ‌ها ادامه‌ی منطقی همین مسیرند.