NPM modules won't install globally without sudo

I have just reinstalled Ubuntu 12.04 LTS, and before anything else i did these steps:

  1. Installed Node via package manager with the following script

    sudo apt-get update
    
    sudo apt-get install python-software-properties python g++ make
    
    sudo add-apt-repository ppa:chris-lea/node.js
    
    sudo apt-get update
    
    sudo apt-get install nodejs
    
  2. Tried to install yeoman, express, n, yeoman's generators globally and all of them returned the same error

    npm ERR! Error: EACCES, symlink '../lib/node_modules/n/bin/n'

    npm ERR! { [Error: EACCES, symlink '../lib/node_modules/n/bin/n'] errno: 3, code: 'EACCES', path: '../lib/node_modules/n/bin/n' }

    npm ERR!

    npm ERR! Please try running this command again as root/Administrator.

    npm ERR! System Linux 3.8.0-29-generic

    npm ERR! command "/usr/bin/node" "/usr/bin/npm" "install" "-g" "-d" "n"

    npm ERR! cwd /home/heberlz

    npm ERR! node -v v0.10.20

    npm ERR! npm -v 1.3.11

    npm ERR! path ../lib/node_modules/n/bin/n

    npm ERR! code EACCES

    npm ERR! errno 3

    npm ERR! stack Error: EACCES, symlink '../lib/node_modules/n/bin/n'

    npm ERR!

    npm ERR! Additional logging details can be found in:

    npm ERR! /home/heberlz/npm-debug.log

    npm ERR! not ok code 0

  3. Reclaimed ownership of the following folders recursively ~/.npm, /usr/lib/node, /usr/lib/node_modules, and of the following symlinks /usr/bin/node, /usr/bin/nodejs with absolutely no success

I need to install yeoman and its generators without sudo not to be in trouble later on :(


Solution 1:

Ubuntu 12.04 and using Chris Lea's PPA for install the following works for me:

npm config set prefix '~/.npm-packages'

and adding $HOME/.npm-packages/bin to $PATH

append to .bashrc

export PATH="$PATH:$HOME/.npm-packages/bin"

see https://stackoverflow.com/a/18277225 from @passy

Solution 2:

If you already have $HOME/bin in your path, a simpler solution is just ...

npm config set prefix ~
  • New node commands will now install into your $HOME/bin directory.
  • No need to change your path!

Since this discussion is really about reducing the security risks of running sudo, you should also be aware that any node app could potentially be installing an app name that does not match the registered node package name you think you're installing. So there is a security risk that an npm install will replace an existing system command or one you already have in $HOME/bin. If you're concerned, check the bin, and scripts properties in the package.json file of the app you're installing first.

In general, it's safest to:

  • (a) Place $HOME/bin last in your path so system commands are not superseded.
  • (b) don't include "." or any relative path in your $PATH so you don't accidentally run a command that happens to be in the current directory.

Reference:

  • package.json properties
  • npm install
  • NodeJS security vulnerabilities: nodesecurity.io.

Solution 3:

As for October 2014:

Node.js is available from the NodeSource Debian and Ubuntu binary distributions repository.

curl -sL https://deb.nodesource.com/setup | sudo bash -
sudo apt-get install -y nodejs

That's it.

Outdated answer:

The fastest way without using sudo is like described here by isaac

I strongly encourage you not to do package management with sudo! Packages can run arbitrary scripts, which makes sudoing a package manager command as safe as a chainsaw haircut. Sure, it's fast and definitely going to cut through any obstacles, but you might actually want that obstacle to stay there.

I recommend doing this once instead:

sudo chown -R $USER /usr/local

EDIT:

There are certain security concerns and functionality limitations regarding changing the ownership of /usr/local to the current user:

  • if there is another user on the machine who could use global npm packages - do not change the ownership of /usr/local
  • https://apple.stackexchange.com/questions/1393/are-my-permissions-for-usr-local-correct
  • https://askubuntu.com/questions/261326/is-it-safe-to-chown-usr-local

Having said that, if you want to install global module without using sudo, I don't see any better solution (from pragmatic point of view) than mentioned. Security vs easy of use is very broad topic, and there is no easy answer for that - it just depends on your requirements.

Solution 4:

The issue was i installed node using sudo, to avoid errors when installing npm modules globally one MUST NEVER install node with sudo.

My solution was to reinstall node it this way:

Download latest stable node sources from nodejs.org #in my case node-v0.10.20.tar.gz

tar -zxf node-v0.10.20.tar.gz #uncompress sources

cd node-v0.10.20 #enter uncompressed folder

sudo chown -R $USER /usr/local

./configure --prefix=/usr/local && make && make install

One thing to note is that only taking ownership of the /usr/local folder wouldn't work in my case because node installation itself was made with sudo

Last step to install yeoman: #although at yeoman.io it says that doing "npm install -g yo" already installs bower and grunt, there are some submodules of grunt that fail, so i fixed that by installing it by itself

npm install -g bower

npm install -g grunt

npm install -g yo

npm install -g generator-angular