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
Most of these tools have an option to disable strict SSL certificate checking, which let you get around the problem: npm config strict-ssl false. git config --global http. sslverify false.
When ssl certificate problem unable to get local issuer certificate error is caused by a self-signed certificate, the fix is to add the certificate to the trusted certificate store. Open the file ca-bundle. crt located in the directory above, then copy and paste the Git SSL certificate to the end of the file.
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>"
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
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
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With