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

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.

29890 次浏览

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

We need to do 2 things here.

First one: If you do not already have a .ebextensions folder in the root of your project, create it. Then create a file in .ebextensions named 01_fix_permissions.config.

Then secondly Enable PROXY set -xe and /opt/elasticbeanstalk/bin/healthd-track-pidfile --proxy nginx

files:
"/opt/elasticbeanstalk/hooks/appdeploy/pre/49_change_permissions.sh":
mode: "000755"
owner: root
group: root
content: |
#!/usr/bin/env bash
sudo chown -R ec2-user:ec2-user tmp/
set -xe
/opt/elasticbeanstalk/bin/healthd-track-pidfile --proxy nginx

i fixed with aws configuration on instance. t2.micro => t2.small or larger one. enter link description here

My team and I were able to get this working on an Amazon NodeJS machine by overriding some of the configuration in the script that initializes the service. This essentially overwrites the included aws node run configuration with the exact same script and a couple of extra commands. This is a file you would place under .ebextensions

files:
"/opt/elasticbeanstalk/hooks/appdeploy/pre/50npm.sh":
mode: "000755"
owner: root
group: root
content: |
#!/bin/bash
#==============================================================================
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Amazon Software License (the "License"). You may not use
# this file except in compliance with the License. A copy of the License is
# located at
#
#       http://aws.amazon.com/asl/
#
# or in the "license" file accompanying this file. This file is distributed on
# an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or
# implied. See the License for the specific language governing permissions
# and limitations under the License.
#==============================================================================


chmod 777 -R /tmp
set -xe


sudo /opt/elasticbeanstalk/containerfiles/ebnode.py --action npm-install

In my case, solved by setting "unsafe-perm=true" in "~/.npmrc"

I needed to create & commit both a .npmrc file and a .ebextensions/01-permissions.config file to resolve this:

www$ cat .npmrc
# Force npm to run node-gyp also as root, preventing permission denied errors in AWS with npm@5
unsafe-perm=true
www$ cat .ebextensions/01-permissions.config
files:
"/opt/elasticbeanstalk/hooks/appdeploy/pre/49_change_permissions.sh":
mode: "000755"
owner: root
group: root
content: |
#!/usr/bin/env bash
sudo chown -R ec2-user:ec2-user tmp/
www$