Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

martinszeltins's avatar

I don't understand why I need to mount Docker volumes for both Nginx and PHP

I have a simple Laravel application with Nginx, PHP and MySQL each in its own container. What I don't understand is:

  1. why do I need to mount volumes for both my Nginx and also PHP? Isn't PHP only a programming language not a server?

  2. Also, for production do I need to COPY my src to /var/www/html but do I need to do it for both Nginx and PHP? Or only for Nginx?

Here is my docker-compose-dev.yml file

version: '3'

networks:
  laravel:

services:
  nginx:
    image: nginx:stable-alpine
    
    container_name: nginxcontainer
    
    ports:
      - "8088:80"

    volumes:
      - ./src:/var/www/html
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf

    depends_on:
      - php
      - mysql

    networks:
      - laravel

  mysql:
    image: mysql:5.7.22

    container_name: mysqlcontainer

    restart: unless-stopped

    tty: true

    ports:
      - "4306:3306"

    volumes:
      - ./mysql:/var/lib/mysql

    environment:
      MYSQL_DATABASE: homestead
      MYSQL_USER: homestead
      MYSQL_PASSWORD: secret
      MYSQL_ROOT_PASSWORD: secret
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql

    networks:
      - laravel

  php:
    build:
      context: .
      dockerfile: php/Dockerfile-dev
    
    container_name: phpcontainer

    volumes:
      - ./src:/var/www/html

    ports:
      - "9000:9000"

    networks:
      - laravel

and here is my php/Docker-dev file

FROM php:7.2-fpm-alpine

RUN docker-php-ext-install pdo pdo_mysql
RUN chown -R www-data:www-data /var/www
RUN chmod 755 /var/www
0 likes
11 replies
bugsysha's avatar

In your case it seems that they use everything the same but it is a bit misleading cause take a look at what I use:

version: '3'

services:
    php:
        volumes:
            - ./:/var/www
    nginx:
        volumes:
            - ./public:/var/www/public

So you see they require different paths to access. Nginx needs where your app starting point (public/index.php) and PHP needs the whole project.

martinszeltins's avatar

Thank you for the help, @bugsysha. I'm a little confused. How could I make this for production instead of mounting volumes for local development?

For example, is this correct?

nginx:
   COPY . /var/www/html

php:
   COPY . /var/www/html
bugsysha's avatar

I only use docker-compose so I'm not sure but I do not have any COPY instructions in my Dockerfile and also none in docker-compose.yml.

fideloper's avatar

What you decide to do here depends on your use case.

For local development, mounting volumes is often required so you can have code on your local machine that the containers can see.

A note about PHP-FPM with Nginx: The most common Nginx configuration to use with php-fpm actually requires that Nginx "sees" the *.php file on the server before it decides to send it to php-fpm instead. If it doesn't find the file, it returns a 404 error. This is why if you have Nginx and PHP-FPM in separate containers, they both often need volume mounts.

I tend to install php-fpm and Nginx in one container for this reason. See Vessel for an example of that.

For production, code is often built into a Docker image (via COPY), and that container can then be deployed wherever based on that new image with that code.

I do that method, and tag each new image with the commit sha (and "retag" the latest image as tag latest - so the same image is tagged twice). This way I have a history of built images at each commit sha.

Hope that makes sense!

1 like
snguimjeu's avatar

@martinszeltins I think you do not need to mount the PHP code in the nginx container. It comes down to how your webserver is configured. e.g.:

version: "3.9"

networks:
  proxy:
    external: true
  laravel:

services:
  nginx:
    image: nginx:stable-alpine
    container_name: "nginxcontainer"
    ports:
      - "8088:80"
    networks:
      - laravel
    depends_on:
      - php-fpm
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf

  php-fpm:
    image: php:8.2-fpm-alpine
    container_name: "phpcontainer"
    networks:
      - laravel
    volumes:
      - ./app:/var/www/html
    working_dir: /var/www/html

Then your default.conf for nginx could look like the following

# ./nginx/default.conf

server {
    index index.php index.html;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;

    location / {
        rewrite ^ /index.php last;
    }
    location ~* \.php$ {
        root /var/www/html/public;

        fastcgi_split_path_info ^(.+\.php)(/.*)$;
        fastcgi_pass php-fpm:9000;
        fastcgi_index index.php;
        fastcgi_read_timeout 9000;

        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $document_root;
    }
}
2 likes
martinszeltins's avatar

@snguimjeu the nginx config doesn't make sense since it does not actually have access to any files therefore how could root /var/www/html/public; even work?

snguimjeu's avatar

@martinszeltins I'm currently playing around with this particular setup and there are a couple of things playing together: This part will redirect to index.php

# default.conf

location / {
    rewrite ^ /index.php last;
}

and this part says index.php is "found" on php-fpm container at the given location (root)

# default.conf

location ~* \.php$ {
    root /var/www/html/public;
   
    fastcgi_split_path_info ^(.+\.php)(/.*)$;
    fastcgi_pass php-fpm:9000;
    fastcgi_index index.php;
    ...
}

The docker-compose.yml should be enough to reproduce and test this behavior.

1 like
azadiali's avatar

@snguimjeu Excellent. Your answer solved all issues about mutual mounting of PHP files. Thank you

bluehat's avatar

In this week I stumbled into this problem myself. My solution was this docker documentation in docs.docker.com/storage/ which says:

If you mount an empty volume into a directory in the container in which files or directories exist, these files or directories are propagated (copied) into the volume. Similarly, if you start a container and specify a volume which does not already exist, an empty volume is created for you. This is a good way to pre-populate data that another container needs. 

So my solution was just to mount an empty volume under

services:
    nginx:
      image: nginx:1.25
      volumes:
         - my-volume:/var/www
     php:
       image: my-custom/image:latest
       volumes:
         - my-volume:/var/www

volumes:
  my-volume:

After this, the static files were perfectly served to nginx from the php-fpm container which in this case has all the code that needed to be shared with nginx.

Please or to participate in this conversation.