Docker-node: Permission issues with the default non-root user on npm start

Created on 13 Jan 2019  Â·  11Comments  Â·  Source: nodejs/docker-node

While building a hello-world application using node as the base image, I encountered this boot time (while running npm start) problem with the default non-root user's file permissions:

...
/webapp/node_modules/mkdirp/index.js:90
                    throw err0;
                    ^

Error: EACCES: permission denied, mkdir '/webapp/node_modules/.cache'
    at Object.mkdirSync (fs.js:775:3)
    at sync (/webapp/node_modules/mkdirp/index.js:71:13)
    at sync (/webapp/node_modules/mkdirp/index.js:77:24)
    at sync (/webapp/node_modules/mkdirp/index.js:77:24)
    at save (/webapp/node_modules/@babel/register/lib/cache.js:50:20)
    at internalTickCallback (internal/process/next_tick.js:70:11)
    at process._tickCallback (internal/process/next_tick.js:47:5)
    at Function.Module.runMain (internal/modules/cjs/loader.js:777:11)
    at executeUserCode (internal/bootstrap/node.js:342:17)
    at startExecution (internal/bootstrap/node.js:276:5)
    at startup (internal/bootstrap/node.js:227:5)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:743:3)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
...

The Dockerfile is below.

Notice the commented out command which changes the node user as the owner of the application working directory. That – obviously – fixes the permission issue.

FROM node:alpine

ENV FRONT_URL=http://localhost:5000

WORKDIR /webapp

COPY package.json .
RUN npm install

COPY config.js index.js logs.txt ./
COPY server ./server

EXPOSE 8000

# This fixes the problem
# RUN chown -R node: /webapp
USER node
CMD ["npm", "start"]

I'm not that familiar with Node so that I'd have intuition on whether this is related to some package in the packages.json or is this problem related to this project (though the stack trace looks like this is related to the npm internals).

Most helpful comment

If I remember correctly, if the WORKDIR command has to create a folder, it creates it as root so you can instead do

USER node

RUN mkdir /home/node/webapp

WORKDIR /home/node/webapp

All 11 comments

I guess you should place your app in a folder that is owned by the executing user or writable, e.g. /home/node/webapp.

see also https://github.com/nodejs/docker-node/issues/603#issuecomment-354765372

@CCFenner that doesn't seem to solve the problem. Here's a Dockerfile with the suggested working directory. Running the commented out chown command fixes the problem again.

FROM node:alpine

ENV FRONT_URL=http://localhost:5000

WORKDIR /home/node/webapp

COPY package.json .
RUN npm install

COPY config.js index.js logs.txt ./
COPY server ./server

EXPOSE 8000

# This, again, fixes the problem
# RUN chown -R node: /home/node/webapp
USER node
CMD ["npm", "start"]

If you are working in the user context you should be able to switch to user node in the beginning. Maybe that solves the permission issues.

@mremes all of the COPY in your docker are run as root so the files created are owned by root. The USER directive should be before the WORKDIR command.

If I remember correctly, if the WORKDIR command has to create a folder, it creates it as root so you can instead do

USER node

RUN mkdir /home/node/webapp

WORKDIR /home/node/webapp

@mremes a bit of nitpick too but the port in your env var doesn't match the port you expose. Is that intentional?

@CCFenner that intuitively should work (as the workdir should get created by the USER user) but it errors on build-time as npm install doesn't have permissions to install locally.

@LaurentGoderre that worked out, cool! The only thing is that that's not a documented practice. As it seems there are multiple, obvious ways to make it work. So my primary concern is with the documentation as it states that

FROM node:6.10.3
...
# **At the end**, set the user to use when running this image
USER node

So now it boils down to selecting the practice to document. I'm neither familiar with the contribution guidelines or the underlying parent Dockerfiles so if someone more close to the project can fix this, then that'd good.

RE nitpick: FRONT_URL is not related to the exposed port but is an endpoint URL (frontend server) to be whitelisted by that application (backend server) for CORS purposes.

It's fun to see that all this discussion spurred from my course assignment. I hope "fixing" this will result someone avoiding encountering this 😄

IMHO it should probably be

FROM node

# Perform root tasks such as install OS package (via apt or APK)

USER node

# Copy your app and install your node dependencies

Unless the app needs to modify its own source at runtime (which is almost never the case), it's a better practice to install as root.

@pecho that was the original problem though. When code and modules are installed as root you get tons of permission issues.

Guys there is a way to solve this in Docker.

https://docs.docker.com/engine/reference/builder/#copy

e.g.
COPY --chown=node:node --from=build-image /home/node/app/remove_source_maps.sh /home/node/app/

Was this page helpful?
0 / 5 - 0 ratings

Related issues

danbev picture danbev  Â·  3Comments

eyaylagul picture eyaylagul  Â·  3Comments

dionysiusmarquis picture dionysiusmarquis  Â·  3Comments

kmetsalu picture kmetsalu  Â·  5Comments

mtibben picture mtibben  Â·  3Comments