I am new to both, php and docker. I am learning as I am working on them. I have a php web app, using vanilla php no framework. I am facing an issue. I am not able to fix it. I searched online with no luck. In the docker container. This is the error I am getting
Warning: move_uploaded_file(/var/www/html/src/reports/upload/files/65f7c289c413f2.84203515.png): Failed to open stream: Permission denied in /var/www/html/src/reports/upload/index.php on line 60
Warning: move_uploaded_file(): Unable to move "/tmp/phpNGBow2" to "/var/www/html/src/reports/upload/files/65f7c289c413f2.84203515.png" in /var/www/html/src/reports/upload/index.php on line 60
At first I thought maybe it's trying to access my systems tmp dir and can't access it for some reason so to fix this first I tried to create a dir inside the upload dir using php but that obviously didn't work. because that actual cause of the error is that the files inside the container /var/www/html/
are owned by root.
To fix that I added this cmd to my .docker/php/Dockerfile
but the file permissions are not changing, they are still owned by root.
FROM php:8.3.2-apache
# Installing Dependencies
RUN apt-get update && apt-get install -y \
libfreetype-dev \
libjpeg62-turbo-dev \
libpng-dev \
&& docker-php-ext-install mysqli pdo_mysql
# Install composer from docker repo
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
# Enable Apache modules
RUN a2enmod rewrite
# Copy application code
COPY . /var/www/html
# Changing Permissions
RUN chown -R www-data:www-data /var/www/html
RUN chmod -R 755 /var/www/html
I do see it run in the verbose after docker compose up -d
no errors here.
=> [php stage-0 5/7] COPY . /var/www/html 0.3s
=> [php stage-0 6/7] RUN chown -R www-data:www-data /var/www/html 1.5s
=> [php stage-0 7/7] RUN chmod -R 755 /var/www/html 1.7s
=> [php] exporting to image 0.3s
but the error is still there in the application and if I go to the container running ls -al
shows that files are owned by root and not www-data:www-data
if run chown -R www-data:www-data * && chmod -R 755 *
here the error goes away and the code works are but this is not a fix. It's only useful once, If I stop the container I'd have to run the cmd again.
# ls -al
total 92
drwxr-xr-x 12 root root 4096 Mar 15 11:00 .
drwxr-xr-x 1 root root 4096 Feb 13 05:03 ..
drwxr-xr-x 3 root root 4096 Mar 18 04:20 .docker
drwxr-xr-x 8 root root 4096 Mar 18 04:10 .git
drwxr-xr-x 2 root root 4096 Mar 15 10:59 .vscode
-rwxr-xr-x 1 root root 17 Mar 12 10:50 README.md
-rwxr-xr-x 1 root root 4124 Mar 6 10:17 composer.lock
drwxr-xr-x 2 root root 4096 Mar 15 11:00 config
-rwxr-xr-x 1 root root 737 Mar 18 04:20 docker-compose.yml
-rwxr-xr-x 1 root root 22408 Mar 16 03:55 index.php
drwxr-xr-x 2 root root 4096 Mar 5 05:29 public
drwxr-xr-x 2 root root 4096 Mar 15 11:00 reset-password
drwxr-xr-x 3 root root 4096 Mar 15 10:59 resources
drwxr-xr-x 6 root root 4096 Mar 15 10:59 src
drwxr-xr-x 2 root root 4096 Mar 15 11:00 templates
drwxr-xr-x 4 root root 4096 Mar 15 11:00 vendor
the Dockerfile is bove and here's my docker compose file, if you want to recreate the env.
version: '3.8'
services:
phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: phpmyadmin
environment:
PMA_HOST: mysql-container
PMA_USER: root
PMA_PASSWORD: rootpassword
ports:
- 8080:80
depends_on:
- mysql-container
mysql-container:
image: mysql:latest
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: database
MYSQL_USER: user
MYSQL_PASSWORD: password
MYSQL_TCP_PORT: 3306
volumes:
- mysql_data:/var/lib/mysql
php:
build:
context: .
dockerfile: ./.docker/php/Dockerfile
ports:
- 80:80
volumes:
- .:/var/www/html
depends_on:
- mysql-container
volumes:
mysql_data:
You are mounting your current workdir to /var/www inside the container, essentially undoing your permission changes. The volume will have the permission bits set as on the host. Its literally the same directory on the host.
You could change the permissions of the host directory mounted, to align with the uid/gid of the container user.
chown -R 33:33 /my/volume
docker run -v /my/volume: ...
Alternatively, if is for development, you can run the container with your local user's uid/gid. This is probably more convenient.
services:
php:
user: 1000:1000 # change to your uid/gid
Volumes is a good keyword here. We can see the application wants to save uploaded files, currently you have all your code mounted, perhaps for local development. Later that may not be the case, and then, the app would produce data, that is lost when the container is removed.
You could try to keep your container file system read only, and every time you get a write permission error, you know this requires thinking about persistence. Maybe there are options to store the data in a database instead. Maybe you mount a disk. Whatever you do, you make sure the data is persisted.