phpdockernginxdocker-composedockerfile

Docker volume only works if all files match


The only way I can get it to work if I use a bind mount volume that connects both of the containers totally, when I remove it it doesnt work. Without the shared volume between frontend and backend they both can't communicate. They are also both on the same network.

UPDATED with no volumes, dockerfiles, nginx config, sample call and error message (2nd update added proxy from nginx to php-fpm which is on port 9000)

Compose:

services:
  web:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    depends_on:
      - api
    links:
      - api
    develop:
      watch:
        - path: .
          target: /var/www/html
          action: sync

  api:
    build:
      context: ./libs/php
      dockerfile: Dockerfile
    ports:
      - "9000:9000"

Dockerfiles

FROM nginxinc/nginx-unprivileged

WORKDIR /var/www/html

COPY --chown=nginx:nginx ./conf.d/ /etc/nginx/conf.d/

COPY --chown=nginx:nginx . /var/www/html

FROM php:8.2-fpm

WORKDIR /var/www/html   

ARG UID=101
ARG GID=101

//just updating user and group to same as nginx user on frontend
RUN groupadd -g "${GID}" php-fpm \
    && useradd --no-log-init -u "${UID}" -g "${GID}" php-fpm \
    && chown php-fpm:php-fpm -R /var/www/html

USER php-fpm


COPY --chown=php-fpm:php-fpm . .

Request made from jquery script:

$("#submit_1").on("click", () => {
  const inputVal = $("#input_1").val();

   $.ajax({
      url: "/api/",
      dataType: "json",
      data: {
        searchTerm: inputVal,
      },
      method: "POST",

      success: (results) => console.log(results),
      error: (obj, details) => console.log(obj, details),
    });
  }
});

Nginx default.conf

server {
    index index.php index.html;
    server_name api;
    error_log /var/log/nginx/error.log debug;
    
    root  /usr/share/nginx/html;
    index  index.html index.htm;
    
    location /api {
        proxy_pass http://api:9000/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Enable CORS headers
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods "POST, OPTIONS";
        add_header Access-Control-Allow-Headers "Content-Type";
    }


    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass api:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}


├── docker-compose.yaml
├── index.html 
└── libs/
    ├── php/
    │   ├── geocodeBackend.php   # PHP files served by php-fpm
    │   └── other_php_files.php
    ├── js/
    │   └── jquery.js            # JS, Css and html served by nginx
    └── css/
        └── styles.css   

Error:

web-1 | 2024/11/03 00:58:59 [error] 30#30: *5 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 172.18.0.1, server: api, request: "POST /api HTTP/1.1", upstream: "http://172.18.0.2:9000/", host: "localhost", referrer: "http://localhost/"

web-1 | 172.18.0.1 - - [03/Nov/2024:00:58:59 +0000] "POST /api HTTP/1.1" 502 157 "http://localhost/" "Mozilla/5.0 (X11; Linux x86_64; rv:132.0) Gecko/20100101 Firefox/132.0" "-"

PHP-FPM container has its file

root@124743cd5330:/var/www/html# ls
Dockerfile  geocodeBackend.php


NGINX has its

root@b4eba721669f:/usr/share/nginx/html# ls
50x.html      compose.dev.yaml  favicon.ico  libs
README.Docker.md  conf.d        index.html   root

UPDATE (it works)

Thanks to changing the nginx default.conf files correctly and updating the js script url to /api/ (extra slash at the end). Below is everything I changed!

default.conf

server {
    listen 8080;
    index index.php index.html;
    server_name api;
    root  /var/www/html/;

    location /api/ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME geocodeBackend.php;
        fastcgi_pass api:9000;
    }
}

script.js

    $.ajax({
      url: "/api/",
      dataType: "json",
      data: {
        searchTerm: inputVal,
      },
      method: "POST",

Solution

  • But after trying for hours the only option is to put it all into the same exact folder in volume which defeats the purpose of containerization.

    This is due to the try_files $uri =404; directive in your nginx config. You don't need to use it at all. Here is documentation on that directive.

    web-1 | 2024/11/03 00:58:59 [error] 30#30: *5 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 172.18.0.1, server: api, request: "POST /api HTTP/1.1", upstream: "http://172.18.0.2:9000/", host: "localhost", referrer: "http://localhost/"

    This is because you are trying to communicate with your PHP-FPM backend via HTTP protocol while it is expects FastCGI one.

    As far as I understand, if you want to pass all /api... requests to the geocodeBackend.php PHP script, you need something like

    location /api {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME /full/path/to/geocodeBackend.php;
        fastcgi_pass api:9000;
    }
    

    (BTW, I recommend to use /api/... rather than /api...).

    Some PHP scripts may additionally rely on some other FastCGI variables like SCRIPT_NAME, DOCUMENT_URI or DOCUMENT_ROOT; see the last part of this answer and comment below for more information.