Beanstalk: Node.js deployment - node-gyp fails due to permission denied

Jakub Holý picture Jakub Holý · Sep 1, 2017 · Viewed 21.2k times · Source

Deployment of a Node.js application (Node 6, npm 5) to Beanstalk fails with:

gyp ERR! stack Error: EACCES: permission denied, mkdir '/tmp/deployment/application/node_modules/heapdump/build'

though the error is not package-specific, any node-gyp call fails.

The ERROR event in the AWS Console reads:

[Instance: i-12345] Command failed on instance. Return code: 1 Output: (TRUNCATED).../opt/elasticbeanstalk/containerfiles/ebnode.py", line 180, in npm_install raise e subprocess.CalledProcessError: Command '['/opt/elasticbeanstalk/node-install/node-v6.10.0-linux-x64/bin/npm', '--production', 'install']' returned non-zero exit status 1. Hook /opt/elasticbeanstalk/hooks/appdeploy/pre/50npm.sh failed. For more detail, check /var/log/eb-activity.log using console or EB CLI.

and eb-activity.log contained the aforementioned npm error.

The application was deployed manually by uploading a .zip file that did not include node_modules. I.e. it was not deployed via the eb command-line tool.

Answer

Jakub Holý picture Jakub Holý · Sep 1, 2017

Solution

The solution is to add the file .npmrc to the application with the content:

# Force npm to run node-gyp also as root, preventing permission denied errors in AWS with npm@5
unsafe-perm=true

(Or configuring npm so in any other way. (Though setting npm_config_unsafe_perm=true in /opt/elasticbeanstalk/env.vars did not work for me.)

Explanation

npm install is run by the root user but the node-gyp process it triggers for some packages is run by the default user ec2-user. This user lacks access to the /tmp/deployment/application/node_modules/ directory created by the npm install run and owned by root. (And it likely also lacks access to /tmp/.npm and /tmp/.config created by the same.) By enabling unsafe-perm we force npm to run node-gyp also as root, avoiding the problem.

(Personally I would prefer to run all as ec2-user rather than root but I guess that would be more involved :-))

Credits

unreal0 has pointed me to the solution

Related questions