Closed guidev closed 2 years ago
I'm trying to update my app to use node16 (currently on node14) on elastic beanstalk.
npm ERR! sharp: Installation error: EACCES: permission denied, mkdir '/root/.npm'
Did you see this question in the issue template?
Is this a problem with filesystem permissions?
If you are using npm v7 or later, does the user running
npm install
own the directory it is run in?
There was a breaking change between npm v6 (Node.js 14) and npm v8 (Node.js 16) relating to filesystem permissions.
ok, so the issue is that /var/app/staging
is owned by webapp
ls -la /var/app/
total 0
drwxr-xr-x 3 root root 21 May 10 17:35 .
drwxr-xr-x 23 root root 327 May 10 17:35 ..
drwxr-xr-x 8 webapp webapp 226 May 10 17:36 staging
npm install
is instead run by root
I'm still unsure on how to fix it, I don't believe elastic beanstalk allows to change which user runs which command...
Another user had the same issue: https://stackoverflow.com/questions/72179711/sharp-js-dependency-breaks-express-server-on-elastic-beanstalk#
It's been a while (c2014) since I last used Elastic Beanstalk, but I remember having to maintain a lot of shell scripts to do anything, hopefully things have improved since then.
Does running npm install
as the webapp
user help?
sudo -H -u webapp npm install
Alternatively, does changing the filesystem ownership to root
before running npm install
work?
chown -R root.root /var/app/staging
I'd like to stress that this problem is caused by a breaking change in npm v8 and not sharp. This problem will affect all native Node.js modules, including sharp, esbuild, etc.
Hello @guidev ,
I recently found a workaround solution for this error when assisting an AWS customer migrate their environment from Amazon Linux 1 to Amazon Linux 2 using the following Platform Version ("Node.js 16 AL2 version 5.5.2") & Solution Stack Name ("64bit Amazon Linux 2 v5.5.2 running Node.js 16"). I was able to reproduce the error and confirm the deployment was successful in my own test environment.
As mentioned by @lovell , the problem is caused by a breaking change in the npm version. Additionally, the error experienced can be considered an application level dependency problem which falls outside of the AWS Support Scope since it is borderline viewed as "Code development" and/or "Debugging custom software". Please note that AWS Support Engineers help with solutions for technical issues with respect to AWS services and infrastructure. Any assistance provided outside of the support scope is on a "best efforts" basis!
Solution: Step 1: Create the following Platform Hooks paths in the root directory of your application bundle.
- .platform/hooks/prebuild
- .platform/confighooks/prebuild
The Platform Hook (.platform/hooks/prebuild) will execute the commands found in the bash script after the application is extracted but before the application configuration and proxy server process initiates.
The Platform Hook (.platform/confighooks/prebuild) will execute the commands found in the bash script during a configuration deployment/environment update.
Please reference the AWS Elastic Beanstalk Documentation, "Instance Deployment Workflow" for more insight.
Step 2: Once the above Platform Hooks paths have been created in your application bundle, the following bash script (00_npm_install.sh) will need to be created and placed under the "Prebuild" directory:
The bash script (00_npm_install.sh) will include the following:
#!/bin/bash
cd /var/app/staging
sudo -u webapp npm install sharp
Please make sure the bash script (00_npm_install.sh) file has execute permissions by using chmod +x
.
Example:
chmod +x 00_npm_install.sh
OR
chmod +x .platform/hooks/prebuild/00_npm_install.sh
chmod +x .platform/confighooks/prebuild/00_npm_install.sh
*The above command is dependent on your current working directory. Overall, the bash script should have the following permissions -rwxr-xr-x
.
Step 3: Validate the Application Bundle Structure
Sample project structure:
~/my-app/
├── app.js
├── index.html
├── .npmrc_bkp
├── package.json
├── package-lock.json
├── .platform
│ ├── confighooks
│ │ └── prebuild
│ │ └── 00_npm_install.sh
│ └── hooks
│ └── prebuild
│ └── 00_npm_install.sh
└── Procfile
Step 4: Deploy the Application!
Summary:
During the application deployment process, the application bundle is initially extracted and deployed within the /var/app/staging
folder. In this same first step, all Node.js dependencies found in your (package.json) file will also be installed here but exist under /var/app/staging/node_modules/...
.
As mentioned in your comment, the /var/app/staging
folder is owned by the webapp
user but the npm install
command is executed by root
user. Therefore, the bash script workaround solution goes to the /var/app/staging/
directory and install the Sharp
dependency by executing the sudo -u webapp npm install sharp
command as the webapp
user. All of this is done before the application and proxy server configuration process initiates as shown in "Instance deployment workflow".
As a result, the workaround solution will make the Elastic Beanstalk deployment process skip installing the Sharp
dependency all together as it already exists! Afterwards, the application deployment process continues to the final provisioning step which moves all files/content from the /var/app/staging/
folder to the final /var/app/current/
directory location.
Lastly, the second Platform Hook (.platform/confighooks/prebuild) was implemented to avoid running into the same permissions error when performing a configuration
deployment. A configuration deployment occurs when you make configuration changes that only update environment instances without recreating them!
Hope the following solution helps!
Hello @guidev ,
I recently found a workaround solution for this error when assisting an AWS customer migrate their environment from Amazon Linux 1 to Amazon Linux 2 using the following Platform Version ("Node.js 16 AL2 version 5.5.2") & Solution Stack Name ("64bit Amazon Linux 2 v5.5.2 running Node.js 16"). I was able to reproduce the error and confirm the deployment was successful in my own test environment.
As mentioned by @lovell , the problem is caused by a breaking change in the npm version. Additionally, the error experienced can be considered an application level dependency problem which falls outside of the AWS Support Scope since it is borderline viewed as "Code development" and/or "Debugging custom software". Please note that AWS Support Engineers help with solutions for technical issues with respect to AWS services and infrastructure. Any assistance provided outside of the support scope is on a "best efforts" basis!
Solution: Step 1: Create the following Platform Hooks paths in the root directory of your application bundle.
- .platform/hooks/prebuild - .platform/confighooks/prebuild
The Platform Hook (.platform/hooks/prebuild) will execute the commands found in the bash script after the application is extracted but before the application configuration and proxy server process initiates.
The Platform Hook (.platform/confighooks/prebuild) will execute the commands found in the bash script during a configuration deployment/environment update.
Please reference the AWS Elastic Beanstalk Documentation, "Instance Deployment Workflow" for more insight.
Step 2: Once the above Platform Hooks paths have been created in your application bundle, the following bash script (00_npm_install.sh) will need to be created and placed under the "Prebuild" directory:
The bash script (00_npm_install.sh) will include the following:
#!/bin/bash cd /var/app/staging sudo -u webapp npm install sharp
Please make sure the bash script (00_npm_install.sh) file has execute permissions by using
chmod +x
.Example:
chmod +x 00_npm_install.sh OR chmod +x .platform/hooks/prebuild/00_npm_install.sh chmod +x .platform/confighooks/prebuild/00_npm_install.sh
*The above command is dependent on your current working directory. Overall, the bash script should have the following permissions
-rwxr-xr-x
.Step 3: Validate the Application Bundle Structure
Sample project structure:
~/my-app/ ├── app.js ├── index.html ├── .npmrc_bkp ├── package.json ├── package-lock.json ├── .platform │ ├── confighooks │ │ └── prebuild │ │ └── 00_npm_install.sh │ └── hooks │ └── prebuild │ └── 00_npm_install.sh └── Procfile
Step 4: Deploy the Application!
Summary:
During the application deployment process, the application bundle is initially extracted and deployed within the
/var/app/staging
folder. In this same first step, all Node.js dependencies found in your (package.json) file will also be installed here but exist under/var/app/staging/node_modules/...
.As mentioned in your comment, the
/var/app/staging
folder is owned by thewebapp
user but thenpm install
command is executed byroot
user. Therefore, the bash script workaround solution goes to the/var/app/staging/
directory and install theSharp
dependency by executing thesudo -u webapp npm install sharp
command as thewebapp
user. All of this is done before the application and proxy server configuration process initiates as shown in "Instance deployment workflow".As a result, the workaround solution will make the Elastic Beanstalk deployment process skip installing the
Sharp
dependency all together as it already exists! Afterwards, the application deployment process continues to the final provisioning step which moves all files/content from the/var/app/staging/
folder to the final/var/app/current/
directory location.Lastly, the second Platform Hook (.platform/confighooks/prebuild) was implemented to avoid running into the same permissions error when performing a
configuration
deployment. A configuration deployment occurs when you make configuration changes that only update environment instances without recreating them!Hope the following solution helps!
Thanks @jceduar for the detailed explanation, your solution worked like a charm!!
@jceduar your solution works correctly. Most answers online must be referring to the previous Linux AMI version where .ebextensions or .npmrc worked as expected. I also had several old projects which were deployed this way. I recently started a new project by copying the skeleton of one of the previous ones, but could not deploy due to this problem. You saved my life. This reply needs more upvotes/hearts and someone who has enough reputation should also submit this solution on stackoverflow :)
@jceduar, thanks a ton for taking the time to investigate and post a solution! I'm sure you saved me MANY hours!! Your solution cleanly addressed the issue :-)
After clearing the above hurdle, I did run into one minor speedbump where npm was ENOMEM'ing after adding sharp to my package. I was on t2.small, and same issue for t2.med. Once bumped up to t2.large, deployment went smoothly, and I verified sharp package works. This was just a side app inside clean nestjs install that I used to validate above solution works. My real service runs on graviton t4g.med, and I had no such issues so not going to bother finding work around to the mem issue. I've read that some folks configure a swap file when running into this problem with other packages when deploying to beanstalk.
@guidev thanks for the tip!
It made my life easier when I deploy directus9 to elasticbeanstalk :) 💪
Even if https://github.com/lovell/sharp/issues/3221#issuecomment-1126783576 works, it's a pretty bad situation that users of Beanstalk have to resort to shims to get a fundamental situation like installing dependencies working. I don't mean to disparage the work of the author, it's very helpful seeing the solution and understanding what's going on... but basically AWS Beanstalk doesn't work for Node 16; and to cope, we have to duplicate our dependencies... It's very easy now to forget to update a dependency in the shim, or future dependencies could have the same issue leading to another wild-goose-chase on deploy (I saw this issue from the @sentry npm module).
Does anyone know if Amazon is working on a solution here?
@jeremyisatrecharm having used elastic beanstalk for 5 years, I'm pretty sure that this is something they won't fix for a long time. Because of this, I think the @guidev 's solution deserves a praise.
However, I agree with you on the fact that one can easily forget to update the beanstalk platform scripts and fail a deployment. sudo -u webapp npm install sharp
must be installing the latest version of sharp, which then could be incompatible with the node version you are using on elastic beanstalk. This is really prone to error.
Off the top of my head, I thought of a solution for this. For the sake of example, let's exemplify the case where we use zip files for elastic beanstalk deployments.
For each of my projects that I deploy to Elastic beanstalk, I have a script called make_zip.sh
which simply zips the directory by excluding some unwanted files/folders. It is really a single line script now. You could have a script like this, but before the zipping operation, you can call a nodejs script which checks package-lock.json
or (yarn.lock
) to learn the specific version of sharp installed, and update the two elastic beanstalk platform scripts to install that specific version. Taking it one step further, you might also advance the script to be able to understand from the lock file which packages need a prebuild stage (and therefore will choke on elastic beanstalk) and add all those packages to the beanstalk platform scripts.
I myself have not implemented anything like this (frankly, I just imagined this when I read your comment), but I sure see how this can be implemented. If you use github to deploy to elastic beanstalk, the same effect can be achieved by using git pre-commit hooks. The node script that I described above can be a pre-commit hook which will make sure that the beanstalk platform scripts are always aligned with the package versions in the lock file.
@tolgaatam thanks for the reply. That's very discouraging that you don't think AWS will fix. Basically, in my mind, this means AWS Node is broken and if AWS won't fix this, I guess I'd discourage folks from using it. I think your solution is also clever, but I also don't think piling on scripts to fix ...basic npm use... should be the solution here. Amazon should just fix their beanstalk deploy situation or we should use another solution from the provider that cares about their users (Render was neat but I needed a higher level of customization).
Feb 2023, and AWS has still not fixed this issue
I'm going to lock this issue as it is the responsibility of AWS to fix and improve their own systems.
For anyone visiting with problems relating to Elastic Beanstalk due to npm v8 dropping root/sudo privileges when running scripts, the "solution" is in https://github.com/lovell/sharp/issues/3221#issuecomment-1126528844
UPDATE: This is due to a breaking change in npm v8 that conflicts with Elastic Beanstalk, and is unrelated to sharp. Please see https://github.com/lovell/sharp/issues/3221#issuecomment-1126528844 provided by an AWS employee for a possible workaround.
Hello, I'm trying to update my app to use node16 (currently on node14) on elastic beanstalk.
Unfortunately sharp fails to install with this error:
npm ERR! code 1 npm ERR! path /var/app/staging/node_modules/sharp npm ERR! command failed npm ERR! command sh -c (node install/libvips && node install/dll-copy && prebuild-install) || (node install/can-compile && node-gyp rebuild && node install/dll-copy) npm ERR! sharp: Are you trying to install as a root or sudo user? Try again with the --unsafe-perm flag npm ERR! sharp: Please see https://sharp.pixelplumbing.com/install for required dependencies npm ERR! sharp: Installation error: EACCES: permission denied, mkdir '/root/.npm'
I have unsafe-perm on via this config file:
.npmrc unsafe-perm=true
I've also tried manually running
sudo npm --production install --unsafe-perm
inside/var/app/staging
but it fails with the same error.Here's the full eb-engine.log:
Possible install-time or require-time problem
npm install
is the same as the architecture and platform of Node.js used at runtime.Are you using the latest version of sharp?
sharp
as reported bynpm view sharp dist-tags.latest
.If you cannot confirm this, please upgrade to the latest version and try again before opening an issue.
If you are using another package which depends on a version of
sharp
that is not the latest, please open an issue against that package instead.Is this a problem with filesystem permissions?
If you are using npm v6 or earlier and installing as a
root
orsudo
user, have you tried with thenpm install --unsafe-perm
flag?If you are using npm v7 or later, does the user running
npm install
own the directory it is run in?If you are using the
ignore-scripts
feature ofnpm
, have you tried with thenpm install --ignore-scripts=false
flag?What is the complete output of running
npm install --verbose --foreground-scripts sharp
in an empty directory?What is the output of running
npx envinfo --binaries --system --npmPackages=sharp --npmGlobalPackages=sharp
?System: OS: Linux 4.14 Amazon Linux 2 CPU: (2) x64 Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz Memory: 1.47 GB / 1.91 GB Container: Yes Shell: 4.2.46 - /bin/bash Binaries: Node: 16.14.2 - /usr/bin/node npm: 8.5.0 - /usr/bin/npm npmPackages: sharp: ^0.30.4 => 0.30.4