I’ve got a simple docker-compose.yml file for working on WordPress projects locally.
version: "3.5"
services:
mysql:
container_name: wp-mysql
privileged: true
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
container_name: wp-wordpress
privileged: true
depends_on:
- mysql
image: wordpress:latest
volumes:
- ./:/var/www/html
ports:
- "8080:80"
restart: always
phpmyadmin:
container_name: wp-phpmyadmin
privileged: true
image: phpmyadmin/phpmyadmin
depends_on:
- mysql
ports:
- 8181:80
environment:
MYSQL_USERNAME: root
MYSQL_ROOT_PASSWORD: root
MYSQL_PORT_3306_TCP_ADDR: mysql
PMA_HOST: mysql
I’ve used this without any issues on my MacBook Air by running docker-compose up
.
When I recently tried to do the same on a windows machine running WSL (Windows Subsystem for Linux) and I tried to upgrade to the latest version of WordPress, I faced the following error in WordPress dashboard:
Update WordPress
Downloading update from https://downloads.wordpress.org/release/wordpress-6.0.3-new-bundled.zip…
The authenticity of wordpress-6.0.3-new-bundled.zip could not be verified as no signature was found.
Unpacking the update…
Warning: copy(/var/www/html/wp-admin/includes/update-core.php): failed to open stream: Permission denied in /var/www/html/wp-admin/includes/class-wp-filesystem-direct.php on line 309
The update cannot be installed because we will be unable to copy some files. This is usually due to inconsistent file permissions.: wp-admin/includes/update-core.php
Installation failed.
In order to see what permissions are set up inside the /var/www/html that may be causing this, I bashed into the container with the following command:
docker exec -ti wp-wordpress bash
The result and subsequent ls -la
listing looks like this:
root@6eaac5e083f5:/var/www/html# ls -la
drwxr-xr-x 8 1000 1000 4096 Oct 26 01:39 .
drwxr-xr-x 1 root root 4096 Oct 5 07:09 ..
-rw-r--r-- 1 1000 1000 1051 Aug 25 2021 .htaccess
-rw-r--r-- 1 1000 1000 1812 Oct 26 01:39 docker-compose.yml
-rw-r--r-- 1 1000 1000 405 Apr 30 2021 index.php
-rw-r--r-- 1 1000 1000 19915 Aug 25 2021 license.txt
-rw-r--r-- 1 1000 1000 7346 Oct 20 2021 readme.html
-rw-r--r-- 1 1000 1000 5626 Apr 30 2021 readme.md
-rw-r--r-- 1 1000 1000 7165 Apr 30 2021 wp-activate.php
drwxr-xr-x 9 1000 1000 4096 Aug 25 2021 wp-admin
-rw-r--r-- 1 1000 1000 351 Apr 30 2021 wp-blog-header.php
-rw-r--r-- 1 1000 1000 2328 Apr 30 2021 wp-comments-post.php
-rw-r--r-- 1 1000 1000 3004 Aug 25 2021 wp-config-sample.php
-rw-r--r-- 1 1000 1000 5907 Jun 30 2021 wp-config.php
drwxrwxrwx 6 1000 1000 4096 Jun 30 2021 wp-content
-rw-r--r-- 1 1000 1000 3939 Apr 30 2021 wp-cron.php
drwxr-xr-x 25 1000 1000 12288 Aug 25 2021 wp-includes
-rw-r--r-- 1 1000 1000 2496 Apr 30 2021 wp-links-opml.php
-rw-r--r-- 1 1000 1000 3900 Aug 25 2021 wp-load.php
-rw-r--r-- 1 1000 1000 45463 Aug 25 2021 wp-login.php
-rw-r--r-- 1 1000 1000 8509 Apr 30 2021 wp-mail.php
-rw-r--r-- 1 1000 1000 22297 Aug 25 2021 wp-settings.php
-rw-r--r-- 1 1000 1000 31693 Aug 25 2021 wp-signup.php
-rw-r--r-- 1 1000 1000 4747 Apr 30 2021 wp-trackback.php
-rw-r--r-- 1 1000 1000 3236 Apr 30 2021 xmlrpc.php
root@6eaac5e083f5:/var/www/html#
From the above, I gathered that the files and folders were owned by user:group 1000:1000. Further reading lead to the finding that on most Linux systems UID:GUID of 1000:1000 is used for the first non-system account created. In addition, when volumes are mounted docker sets UID:GUID for volume mounted files and folders to the same. [1], [2].
As a result, when the apache’s www-data user tries to modify files or folders owned by 1000:1000 we face the issue described at the beginning of this post.
To get around this I switched to building my WordPress image with the help of a Dockerfile where I change ownership of the files and folders to www-data:www-data.
My modified docker-compose.yml file:
version: "3.5"
services:
mysql:
container_name: wp-mysql
privileged: true
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
wordpress:
container_name: wp-wordpress
privileged: true
depends_on:
- mysql
image: local-wordpress:latest
build:
context: .
dockerfile: Dockerfile.WordPress
volumes:
- ./:/var/www/html
ports:
- "8080:80"
restart: always
phpmyadmin:
container_name: wp-phpmyadmin
privileged: true
image: phpmyadmin/phpmyadmin
depends_on:
- mysql
ports:
- 8181:80
environment:
MYSQL_USERNAME: root
MYSQL_ROOT_PASSWORD: root
MYSQL_PORT_3306_TCP_ADDR: mysql
PMA_HOST: mysql
Dockerfile (Dockerfile.WordPress) thanks to [3]:
FROM wordpress:latest
ARG UNAME=www-data
ARG UGROUP=www-data
ARG UID=1000
ARG GID=1000
RUN usermod --uid $UID $UNAME
RUN groupmod --gid $GID $UGROUP