178

I'm trying to mount a volume in docker-compose to apache image. The problem is, that apache in my docker is run under www-data:www-data but the mounted directory is created under root:root. How can I specify the user of the mounted directory?

I tried to run command setupApacheRights.sh. chown -R www-data:www-data /var/www but it says chown: changing ownership of '/var/www/somefile': Permission denied

services:
    httpd:
        image: apache-image
        ports:
            - "80:80"
        volumes:
            - "./:/var/www/app"
        links:
            - redis
        command: /setupApacheRights.sh

I would prefer to be able to specify the user under which it will be mounted. Is there a way?

simPod
  • 11,498
  • 17
  • 86
  • 139

6 Answers6

86

To achieve the desired behavior without changing owner / permissions on the host system do the following steps.

  1. get the ID of the desired user and or group you want the permissions to match with executing the id command on your host system - this will show you the uid and gid of your current user and as well all IDs from all groups the user is in.

     $ id
    
  2. add the definition to your docker-compose.yml

     user: "${UID}:${GID}"
    

    so your file could look like this

     php: # this is my service name
         user: "${UID}:${GID}" # we added this line to get a specific user / group id
         image: php:7.3-fpm-alpine # this is my image
     # and so on
    
  3. set the values in your .env file

     UID=1000
     GID=1001
    

3a. Alternatively you can extend your ~/.bashrc file with:

    export UID GID

