How to manage permissions for a volume mounted into a docker container?
Asked Answered
C

2

6

I'm developing a Wordpress theme, and want to use Docker in my dev setup. What I've done is pretty simple:

  • create a database service running MySQL 5.7
  • create a wordpress service, where I mount my theme folder as a volume into /var/www/html/wp-content/themes

I'm struggling with the volume permissions, however.

I'm working with the following project folder structure:

.
├── docker-compose.yml
└── my-theme

My docker-compose.yml file looks like this:

version: '3.2'

services:
  database:
    image: mysql:5.7
    volumes:
      - my_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: root

  wordpress:
    depends_on:
      - database
    image: wordpress:php7.3-apache
    ports:
      - '8000:80'
    restart: always
    environment:
      WORDPRESS_DB_HOST: database:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: root
    working_dir: /var/www/html
    volumes:
      - type: volume
        source: ./my-theme
        target: /var/www/html/wp-content/themes/my-theme
volumes:
  my_data: {}

When I run docker-compose up, everything works as expected: containers are created, and I can access Wordpress in the browser. However, the theme I mounted as a volume doesn't render anything when I activate it.

When I sh into the wordpress container (docker-compose exec wordpress sh) I can see that the wp-content/themes folder is owned by root. So I figured that was the problem.

I verified this being a permissions issue by manually and recursively chowning the wp-content folder in the container:

chown -R www-data:www-data /var/www/html/wp-content

Once that was done, my theme rendered as expected. So now I'm looking for a way to avoid this chown process (the idea is that any other dev can clone this project, simply run docker-compose up and start working).

The first thing I tried was to make a Dockerfile where I would build a slightly customized Wordpress image:

FROM wordpress:php7.3-apache
RUN mkdir -p /var/www/html/wp-content/themes/test-theme \
  && chown -R /var/www/html/wp-content

My reasoning behind this was that by creating the directory and chowning it beforehand, the volume would inherit the user:group mapping. Alas, no such thing; mounting the volume overrides this mapping and sets it back to root:root.

After that, I tried to set the APACHE_RUN_USER and APACHE_RUN_GROUP environment variables in my docker-compose.yml file:

version: '3.2'

services:
  database:
    ...

  wordpress:
    ...
    environment:
      WORDPRESS_DB_HOST: database:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: root
      APACHE_RUN_USER: '$(id -u)'
      APACHE_RUN_GROUP: '$(id -g)'
    working_dir: /var/www/html
    volumes:
      - type: volume
        source: ./my-theme
        target: /var/www/html/wp-content/themes/my-theme
volumes:
  my_data: {}

However, this threw a bunch of apache errors on build.

I'm at a bit of a loss here now. Is there any best practice for managing permissions of mounted volumes in Docker? I've googled a lot for this, but the solutions I do find go a little bit over my head.

Conversazione answered 24/4, 2019 at 8:22 Comment(2)
What exactly are the Apache errors you face? I suspect '$(id -u)' to be wrong, as Shell variables are not evaluated between single quotes, although I'm not sure this applies here. Other than that, doing chown in your Dockerfile is totally legit (here is a GitHub issue discussing this problem.)Harquebusier
Indeed, I also thought that doing chown in Dockerfile would do the trick (based on same GH issue you linked), but it seems that once I mount a volume, the permissions are overridden and set back to root:root. I tested by doing docker-compose up with and without volumes key in wordpress service. When I sh into the container without mounted volume, ls -l shows www-data:www-data for wp-content folder. Once I mount the volume, ls -l shows root:root...Conversazione
P
11

You can do this by overwriting the entrypoint for the wordpress image.

Create a file startup.sh in your project and make is executable:

#!/bin/bash

chown -R www-data:www-data /var/www/html/wp-content
docker-entrypoint.sh apache2-foreground

Then in your docker-compose.yml:

...
  wordpress:
...
    working_dir: /var/www/html
    volumes:
        - './my-theme:/var/www/html/wp-content/themes/my-theme'
        - './startup.sh:/startup.sh'
    entrypoint: /startup.sh

This worked for me, let me know if you have problems implementing it.

Pannier answered 24/4, 2019 at 9:34 Comment(1)
Hold on, I spoke too soon. The wordpress container build was just delayed more than usual but eventually came through. It's working now! Thanks for all your help.Conversazione
B
1

Asked ChatGPT about the problem and got a solution:

FROM php:8.0-apache

# Create a www-data user with the same UID and GID as the host user
ARG WWW_DATA_UID=1000
ARG WWW_DATA_GID=1000
RUN usermod -u $WWW_DATA_UID www-data && groupmod -g $WWW_DATA_GID www-data

# Rest of the Dockerfile...

By setting the UID and GID of the www-data user inside the container to the same values as the host machine, the ownership of the mounted files and directories should now correctly reflect the www-data user.

version: "3.9"

services:
    wordpress:
        build:
            context: .
        ports:
            - 80:80
        volumes:
            - ./src:/var/www/html:rw
        user: www-data
Breath answered 23/5, 2023 at 9:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.