Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Permissions error - after declaring USER and WORKDIR #740

Open
ORESoftware opened this issue May 16, 2018 · 38 comments
Open

Permissions error - after declaring USER and WORKDIR #740

ORESoftware opened this issue May 16, 2018 · 38 comments

Comments

@ORESoftware
Copy link

I have this:

FROM node:9
USER node
WORKDIR /home/node/app
COPY package.json .
RUN npm install --loglevel=warn;

and I get:

Step 20/24 : RUN  npm install --loglevel=warn;
 ---> Running in 8aa9717ac2be
npm WARN checkPermissions Missing write access to /home/node/app
npm ERR! path /home/node/app
npm ERR! code EACCES
npm ERR! errno -13
npm ERR! syscall access
npm ERR! Error: EACCES: permission denied, access '/home/node/app'
npm ERR!  { Error: EACCES: permission denied, access '/home/node/app'
npm ERR!   stack: 'Error: EACCES: permission denied, access \'/home/node/app\'',
npm ERR!   errno: -13,
npm ERR!   code: 'EACCES',
npm ERR!   syscall: 'access',
npm ERR!   path: '/home/node/app' }
npm ERR! 
npm ERR! Please try running this command again as root/Administrator.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/node/.npm/_logs/2018-05-16T17_37_34_421Z-debug.log

this seems completely crazytown. How does my user not have access to this directory by default considering it was "created" by the WORKDIR command after USER was declared?

@LaurentGoderre
Copy link
Member

If I remember correctly, folder created by WORKDIR are owned by root even if they are created after the USER directive. Try creating the folder first

@ORESoftware
Copy link
Author

Yeah I tried that too, I still get permissions errors with this:

RUN mkdir -p /home/node/app
WORKDIR /home/node/app

@serbanghita
Copy link

I have the same issue

@ORESoftware
Copy link
Author

ORESoftware commented Jun 6, 2018

Just do this and call it a day lol

 RUN sudo chmod -R 777 /home/node/app

F it lol...just run that before and after npm install and you should be g2g. Even better, do this:

 RUN sudo chmod -R 777 /home/node

@minnam
Copy link

minnam commented Jul 11, 2018

Correct me if I'm wrong. The doc is recommending us to declare user as node because Docker runs container as root by default.

So you declare it at the end

FROM node:9
WORKDIR /home/node/app
COPY package.json .
RUN npm install --loglevel=warn;
USER node

@serbanghita
Copy link

