Search code examples
dockerdocker-composedockerfile

Can't move files to a dir, in docker


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:

Solution

  • Solution

    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
    

    Persistence

    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.