to define it globally rather than defining it in a .env file for each project. If this does not work for you (like on my current distro, the GID is not set by this, use following two lines:

    export UID=$(id -u)
    export GID=$(id -g)

Thanks @SteenSchütt for the easy solution for defining the UID / GID globally.

Now your user in the container has the id 1000 and the group is 1001 and you can set that differently for every environment.

Note: Please replace the IDs I used with the user / group IDs you found on your host system. Since I cannot know which IDs your system is using I gave some example group and user IDs.

If you don't use docker-compose or want to know more different approaches to achieve this have a read through my source of information: https://dev.to/acro5piano/specifying-user-and-group-in-docker-i2e

If the volume mount folder does not exist on your machine, docker will create it (with root user), so please ensure that it already exists and is owned by the userid / groupid you want to use.

I add an example for a dokuwiki container to explain it better:

version: '3.5'
services:
  dokuwiki:
    user: "${UID}" # set a specific user id so the container can write in the data dir
    image: bitnami/dokuwiki:latest
    ports:
      - '8080:8080'
    volumes:
      - '/home/manuel/docker/dokuwiki/data:/bitnami/dokuwiki/'
    restart: unless-stopped
    expose:
      - "8080"

The dokuwiki container will only be able to initialize correctly if it has write access to the host directory /home/manuel/docker/dokuwiki/data.

If on startup this directory does not exist, docker will create it for us but it will have root:root as user & group. --> Therefor the container startup will fail.

If we create the folder before starting the container

mkdir -P /home/manuel/docker/dokuwiki/data

and then check with

ls -nla /home/manuel/docker/dokuwiki/data| grep ' \.$'

which uid and gid the folder has - and check that they match the ones we put in our .env file in step 3. above.

Manuel Manhart
  • 4,819
  • 3
  • 24
  • 28
  • 4
    In my case, the container won't discover its name, as the www-data user has gid and uid of 33. this leads to other problems for me. – k0pernikus Jul 21 '20 at 09:16
  • 1
    Not working for me (version 3.7). I had to create a new group 1000 on my host machine and add my user to the group 1000. – bpile Jan 03 '21 at 11:11
  • @bpile I updated the answer with a lookup for finding already existing group ids before updating docker. – Manuel Manhart Jan 28 '21 at 15:34
  • It's working for a single user:group but is it possible to setting up multiple groups this way ? – Dr Claw Sep 29 '21 at 13:27
  • This is for the main group of the user. Additional groups cannot be setup with this. Also this sounds like a completely different use case to me, if you have such requirements, my guess is, that you made your own docker image anyways. You can always create new groups with `groupadd -g 1010 mygroup` or change the gid for existing groups with `groupmod -g 1010 mygroup`. If this does not help, I would encourage you to create a new question and explain everything more in detail. – Manuel Manhart Sep 29 '21 at 15:25
  • Does not change anything for me. Unfortunatly the volume is still created under root:root on the host machine – Olivier Masseau Mar 31 '22 at 08:00
  • Have you tried to create the volume mount folder eg: /home/your-user/docker-service/data with your user beforehand - or doing a sudo chown -r your-user:your-user /path/to/folder ? Because if the volume mount folder does not exist, the docker service will create this folder (as root), but if it exists, any files and subfolders will be created by the container (which runs under the given user) – Manuel Manhart Mar 31 '22 at 09:29
  • 1
    I found it much simpler to just add `export UID GID` to my `.bashrc` rather than defining it in a .env file for each project. – Steen Schütt Apr 25 '22 at 09:22
  • @SteenSchütt Nice one, I'll adapt this in my own containers :) – Manuel Manhart Apr 25 '22 at 17:56
  • 1
    @k0pernikus, there is [libnss-unknown](https://gitlab.collabora.com/sjoerd/libnss-unknown) (Debian and Ubuntu have a package) that you can install in the container and then any user that isn't in the `/etc/passwd` inside the container will get a synthesized pwent with home set according to environment. That makes applications that use `getpwent` work in containers with arbitrary user ID. – Jan Hudec Sep 08 '22 at 06:52
  • @JanHudec nice thanks for the update on that. – Manuel Manhart Sep 12 '22 at 10:55
  • 1
    To expand on my previous suggestion of exporting GID - some distros don't have that variable defined, but may have it under another name such as GROUP, in which case you can `export UID GID="$GROUP"` in your bashrc or equivalent :) – Steen Schütt Nov 20 '22 at 21:35
  • what if the volume already exists and u want to change ownership? – mike01010 Mar 25 '23 at 18:53
  • As it is a host volume mount, you can just use `sudo chown newUser:newGroup /full/path/to/mount/dir` - But you need to ensure, that the container is okay with that ;-) – Manuel Manhart Mar 27 '23 at 09:27
  • @ManuelManhart the problem is - the mount happens AFTER. so there isn't anything there to chown. if files exist with different permissions, they are not changed after the mount. – mike01010 Apr 01 '23 at 02:18
  • But once you have created the container, the host volume exists and you can change like I described. Or you create the path upfront, so it already exists before the container starts. Either way, when the container is recreated and the path already exists (on the host) the ownership is not changed. One warning though: I did encounter some containers having issues with changing UID/GIDs. – Manuel Manhart Apr 11 '23 at 15:49
53

The bad news is there's no owner/group/permission settings for volume . The good news is the following trick will let you bake it into your config, so it's fully automated .

In your Dockerfile, create an empty directory in the right location and with desired settings.

This way, the directory will already be present when docker-compose mounts to the location. When the server mounts during boot (based on docker-compose), the mounting action happily leaves those permissions alone.

Dockerfile:

# setup folder before switching to user
RUN mkdir /volume_data
RUN chown postgres:postgres /volume_data
VOLUME /volume_data
USER postgres

docker-compose.yml

volumes:
   - /home/me/postgres_data:/volume_data

source

Dedalus
  • 340
  • 2
  • 10
mahemoff
  • 44,526
  • 36
  • 160
  • 222
38

First determine the uid of the www-data user:

$ docker exec DOCKER_CONTAINER_ID id
uid=100(www-data) gid=101(www-data) groups=101(www-data)

Then, on your docker host, change the owner of the mounted directory using the uid (100 in this example):

chown -R 100 ./

Dynamic Extension

If you are using docker-compose you may as well go for it like this:

$ docker-compose exec SERVICE_NAME id
uid=100(www-data) gid=101(www-data) groups=101(www-data)
$ chown -R 100 ./

You can put that in a one-liner:

$ chown -R $(docker-compose exec SERVICE_NAME id -u) ./

The -u flag will only print the uid to stdout.

Edit: fixed casing error of CLI flag. Thanks @jcalfee314!

Arne L.
  • 2,194
  • 19
  • 19
  • 25
    Thank you for the answer. But that isn't very dynamic. I'd say that the main goal of setting this up should be something that doesn't need further customisations. However there isn't any other way to solve it or at least I wasn't able to find it. I'll try to build apache so it can run under root user, that might work too. – simPod Nov 15 '16 at 18:10
  • No, indeed, it is not dynamic (you did not ask for that). But with some hacking you could build some scripts which gets the required information (expect the `DOCKER_IMAGE_ID`) dynamically. The core problem is that the permissions are determined by the host OS and the effective user by the container itself. – Arne L. Nov 16 '16 at 10:07
  • @simPod Please review my answer. Furthermore, please adjust your question. – Arne L. Feb 08 '17 at 10:57
  • Awesome! fixed my problem, thanks a lot for this tip – flks Mar 27 '18 at 11:44
  • I was getting crazy trying to mount the volume with the uid of www-data, instead it was sooo simple... great! – Francesco Marchetti-Stasi Sep 21 '18 at 09:21
  • This is unbelievably bad advice. I have no idea why @simPod is running the container as root, but this is going to choke anyone trying to run docker normally as their current user. This simply does not work under any circumstances if you're running as current user. The container has no idea what your host user id is. – MikeyT Jun 23 '20 at 22:23
  • @MikeyT Firstly, I don't think @simPod is "running the container as root". The reason the mounts are created as `root:root` is simply that the `dockerd` daemon runs as root which in turn takes all the actions required to run containers and mount volumes. Secondly, could you explain more detailed why you believe this to be bad advice? My answer certainly should only be applied to fix a running system. @mahemoff provides [a more permanent solution](https://stackoverflow.com/a/56990338/346095). – Arne L. Jun 24 '20 at 08:07
  • 7
    @ArneL. I was too harsh, but the problem is real. The idea behind a docker-compose file is multiple devs can get some code and "it just works" as long as docker is installed. The moment you use something host specific (host user ids in this case), that breaks down. The advice given might work on linux but the next guy on windows or mac may be out of luck. Bind mounts have their uses but for this specific problem I think people are going to struggle less with a [standard docker volume](https://docs.docker.com/storage/volumes/). – MikeyT Jul 11 '20 at 05:23
  • Did you mean `chown -R`? `chown: invalid option -- 'r'` – jcalfee314 Dec 26 '21 at 14:27
12

Adding rw to the end of the volume mount worked for me:

services:
    httpd:
        image: apache-image
        ports:
            - "80:80"
        volumes:
            - "./:/var/www/app:rw"
        links:
            - redis
        command: /setupApacheRights.sh
John
  • 1,688
  • 1
  • 12
  • 9
5

Set user www-data for this compose service

    user: "www-data:www-data"

Example:

 wordpress:
    depends_on:
      - db
    image: wordpress:5.5.3-fpm-alpine
    user: "www-data:www-data"
    container_name: wordpress
    restart: unless-stopped
    env_file: 
      - .env
    volumes:
      - ./wordpress/wp-content:/var/www/html/wp-content
      - ./wordpress/wp-config-local.php:/var/www/html/wp-config.php
Yaakov Klein
  • 131
  • 1
  • 5
2

If your volumes create ownership issue then you might need to find your volume mount path by

cmd: docker volume ls

After that identify your volume name then inspect your mount path

cmd: docker volume inspect <volume name>

check your mount point there and go on mount point on your docker host machine.

where check ownership of volume by

cmd: ls -l

if it's suggest root:root then change owneship here to your docker user.

cmd: chown docker_user_id:docker_group_id -R volume_path

Note: you can find your docker user id & user group id by entering into your docker bash & hit "id" cmd.

cmd: docker-compose run --rm <container_name> bash
cmd: id
output: uid=102(www-data) gid=102(www-data) groups=102(www-data)

Find similar thread here. https://www.hamaraweb.com/sms/407/docker-volume-ownership-issue-errno-13-permission-denied-bgb6ld/

viiren
  • 21
  • 2