Короткие ответы
Настраивает ли агент Node.js прокси для npm?
Нет. npm запускается отдельным клиентом и читает свои параметры. Агент вашего приложения, переменные процесса и конфигурация npm отвечают за разные запросы. Проверяйте именно процесс, в котором возник сбой.
Чем proxy отличается от registry?
proxy и https-proxy задают шлюз, registry — сервер пакетов. Токен registry подтверждает доступ к нему, а пароль прокси — соединение со шлюзом. Смена адреса registry не заменяет настройку прокси.
Устанавливает ли проверка пакеты?
Нет. Она вызывает npm ping для выбранного HTTPS-registry. Установка может дополнительно обращаться к tarball- и Git-узлам и запускать скрипты; успешный ping эти действия не проверяет.
Можно ли отключить strict-ssl ради проверки?
Не следует. Найдите ошибку имени или цепочки доверия. Для разрешённого внутреннего центра сертификации пример может использовать явно заданный CA-файл, сохраняя проверку сертификата.
Проверьте версии рабочего процесса
node --version
npm --versionСохранённый пример рассчитан на npm 10, macOS и Linux и использует встроенные модули Node.js. Документация npm 10 сейчас обозначена Legacy. Это версия рецепта, а не рекомендация по выбору нового runtime: для другого npm проверьте его справку и совместимость сценария. В Windows данный скрипт намеренно останавливается.
Конфигурация npm описывает отдельные proxy, https-proxy, registry, noproxy и ограничения запросов. Сначала зафиксируйте версию именно в worker или CI. Версия вашего интерактивного терминала не подтверждает окружение давно запущенной задачи.
Разделите конфигурацию и авторизацию
| Параметр | Назначение |
|---|---|
| proxy / https-proxy | Маршрут запросов npm к registry через шлюз. |
| registry | Адрес сервера пакетов, а не промежуточного шлюза. |
| Токен с областью registry | Доступ к конкретному registry; пароль прокси его не заменяет. |
| noproxy / NO_PROXY | Исключения прямого подключения для назначений. |
| Агент или dispatcher приложения | Транспорт приложения, не отдельного npm CLI. |
У проекта, пользователя и глобальной конфигурации есть разные npmrc. Не выводите всю конфигурацию в поддержку: она может содержать токены и URL с паролем. Сначала установите источник нужного параметра. Данные входа registry должны быть ограничены его узлом и путём.
Подготовьте изолированный тест
Возьмите полный логин и пароль в Connection builder · English. Сохраните скрипт как npm-proxy-check.mjs и запустите node npm-proxy-check.mjs в терминале. Секреты запрашиваются без отображения. PROXY_SERVER при необходимости меняет только адрес разрешённого HTTP-шлюза без данных входа в URL.
По умолчанию используется публичный npm registry. NPM_CHECK_REGISTRY можно задать для разрешённого HTTPS-registry, но существующие токены намеренно не загружаются. Сервер, которому нужен токен, может отклонить проверку. Это не инструкция для готового авторизованного доступа к частному registry.
Проверка намеренно исключает унаследованные настройки npm и прямые исключения только в своём дочернем процессе. Выполняйте её там, где выбранный маршрут разрешён. Скрипт не изменяет рабочие файлы npmrc, оболочку или сетевую политику. NPM_CHECK_CA допустим только для доверенного и разрешённого PEM-файла.
Выполните один registry ping
import { execFile } from 'node:child_process';
import { mkdtemp, writeFile, rm } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join, resolve } from 'node:path';
import { createInterface } from 'node:readline';
import { Writable } from 'node:stream';
import { promisify } from 'node:util';
const run = promisify(execFile);
async function secret(name, label) {
if (process.env[name]) return process.env[name];
if (!process.stdin.isTTY) throw new Error('Secret input requires a terminal');
process.stderr.write(label + ': ');
const muted = new Writable({ write(_data, _encoding, done) { done(); } });
const rl = createInterface({ input: process.stdin, output: muted, terminal: true });
try {
return await new Promise((resolve, reject) => {
rl.once('SIGINT', () => reject(new Error('Input cancelled')));
rl.once('close', () => reject(new Error('Input closed')));
rl.question('', resolve);
});
} finally {
rl.close();
process.stderr.write('\n');
}
}
async function main() {
if (process.platform === 'win32') throw new Error('This example targets macOS and Linux');
const proxy = new URL(process.env.PROXY_SERVER ?? 'http://gw.portproof.org:7000');
const registry = new URL(process.env.NPM_CHECK_REGISTRY ?? 'https://registry.npmjs.org/');
if (proxy.protocol !== 'http:' || proxy.username || proxy.password ||
proxy.pathname !== '/' || proxy.search || proxy.hash) throw new Error('Invalid proxy');
if (registry.protocol !== 'https:' || registry.username || registry.password ||
registry.search || registry.hash) throw new Error('Invalid registry');
const username = await secret('PROXY_USER', 'Full proxy username');
const password = await secret('PROXY_PASSWORD', 'Proxy password');
if (!username || !password || /[:\r\n\0]/.test(username) || /[\r\n\0]/.test(password)) {
throw new Error('Invalid credentials');
}
proxy.username = encodeURIComponent(username);
proxy.password = encodeURIComponent(password);
// Keep npm's child environment small: no inherited npm settings, proxy
// exceptions, registry tokens, NODE_OPTIONS or TLS-verification overrides.
const childEnv = {};
for (const name of ['PATH', 'HOME', 'TMPDIR', 'TMP', 'TEMP', 'LANG']) {
if (process.env[name]) childEnv[name] = process.env[name];
}
// npm enables Node's compile cache outside its --cache directory by default.
// Disable that optional cache for this one-off child so nothing is left behind.
childEnv.NODE_DISABLE_COMPILE_CACHE = '1';
const directory = await mkdtemp(join(tmpdir(), 'npm-proxy-check-'));
const controller = new AbortController();
const stop = () => controller.abort();
process.once('SIGINT', stop);
process.once('SIGTERM', stop);
try {
const config = [
'proxy=' + JSON.stringify(proxy.href),
'https-proxy=' + JSON.stringify(proxy.href),
'noproxy=',
];
// Optional certificate file for an approved internal registry.
// This adds trust for this check; certificate verification remains on.
if (process.env.NPM_CHECK_CA) {
config.push('cafile=' + JSON.stringify(resolve(process.env.NPM_CHECK_CA)));
}
await writeFile(join(directory, 'user.npmrc'), config.join('\n') + '\n', { mode: 0o600 });
await writeFile(join(directory, 'global.npmrc'), '', { mode: 0o600 });
await run('npm', [
'ping', '--json', '--registry=' + registry.href,
'--userconfig=' + join(directory, 'user.npmrc'),
'--globalconfig=' + join(directory, 'global.npmrc'),
'--cache=' + join(directory, 'cache'),
'--strict-ssl=true', '--fetch-retries=0', '--fetch-timeout=15000',
'--logs-max=0', '--update-notifier=false', '--ignore-scripts=true',
], {
cwd: directory, env: childEnv, signal: controller.signal,
timeout: 20000, killSignal: 'SIGKILL', maxBuffer: 65536,
});
console.log('Registry ping succeeded. No package was installed.');
} catch (error) {
// Never echo npm's raw output: it may contain configuration details.
let code = error.code === 'ABORT_ERR' ? 'ABORTED' : 'CHECK_FAILED';
try {
const reported = JSON.parse(error.stdout).error?.code;
if (['E401', 'E403', 'E407', 'E502', 'ECONNREFUSED', 'ENOTFOUND',
'ETIMEDOUT', 'ECONNRESET', 'FETCH_ERROR', 'CERT_HAS_EXPIRED',
'SELF_SIGNED_CERT_IN_CHAIN', 'DEPTH_ZERO_SELF_SIGNED_CERT',
'UNABLE_TO_VERIFY_LEAF_SIGNATURE'].includes(reported)) code = reported;
} catch {}
console.error('Registry ping failed: ' + code);
process.exitCode = 1;
} finally {
process.removeListener('SIGINT', stop);
process.removeListener('SIGTERM', stop);
await rm(directory, { recursive: true, force: true });
}
}
main().catch(() => {
console.error('Check setup failed. Verify the gateway, HTTPS registry and secret input.');
process.exitCode = 1;
});Секреты кратковременно записываются в файл с правами 600 внутри собственного временного каталога. Скрипт ограничивает вывод, отключает лог-файлы npm и удаляет каталог при обычном завершении или обработанном прерывании. Авария машины или принудительное завершение могут оставить защищённые временные данные; права не защищают от администратора либо процесса вашего пользователя.
Автоматизация может передать PROXY_USER и PROXY_PASSWORD через свой механизм секретов. Не вставляйте реальные значения в команду оболочки или CI-лог. Эти переменные не передаются дочернему npm. Ни пароль шлюза, ни токен registry не нужны для публичного отчёта об ошибке.
Правильно истолкуйте результат
npm ping обращается к настроенному registry. Сценарий выдаёт только успех или ограниченную категорию ошибки. Он не печатает IP и не устанавливает географию. Успех относится к этому изолированному запуску, а не доказывает совпадение с рабочим проектом.
Для шлюза используйте отдельный curl-тест, затем сравните конфигурацию клиентов. Установка зависимости может загружать намного больше данных и обращаться к другим узлам. Не оценивайте её расход по одному ping и не запускайте install только ради диагностики proxy.
Найдите слой отказа перед изменением
| Категория | Следующая проверка |
|---|---|
| E407 или отказ CONNECT | Шлюз, полный логин и пароль по диагностике 407. |
| E401 или E403 от registry | Разрешения сервера пакетов; изолированный сценарий не читает сохранённый токен. |
| ECONNREFUSED или ENOTFOUND | Адрес, порт и среда worker, а не другого компьютера. |
| Таймаут или FETCH_ERROR | Доступность шлюза и registry; повторы ограничены, сырой вывод намеренно скрыт. |
| Ошибка сертификата | Доверенная цепочка и имя назначения, без отключения strict-ssl. |
| Тест проходит, проект нет | Сравнить npmrc проекта, registry, окружение, исключения и дополнительные узлы загрузки. |
Перенесите только разрешённые настройки
После диагностики используйте обычный механизм развёртывания и секретов проекта. Сам временный скрипт не чинит его конфигурацию. Сохраняйте область токенов registry, исключайте файлы с секретами из Git и ограничивайте повторы отказавших запросов. Для HTTP CONNECT есть отдельное руководство.
Измерьте разрешённый представительный запуск перед увеличением нагрузки, учитывая ошибки и повторные передачи. Тарифы Portproof описывают общий баланс мобильного и резидентского трафика; настройка npm не резервирует устройство. Покупка и кабинет остаются на английском. Справки проверены 31 октября 2026 года; живой registry, шлюз и реальная установка пакетов при подготовке статьи не тестировались.
Допустимое использование
Используйте прокси для разрешённых задач и соблюдайте правила принимающего сервиса. Настройка соединения не даёт права на доступ. Применяются правила допустимого использования · English.