You should not run node as root, bad things can happen (see the last issue with changing files permissions).
I think you need to make sure that when the node user is created it has the right permissions over /home/node (eg. https://github.com/vvo/selenium-standalone/blob/master/Dockerfile#L29). Maybe the permissions are not well propagated to subsequent directories:

@ORESoftware do a docker exec ls -al /home/node/app and check who owns that?

@albertoantunes
Copy link

@ORESoftware i believe this issue happens because only the /home/node directory is owned by the node user in the default node image. The /app directory is created and owned by root. If you change the WORKDIR to /home/node it should work.

@0xDones
Copy link

0xDones commented Feb 11, 2019

@albertoantunes You are right, it worked for me. Here is my Dockerfile, hope it helps some with the same problem.

FROM node:8
USER node
ENV NPM_CONFIG_PREFIX=/home/node/.npm-global
ENV PATH=$PATH:/home/node/.npm-global/bin
WORKDIR /home/node
COPY package.json .
RUN npm install --only=prod
COPY . .

@samson-sham
Copy link

This has been a nightmare for me...
Can this be documented as what the Best Practice is suggesting to use USER node but doesn't provide a viable config?

@Maxime1991
Copy link

@ORESoftware
I had the same issue, you can specify the user with the COPY command. See my Dockerfile:

FROM node:latest
USER node

ARG APP=app
ARG HOME=/home/node

ENV NPM_CONFIG_PREFIX=$HOME/.npm-global
ENV PATH=$PATH:$HOME/.npm-global/bin

COPY --chown=node:node ./$APP/package*.json $HOME/$APP/

The COPY is done by default with root (source):

All new files and directories are created with a UID and GID of 0, unless the optional --chown flag specifies a given username, groupname, or UID/GID combination to request specific ownership of the copied content.

Note that COPY --chown won't work with all docker versions (see here). Mine is 18.03.1-ce.

@christyjacob4
Copy link

christyjacob4 commented Mar 6, 2019

I had the same issue and here's my Dockerfile. This fixed it

#Choose the base image for the build
FROM node:8-alpine
RUN mkdir -p /home/node/app && chown -R node:node /home/node/app
WORKDIR /home/node/app
COPY package*.json ./
USER node
RUN npm install
COPY --chown=node:node . .
RUN ["chmod", "755", "your-script.sh"]
EXPOSE 4140
CMD [ "node", "index.js" ]

The trick was to use

RUN ["chmod", "755", "your-script.sh"]

@GeorgeKagan
Copy link

GeorgeKagan commented Oct 5, 2019

This worked for me.
A combination of using the existing /home/node dir to host the app files and specifying the user and group for the COPY commands.

FROM node:12.10.0-slim

USER node
RUN mkdir -p /home/node/app
WORKDIR /home/node/app

COPY --chown=node:node package.json .
COPY --chown=node:node yarn.lock .

RUN yarn --pure-lockfile

COPY --chown=node:node . .

EXPOSE 4040

CMD [ "node", "index.js" ]

tkurki added a commit to SignalK/signalk-server that referenced this issue Oct 23, 2019
tsc fails with permission denied for writing under lib. Fixed with advice
from nodejs/docker-node#740 (comment)
@derhecht
Copy link

another working approach: start docker run with
-e npm_config_cache=/path/to/cache
and setup the folder e.g. in working dir

then I could use non-root user + get npm install working as it does not try to create a /.npm folder

@antonovicha
Copy link

I had a problem of creating files / directories while node app is running (logs directory for example, when I don't care about them and do not mount logs dir from host). Here is my solution:

RUN chown node:node /usr/src/app
USER node
CMD ["npm", "start"]

That way app can create new files / directories inside of /usr/src/app. All other files/dirs are owned by root, and can not be modified by app (totally fine for me).

@derhecht
Copy link

derhecht commented Mar 2, 2020

yes but e.g. Jenkins setup working dir in pipeline approach on its own and you cannot really/easy/good overwrite it and you have to handle a different working dir so

@antonovicha
Copy link

@derhecht Sorry did not understood completely. If your comment was addressed to me, and it meant to say: when app is built on Jenkins it causes errors because of .npm dir, then here is the solution that we are using:

environment {
  HOME = '.'
}

Also do not forget to include .npm into your .dockerignore so that its content is not sent to daemon during build (not a big deal, but still).

@ecs-hk
Copy link

ecs-hk commented Apr 23, 2020

This issue/discussion is currently the top Google hit for the terms:

docker Error: EACCES: permission denied, scandir

[ None of the solutions in this thread were the cause of my specific issue, so I'm adding a comment here. ]

In my case, I created a new LVM2 logical volume and mounted it to /var/lib/docker (i.e. so that Docker would have room to grow). Afterward, my builds began failing with the error message I quoted above. I determined the cause to be SELinux context. The fix was simply:

sudo /usr/sbin/restorecon -R /var/lib/docker

@derhecht
Copy link

may anyone could use it, we solved Jenkins Docker scripted pipeline build with the following setup/commands/variables:
docker.image('node:8').inside("-e npm_config_cache=$env.WORKSPACE/.npm") { sh "npm install && export BABEL_CACHE_PATH=$env.WORKSPACE/.babel.json && npm run build" }

@blakemorgan
Copy link

blakemorgan commented Jan 14, 2021

Note this comment in the Best Practices documentation: # At the end, set the user to use when running this image. What I ended up doing is running the Dockefile as the root user, then copying everything I need, using the --chown node:node flag in the COPY command when needed, then changing the user to node before running the application.

FROM node:14.15.4-slim
WORKDIR /home/node
COPY --from=build --chown=node:node ./ /home/node
ENV NODE_ENV="production"
ENV PORT="8080"
EXPOSE 8080
USER node
CMD ["node", "app.js"]

@mikhailrojo
Copy link

hi guys,

sometimes this happens - when the container you are trying to use (FROM) - set up the user already and it is different from the root. In this case permission is denied

adrienjoly added a commit to openwhyd/openwhyd that referenced this issue May 14, 2021
@abhaykumar01234
Copy link

This dockerfile works fine with any image but the issue comes when you try to mount the volume <current_dir>:/home/node

FROM node:latest

ENV NODE_ENV="development"
ENV PORT="4000"

WORKDIR /home/node
COPY --chown=node:node ./node_project /home/node

RUN npm install
EXPOSE ${PORT}
USER node

ENTRYPOINT ["npm", "run", "dev"]
version: "3.1"

services:
  node:
    build:
      context: .
      dockerfile: node.dockerfile
    container_name: node_server
    ports:
      - "4000:4000"
    volumes:
      - ./node_project:/home/node   ----------> this creates the issue, remove this and everything works

How to fix this? How to mount current folder as volume inside docker container?

@rod-glover
Copy link

rod-glover commented Jul 16, 2021

@abhaykumar01234 , if you build the project with the context . (where your ./node_project lives), then you don't need to mount the directory. The COPY command loads that content for you.

However ... you have to build the image each time you make a change to the code. The image contains an unchanging copy of the code as of build time.

If your objective is to have a container with "live" code changes (made from the host machine) available inside the container, then you will need a different arrangement. It's a bit complicated, and it's Friday afternoon, so I'll post some information on this on Monday.

@rod-glover
Copy link

rod-glover commented Jul 17, 2021

@abhaykumar01234 , the basic problem is that your container is using a user (in this case node, I believe) which does not map (see below) onto a user in the host that has permission to write to the directory you mounted. You get an error because the npm install writes to that directory but the user in the host doesn't have permission.

It helps to understand what "map" means here: When a Docker container is run, the users inside the container are also interpreted as users in the host. The identity of the host user is determined by the numeric user id of the user inside the container.

  • In the simplest case, which is to say without something called "user namespace mapping", the numeric id in the host is the same as the numeric id in the container. So user 0 (root) in the container maps to user 0 (root, yikes, danger!) in the host. User 1001 in the container maps to user 1001 in the host. And so on.
  • When user namespace mapping is set up in your Docker daemon, then the numeric id of a container user is mapped to a different numeric user id in the host. The mechanism is a little obscure and confusing, but that's the essence of it. See Isolate containers with a user namespace.

All solutions to this problem involve ensuring that the user inside the container maps onto a suitable user on the host. This can be done in several ways.

The simplest way is to define and use a user in the image (i.e., in the Dockerfile) whose numeric user id is the same as a host user with suitable permissions (e.g., your own user id). This is not very flexible because the user id is fixed, but if you don't need that flexibility, it's effective.

A more flexible way to do much the same thing is to specify a user id externally when you build your image. There's some good advice on this in Avoiding Permission Issues With Docker-Created Files.

A more complex but fully flexible solution to the problem is to use Docker's user namespace mapping facility. I am doing this with a couple of Python projects, and I haven't yet worked out all the kinks, but in principle it's reasonably straightforward. I found the following articles helpful:

A few other remarks:

  • If you mount the codebase to the container, then you do not need to COPY it also in the image. The mount supersedes the copy.
  • What user does your base image node:latest set for you? Is your own Dockerfile's command USER node necessary?

@hraban
Copy link

hraban commented Jul 21, 2021

Yeah I tried that too, I still get permissions errors with this:

RUN mkdir -p /home/node/app
WORKDIR /home/node/app

@ORESoftware FWIW this works for me. It fixes the permissions issue.

@herbievine
Copy link

Guys, I'm absolultly shit at Docker, I don't understand anything in this thread. Can someone please help me?

Here's my Dockerfile:

FROM node:latest

WORKDIR /usr/src/app

COPY package.json ./
COPY yarn.lock ./

RUN yarn

COPY . .
COPY .env.production .env

RUN yarn build
RUN yarn db:pull

ENV NODE_ENV production

EXPOSE 3000
CMD [ "node", "dist/main" ]

USER node

I get this error:

yarn docker:run
yarn run v1.22.10
$ docker run -p 3000:3000 blog-api
[Nest] 1  - 11/08/2021, 6:12:26 PM     LOG [NestFactory] Starting Nest application...
[Nest] 1  - 11/08/2021, 6:12:26 PM     LOG [InstanceLoader] AppModule dependencies initialized +129ms
[Nest] 1  - 11/08/2021, 6:12:26 PM     LOG [InstanceLoader] PassportModule dependencies initialized +1ms
[Nest] 1  - 11/08/2021, 6:12:26 PM     LOG [InstanceLoader] ThrottlerModule dependencies initialized +1ms
[Nest] 1  - 11/08/2021, 6:12:26 PM     LOG [InstanceLoader] JwtModule dependencies initialized +0ms
[Nest] 1  - 11/08/2021, 6:12:26 PM     LOG [InstanceLoader] ConfigHostModule dependencies initialized +0ms
[Nest] 1  - 11/08/2021, 6:12:26 PM     LOG [InstanceLoader] UsersModule dependencies initialized +1ms
[Nest] 1  - 11/08/2021, 6:12:26 PM     LOG [InstanceLoader] ConfigModule dependencies initialized +2ms
[Nest] 1  - 11/08/2021, 6:12:26 PM     LOG [InstanceLoader] AuthModule dependencies initialized +1ms
[Nest] 1  - 11/08/2021, 6:12:26 PM     LOG [InstanceLoader] PostsModule dependencies initialized +0ms
[Nest] 1  - 11/08/2021, 6:12:26 PM     LOG [InstanceLoader] CategoriesModule dependencies initialized +1ms
[Nest] 1  - 11/08/2021, 6:12:26 PM     LOG [InstanceLoader] GraphQLSchemaBuilderModule dependencies initialized +0ms
[Nest] 1  - 11/08/2021, 6:12:26 PM     LOG [InstanceLoader] GraphQLModule dependencies initialized +1ms
node:internal/process/promises:246
          triggerUncaughtException(err, true /* fromPromise */);
          ^

[Error: EACCES: permission denied, open '/usr/src/app/schema.gql'] {
  errno: -13,
  code: 'EACCES',
  syscall: 'open',
  path: '/usr/src/app/schema.gql'
}

@rod-glover
Copy link

rod-glover commented Nov 8, 2021

@herbievine , I think your problem is that WORKDIR creates the working directory as root, but the process is running as user node when you run the CMD. (Pretty sure the default user for the image node -- your base image -- is user node.) This means that GraphQL (or anything else) can't create files in the working directory, which is what appears to be problem here.

The likely fix is to explicitly create the WORKDIR directory and give it correct ownership and permissions before you select it as WORKDIR. You may need to do this as root:

USER root
# Do stuff ...
USER node

Don't stay as user root for the rest of the image, it exposes a lot of security vulnerabilities and you DO NOT want that.

@thajib
Copy link

thajib commented Nov 10, 2021

I added 'user: node' on my docker-compose.yml and it fixed the issue.

version: '3'
services:
  app-name:
    user: node

@rod-glover
Copy link

@thajib , that means your container will be running all its commands as the root user -- both inside the container and outside the container (unless, for the latter, you have set up user namespace mapping). This exposes you to serious security risks unless you are running the container entirely behind a firewall with no outside access to it. Even then, it's not a good idea; anyone inside your firewall can docker exec into the container and from there they have root privilege on your system(s), and can effectively do anything.

That's the reason the node image gives you a default non-root user (named node).

For further information on this, search things like "Docker best practices security".

@thajib
Copy link

thajib commented Nov 11, 2021

I have corrected it now. I intended to use 'node' and I typed 'root' :-(

@dgleba
Copy link

dgleba commented Jan 8, 2022

I made a few example docker and compose files and I found the following.

For volume mount where the folders don't exist before running the container gets folders made as root. This means no non-root user permissions to that folder or subfolders.

Making the folders to be mounted in the host before running the container means the permissions will be preserved in the container by user ID. Permission granted.

Minimal example:

Dockerfile:

FROM node:16-slim
USER node
CMD ["yarn", "serve"]

Bash code:

export iiname=userdocker_aa; echo ${PWD}; 
docker rmi $iiname
docker build -t $iiname .
#
runa() {
    echo $1; echo iiname=$iiname
    docker run --rm -v "${PWD}/$1:/$1" -w "/$1"  -it $iiname sh -c "touch afile;"
}
# error: touch: cannot touch 'afile': Permission denied
    ls -l code; runa code
# Works!
    mkdir code2; runa code2; ls -laR;

Output:

code/ doesn't exist before running and gets root permissions. Cannot touch the file. touch: cannot touch 'afile': Permission denied

code2/ is created before running and has host user permissions. Can touch file.

albe@racknerd-4f4016:/ap/dkr/605dkrcollection/userdocker/u7$ bash sha
/ap/dkr/605dkrcollection/userdocker/u7
Untagged: userdocker_aa:latest
Deleted: sha256:677eddefff16ad91a8fa95f40992720bbb4f49f38ad155312fff8c05e9ff234f
Sending build context to Docker daemon  4.608kB
Step 1/3 : FROM node:16-slim
 ---> 13cc87dcb313
Step 2/3 : USER node
 ---> Using cache
 ---> 5d28a19d291f
Step 3/3 : CMD ["yarn", "serve"]
 ---> Running in faba7178762b
Removing intermediate container faba7178762b
 ---> a29162820ea8
Successfully built a29162820ea8 Successfully tagged userdocker_aa:latest
code
iiname=userdocker_aa
touch: cannot touch 'afile': Permission denied
mkdir: cannot create directory ‘code2’: File exists
code2
iiname=userdocker_aa
drwxr-xr-x 2 root root 4096 Jan  8 13:35 code
drwxrwxr-x 2 albe albe 4096 Jan  8 13:35 code2
./code2:
drwxrwxr-x 2 albe albe 4096 Jan  8 13:35 .
drwxrwxr-x 4 albe albe 4096 Jan  8 13:36 ..
-rw-r--r-- 1 albe albe    0 Jan  8 13:37 afile

So I think a solution is to create ./app on the host and mount that as a volume with -v "${PWD}/app://home/node/app.
If the host user and the container user are both ID=1000 then the permissions match. On Debian systems the first user is given ID=1000, but you can create users with an assigned ID if need be.

All the code is here: https://github.com/dgleba/605dkrcollection/tree/main/userdocker/u7

@salehhoushangi
Copy link

I know this is old poet but below code worked for me:
FROM node:14.16.0-alpine3.13

RUN addgroup app && adduser -S -G app app
RUN mkdir -p /app && chown -R app:app /app
USER app
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .

EXPOSE 3000

CMD ["npm", "start"]

@iglizar
Copy link

iglizar commented Apr 15, 2022

Correct me if I'm wrong. The doc is recommending us to declare user as node because Docker runs container as root by default.

So you declare it at the end

FROM node:9
WORKDIR /home/node/app
COPY package.json .
RUN npm install --loglevel=warn;
USER node

Thank you so much! This really solved my problem!

@lgrachov
Copy link

I know WORKDIR permissions

@marcosaguilera-glober
Copy link

marcosaguilera-glober commented Sep 5, 2022

I was getting same issue:
# EACCES: permission denied, mkdir '/root/.cache/Cypress'

I've fixed like this:

  1. In my Dockerfile
#Cypress version using
FROM cypress/included:10.6.0

# Installing sudo for superower installation required
# into entrypoint.sh
RUN apt-get install sudo

# Directories actions
WORKDIR /home/pwsh/tempVolume

ENTRYPOINT ["/bin/sh", "./entrypoint.sh"]
  1. In my entrypoint.sh script file
#!/bin/sh
echo "I'm into the sh file"

## Install packages defined into package.json > dependencies node
##npm install
sudo npm install --unsafe-perm=true --allow-root

## Run cypress
cypress run

I messed up a time with this issue, and I tried with permissions chown node:node, also some chmod -R 777, but nothing worked for me, so I installed apt-get install sudo into Linux distro given superpowers to handle internally the permissions. Maybe is unorthodox but, worked for me.

Hope this help anyone.

@ryepup
Copy link

ryepup commented Jan 5, 2023

I was able to solve this with a newer docker backend component called buildkit. Buildkit mode is enabled by default for Docker Desktop users, and can be enabled manually by setting an environment variable when building the image:

DOCKER_BUILDKIT=1 docker build ...

Buildkit creates directories a little differently. Say we have a dockerfile that just prints out details of the WORKDIR:

FROM node:18-alpine
USER node
WORKDIR /app
CMD stat /app

Without buildkit, the WORKDIR is owned by root:

$ docker build --quiet . -t demo
sha256:28817c441bf181fa589ed827acc08bed54605977f26c46b4923e69da2261d21d
$ docker run --rm demo
  File: /app
  Size: 4096      	Blocks: 8          IO Block: 4096   directory
Device: 93h/147d	Inode: 22454774    Links: 2
Access: (0755/drwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
...

With buildkit, the WORKDIR is owned by our USER:

$ DOCKER_BUILDKIT=1 docker build --quiet . -t demo
sha256:37ae7418d59cba2024bff10c798f6577b1de84ddd8a275d12b63cad19554d759
$ docker run --rm demo
  File: /app
  Size: 4096      	Blocks: 8          IO Block: 4096   directory
Device: 8dh/141d	Inode: 22558956    Links: 2
Access: (0755/drwxr-xr-x)  Uid: ( 1000/    node)   Gid: ( 1000/    node)
...

When the WORKDIR is owned by the USER, any further RUN commands that want to create files in the WORKDIR will have enough permissions.

@hafidousbaa
Copy link

i get the same error when i want to build the image used podman on my runner when i run my pipeline show
STEP 4: RUN npm install -g npm@9.6.0
exec /bin/sh: permission denied
Error: error building at STEP "RUN npm install -g npm@9.6.0": error while running runtime: exit status 1

@ghost
Copy link

ghost commented Jun 25, 2023

I'm not sure if it's the same issue, but I've stumble upon this GitHub issue trying to find out what's happening with my NestJS app. When trying to start development mode, Nest tries to rmdir the dist/ folder, but it stops because of permission denied, even with user being specified in the compose file and in the Docker file.

https://stackoverflow.com/q/76544048/7443903

@jeffkeilman
Copy link

This worked for me. A combination of using the existing /home/node dir to host the app files and specifying the user and group for the COPY commands.

FROM node:12.10.0-slim

USER node
RUN mkdir -p /home/node/app
WORKDIR /home/node/app

COPY --chown=node:node package.json .
COPY --chown=node:node yarn.lock .

RUN yarn --pure-lockfile

COPY --chown=node:node . .

EXPOSE 4040

CMD [ "node", "index.js" ]

Years later, you are helping me when several guides from well-known tech companies have failed. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests