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.
node --version
npm --versionThe 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
| Setting | Purpose |
|---|---|
| proxy / https-proxy | Select the gateway for npm registry requests. An HTTPS destination can use an HTTP gateway through CONNECT. |
| registry | Select the package registry being contacted. Changing it does not configure a network proxy. |
| A registry-scoped authentication token | Authenticate to that registry; it is not a substitute for the gateway password. |
| noproxy / NO_PROXY | Exclude matching destinations from proxy routing. Check these when the observed route differs between hosts. |
| An application dispatcher or HTTP agent | Configure 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.
NPM_CHECK_CA may name its PEM certificate file; do not trust an unverified certificate merely to make a test pass.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
| Result | Next check |
|---|---|
| E407 or a rejected CONNECT tunnel | Confirm the complete proxy username, password and gateway address. Separate gateway authentication from registry login. |
| E401 or E403 from the registry | Check registry permissions and its token requirements. The isolated script does not load your saved registry token. |
| ECONNREFUSED or ENOTFOUND | Check 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_FAILED | Check gateway and registry availability. The script disables automatic fetch retries and bounds the child process; raw output is intentionally suppressed. |
| Certificate verification failure | Inspect 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 fails | Compare 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.
Read next
Node.js fetch proxy setup with Undici
An explicit HTTP proxy dispatcher with safe credential handling, bounded requests and response cleanup.
Read the guide
Fix 407 Proxy Authentication Required
Read the gateway code, check credentials and balance, then separate a rejected HTTPS tunnel from an HTTP response.
Read the guide