Skip to content

Guides · Connect and debug

npm CLI proxy setup and connection checks

Check whether the npm command-line client can reach an HTTPS registry through your authenticated HTTP proxy. Start with a read-only ping, keep registry tokens separate from proxy credentials and avoid changing your normal npm configuration.

Published

Short answers

Which npm settings select a proxy?

The npm CLI has proxy and https-proxy settings for registry requests. They are separate from an application’s fetch dispatcher. Environment variables and npmrc files can also affect npm, so inspect the configuration used by the actual process.

Does npm ping install a package?

No. It checks the configured registry and authentication. A successful ping does not establish that a package tarball, Git dependency or install script can use the same route.

Is my registry token the proxy password?

No. The proxy authenticates access to the gateway; a registry token authenticates access to the package registry. Keep them separate and scope registry tokens to the intended registry.

Should I disable strict-ssl to fix a proxy error?

No. Keep certificate verification enabled. Check the certificate chain, hostname and approved trust configuration. An HTTP proxy can carry an HTTPS registry request through CONNECT without changing the registry URL to HTTP.

Configure the npm CLI that makes the request

This guide is for the npm package-manager command, not for writing a proxy server or routing an application’s HTTP requests. If npm succeeds but your Node application fails, configure the Node fetch client or Axios separately.

Check the installed clientssh
node --version
npm --version

The example targets npm 10 on macOS or Linux and uses Node.js built-in modules. Follow the documentation for the version installed on the worker that runs your job. The npm configuration reference describes proxy settings and request limits.

Separate proxy, registry and application settings

Settings that answer different questions
SettingPurpose
proxy / https-proxySelect the gateway for npm registry requests. An HTTPS destination can use an HTTP gateway through CONNECT.
registrySelect the package registry being contacted. Changing it does not configure a network proxy.
A registry-scoped authentication tokenAuthenticate to that registry; it is not a substitute for the gateway password.
noproxy / NO_PROXYExclude matching destinations from proxy routing. Check these when the observed route differs between hosts.
An application dispatcher or HTTP agentConfigure that application client, not the separate npm CLI process.

Project, user and global npmrc files can carry different settings. Do not paste a full npm configuration dump into a support message. Inspect relevant values locally and redact credentials. Registry authentication entries should be scoped to their registry host and path.

Run one isolated registry ping

Save the script as npm-proxy-check.mjs and run node npm-proxy-check.mjs in a terminal. It asks for the full generated proxy username and password without displaying either. The default gateway comes from this site’s configuration; PROXY_SERVER can select an approved HTTP gateway without credentials in its URL.

The check uses the public npm registry by default. Set the non-secret NPM_CHECK_REGISTRY only for an HTTPS registry you are permitted to contact. Existing registry tokens are deliberately not loaded, so a registry requiring a token may reject this check. It is not an authenticated private-registry setup recipe.

The script intentionally tests the selected proxy without inherited proxy exclusions or npm configuration, in its own child process. Run it only where that route is approved. It does not change your shell, existing npmrc files or network policy. For an approved internal certificate authority, NPM_CHECK_CA may name its PEM certificate file; do not trust an unverified certificate merely to make a test pass.
npm-proxy-check.mjsjavascript
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;
});

Credentials exist briefly in a mode-600 file inside a private temporary directory. The script passes only file paths to npm, disables npm log files, limits captured output and removes the directory on ordinary completion or handled interruption. A forced process termination or machine failure can still leave protected temporary files; remove that check’s directory after investigating. File permissions do not protect against an administrator or another process running as your account.

Automation may supply PROXY_USER and PROXY_PASSWORD through its existing secret manager instead of the prompts. Do not put their literal values in a shell command, saved script or CI output. Environment variables remain readable by sufficiently privileged processes. The script does not pass those variables to the npm child.

What the result establishes

The npm ping command checks the registry. This script reports only success or a small set of error codes; it does not print an exit IP or claim to prove geographic routing. A passing result confirms that this isolated invocation reached a registry response through its configured request path, not that your normal project configuration is identical.

To investigate the proxy itself, first run the separate curl connection check. Then compare the gateway and client settings. Do not infer npm’s path solely from a successful curl request. A package install can contact additional tarball or Git hosts, run scripts and consume substantially more data; a ping does none of those checks.

Find the failing layer before changing settings

npm proxy check failures
ResultNext check
E407 or a rejected CONNECT tunnelConfirm the complete proxy username, password and gateway address. Separate gateway authentication from registry login.
E401 or E403 from the registryCheck registry permissions and its token requirements. The isolated script does not load your saved registry token.
ECONNREFUSED or ENOTFOUNDCheck the proxy host, port and worker network. A successful test on another computer does not establish this worker’s connectivity.
Timeout, FETCH_ERROR or CHECK_FAILEDCheck gateway and registry availability. The script disables automatic fetch retries and bounds the child process; raw output is intentionally suppressed.
Certificate verification failureInspect the hostname and trusted certificate chain. Keep strict-ssl enabled and use only an approved CA file when required.
The isolated check succeeds but a project command failsCompare the project npmrc, registry selection, environment, proxy exclusions and any additional download hosts.

See 407 authentication troubleshooting, CONNECT tunnel failures and a proxy that works in curl but not an app. Do not keep retrying a registry’s refusal or change certificate verification to hide the error.

Move the approved settings into your workflow

After the check, use your team’s normal secret and npm configuration process for the real job. Keep registry tokens scoped, exclude secret-bearing npmrc files from source control and check proxy exclusions deliberately. The script is a diagnostic with temporary settings, so it does not repair an existing project configuration automatically.

A short ping is not a bandwidth estimate for a dependency install. Measure an authorised representative job before increasing its size and account for repeated or failed transfers. Read how proxy traffic is counted, compare HTTP and SOCKS5 and check current traffic prices if this route fits your task.

What is not allowed

Use the proxy only for authorised package access, QA and development within the registry’s terms and your network policy. A different network route does not change permission to download a package. See the acceptable-use policy.

npm CLI proxy setup and connection checks · Portproof