How to fix SSL certificate error when running Npm on Windows?
When I try to install a package with npm, it doesn't work. After a long wait, I eventually get an error 'tunneling socket could not be established, sutatusCode=403'.
$ npm install coffee-script
npm http GET https://registry.npmjs.org/coffee-script
npm http GET https://registry.npmjs.org/coffee-script
npm http GET https://registry.npmjs.org/coffee-script
npm ERR! Error: tunneling socket could not be established, sutatusCode=403
npm ERR! at ClientRequest.onConnect (c:\Program Files\nodejs\node_modules\npm\node_modules\request\tunnel.js:148:19)
npm ERR! at ClientRequest.g (events.js:193:14)
npm ERR! at ClientRequest.EventEmitter.emit (events.js:123:20)
npm ERR! at Socket.socketOnData (http.js:1393:11)
npm ERR! at TCP.onread (net.js:403:27)
However, when I browse to that same URL in my web browser (Google Chrome) it loads fine (see footnote). https://registry.npmjs.org/coffee-script
What's going wrong?
While I happen to use a https proxy, I'm confident this isn't the problem. I've configured the environment variable https_proxy
(per the npm user guide). I know the environment variable is correct, because the Python package manager pip
follows it correctly.
I believe the problem relates to SSL certificates, because if I download that URL with wget
, I get an explicit error about certificates
$ wget https://registry.npmjs.org/coffee-script
SYSTEM_WGETRC = c:/progra~1/wget/etc/wgetrc
syswgetrc = c:/progra~1/wget/etc/wgetrc
--2012-12-17 12:14:07-- https://registry.npmjs.org/coffee-script
Resolving corpproxy... 10.254.215.35
Connecting to corpproxy|10.254.215.35|:8080... connected.
ERROR: cannot verify registry.npmjs.org's certificate, issued by `/C=US/ST=CA/L=Oakland/O=npm/OU=npm Certificate Authority/CN=npmCA/[email protected]':
Unable to locally verify the issuer's authority.
To connect to registry.npmjs.org insecurely, use `--no-check-certificate'.
Unable to establish SSL connection.
How can I fix this? Without compromising security.
I used to get SSL certificate errors in my web browser too, until I installed the 'npmCA' certificate as a 'trusted root certification authority' in Control Panel's Internet Options (screenshot )
Edit: I tried an insecure workaround per https://npmjs.org/doc/config.html#strict-ssl
npm set strict-ssl false
Yet it still times out with the same error
$ npm install coffee-script
npm http GET https://registry.npmjs.org/coffee-script
npm http GET https://registry.npmjs.org/coffee-script
npm http GET https://registry.npmjs.org/coffee-script
npm ERR! Error: tunneling socket could not be established, sutatusCode=403
TL;DR - Just run this and don't disable your security:
Replace existing certs
# Windows/MacOS/Linux
npm config set cafile "<path to your certificate file>"
# Check the 'cafile'
npm config get cafile
or extend existing certs
Set this environment variable to extend pre-defined certs:
NODE_EXTRA_CA_CERTS
to "<path to certificate file>"
Full story
I've had to work with npm, pip, maven etc. behind a corporate firewall under Windows - it's not fun. I'll try and keep this platform agnostic/aware where possible.
HTTP_PROXY & HTTPS_PROXY
HTTP_PROXY
& HTTPS_PROXY
are environment variables used by lots of software to know where your proxy is. Under Windows, lots of software also uses your OS specified proxy which is a totally different thing. That means you can have Chrome (which uses the proxy specified in your Internet Options) connecting to the URL just fine, but npm, pip, maven etc. not working because they use HTTPS_PROXY (except when they use HTTP_PROXY - see later). Normally the environment variable would look something like:
http://proxy.example.com:3128
But you're getting a 403 which suggests you're not being authenticated against your proxy. If it is basic authentication on the proxy, you'll want to set the environment variable to something of the form:
http://user:[email protected]:3128
The dreaded NTLM
There is an HTTP status code 407 (proxy authentication required), which is the more correct way of saying it's the proxy rather than the destination server that's rejecting your request. That code plagued me for the longest time until after a lot of time on Google, I learned my proxy used NTLM authentication. HTTP basic authentication wasn't enough to satisfy whatever proxy my corporate overlords had installed. I resorted to using Cntlm on my local machine (unauthenticated), then had it handle the NTLM authentication with the upstream proxy. Then I had to tell all the programs that couldn't do NTLM to use my local machine as the proxy - which is generally as simple as setting HTTP_PROXY
and HTTPS_PROXY
. Otherwise, for npm use (as @Agus suggests):
npm config set proxy http://proxy.example.com:3128
npm config set https-proxy http://proxy.example.com:3128
"We need to decrypt all HTTPS traffic because viruses"
After this set-up had been humming along (clunkily) for about a year, the corporate overlords decided to change the proxy. Not only that, but it would no longer use NTLM! A brave new world to be sure. But because those writers of malicious software were now delivering malware via HTTPS, the only way they could protect we poor innocent users was to man-in-the-middle every connection to scan for threats before they even reached us. As you can imagine, I was overcome with the feeling of safety.
To cut a long story short, the self-signed certificate needs to be installed into npm to avoid SELF_SIGNED_CERT_IN_CHAIN
:
npm config set cafile "<path to certificate file>"
Alternatively, the NODE_EXTRA_CA_CERTS
environment variable can be set to the certificate file.
I think that's everything I know about getting npm to work behind a proxy/firewall. May someone find it useful.
Edit: It's a really common suggestion to turn off HTTPS for this problem either by using an HTTP registry or setting NODE_TLS_REJECT_UNAUTHORIZED
. These are not good ideas because you're opening yourself up to further man-in-the-middle or redirection attacks. A quick spoof of your DNS records on the machine doing the package installation and you'll find yourself trusting packages from anywhere. It may seem like a lot of work to make HTTPS work, but it is highly recommended. When you're the one responsible for allowing untrusted code into the company, you'll understand why.
Edit 2:
Keep in mind that setting npm config set cafile <path>
causes npm to only use the certs provided in that file, instead of extending the existing ones with it.
If you want to extend the existing certs (e.g. with a company cert) using the environment variable NODE_EXTRA_CA_CERTS
to link to the file is the way to go and can save you a lot of hassle. See how-to-add-custom-certificate-authority-ca-to-nodejs
This problem was fixed for me by using http version of repository:
npm config set registry http://registry.npmjs.org/
npm config set strict-ssl false
solved the issue for me. In this case both my agent and artifact depository are behind a private subnet on aws cloud
I happened to encounter this similar SSL problem a few days ago. The problem is your npm does not set root certificate for the certificate used by https://registry.npmjs.org.
Solutions:
- Use
wget https://registry.npmjs.org/coffee-script --ca-certificate=./DigiCertHighAssuranceEVRootCA.crt
to fix wget problem - Use
npm config set cafile /path/to/DigiCertHighAssuranceEVRootCA.crt
to set root certificate for your npm program.
you can download root certificate from : https://www.digicert.com/CACerts/DigiCertHighAssuranceEVRootCA.crt
Notice: Different program may use different way of managing root certificate, so do not mix browser's with others.
Analysis:
let's fix your wget https://registry.npmjs.org/coffee-script
problem first. your snippet says:
ERROR: cannot verify registry.npmjs.org's certificate, issued by /C=US/ST=CA/L=Oakland/O=npm/OU=npm Certificate Authority/CN=npmCA/[email protected]: Unable to locally verify the issuer's authority.
This means that your wget program cannot verify https://registry.npmjs.org
's certificate. There are two reasons that may cause this problem:
- Your wget program does not have this domain's root certificate. The root certificate usually ship with system.
- The domain does not pack root certificate into his certificate.
So the solution is explicitly set root certificate for https://registry.npmjs.org
. We can use openssl to make sure that the reason bellow is the problem.
Try openssl s_client -host registry.npmjs.org -port 443
on the command line and we will get this message (first several lines):
CONNECTED(00000003) depth=1 /C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance CA-3 verify error:num=20:unable to get local issuer certificate verify return:0 --- Certificate chain 0 s:/C=US/ST=California/L=San Francisco/O=Fastly, Inc./CN=a.sni.fastly.net i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance CA-3 1 s:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance CA-3 i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA ---
This line verify error:num=20:unable to get local issuer certificate
makes sure that https://registry.npmjs.org
does not pack root certificate. So we Google DigiCert High Assurance EV Root CA
root Certificate.
I am having the same issue, I overcome using
npm config set proxy http://my-proxy.com:1080
npm config set https-proxy http://my-proxy.com:1080
Additionally info at node-doc