Docker deploy backend and frontend with one nginx

Hi everyone.
I have an app composed by a frontend written in React and a backend written in Laravel.
Now I want to deploy it using Docker.

My goal is to setup only one “NGINX” to serve both frontend and backend applications.
The problem is that no content is copied from frontend build stage into the nginx folder.

I’ve written the Dockerfiles both for the frontend and the backend.

Backend:

FROM php:7.4-fpm

# Arguments defined in docker-compose.yml
ARG user
ARG uid

# Install system dependencies
RUN apt-get update && apt-get install -y \
    git \
    curl \
    libpng-dev \
    libonig-dev \
    libxml2-dev \
    zip \
    unzip

# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*

# Install PHP extensions
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd

# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Create system user to run Composer and Artisan Commands
RUN useradd -G www-data,root -u $uid -d /home/$user $user
RUN mkdir -p /home/$user/.composer && \
    chown -R $user:$user /home/$user

# Set working directory
WORKDIR /var/www

USER $user

Frontend:

# Stage 1
FROM node:16.13.0 as build-stage

WORKDIR ./

COPY package.json ./
COPY package-lock.json ./
COPY ./ ./
RUN npm i

ARG REACT_APP_API_BASE_URL
ARG REACT_APP_BACKEND_ENDPOINT
ARG REACT_APP_FRONTEND_ENDPOINT
ARG REACT_APP_FRONTEND_ENDPOINT_ERROR
ARG REACT_APP_CUSTOMER
ARG REACT_APP_NAME

ENV REACT_APP_API_BASE_URL=$REACT_APP_API_BASE_URL
ENV REACT_APP_BACKEND_ENDPOINT=$REACT_APP_BACKEND_ENDPOINT
ENV REACT_APP_FRONTEND_ENDPOINT = $REACT_APP_FRONTEND_ENDPOINT
ENV REACT_APP_FRONTEND_ENDPOINT_ERROR = $REACT_APP_FRONTEND_ENDPOINT_ERROR
ENV REACT_APP_CUSTOMER=$REACT_APP_CUSTOMER
ENV REACT_APP_NAME=$REACT_APP_NAME

#avoid javascript out of memory
ENV GENERATE_SOURCEMAP=false

RUN npm run build
EXPOSE $REACT_DOCKER_PORT

The docker-compose is the following:

version: "3.8"


services:
  db: #mysqldb
    image: mysql:5.7
    container_name: ${DB_SERVICE_NAME}
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_USER: ${DB_USERNAME}
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    ports:
      - $MYSQLDB_LOCAL_PORT:$MYSQLDB_DOCKER_PORT
    volumes:
      - ./docker-compose/mysql:/docker-entrypoint-initdb.d
    networks:
      - backend

  mrmfrontend:
    build:
      context: ./mrmfrontend
      args:
        - REACT_APP_API_BASE_URL=$CLIENT_API_BASE_URL
        - REACT_APP_BACKEND_ENDPOINT=$REACT_APP_BACKEND_ENDPOINT
        - REACT_APP_FRONTEND_ENDPOINT=$REACT_APP_FRONTEND_ENDPOINT
        - REACT_APP_FRONTEND_ENDPOINT_ERROR=$REACT_APP_FRONTEND_ENDPOINT_ERROR
        - REACT_APP_CUSTOMER=$REACT_APP_CUSTOMER
        - REACT_APP_NAME=$REACT_APP_NAME
        - REACT_APP_OWNER=""
    ports:
      - $REACT_LOCAL_PORT:$REACT_DOCKER_PORT
    stdin_open: true
    tty: true
    networks:
      - frontend

  app:
    build:
      args:
        user: admin
        uid: 1000
      context: ./MRMBackend
      dockerfile: Dockerfile
    image: backend
    container_name: backend-app
    restart: unless-stopped
    networks:
      - backend

  nginx:
    image: nginx:alpine
    container_name: nginx
    restart: unless-stopped
    ports:
      - 8000:80
    volumes:
      - ./MRMBackend:/var/www
      - ./mrmfrontend/build:/usr/share/nginx/html
      - ./docker-compose/nginx/backend:/etc/nginx/conf.d/
    networks:
      - backend
      - frontend

volumes:
  db:

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

The problem is that no content is copied from “mrmfrontend/build” into the nginx folder.
Note instead that the content of the backend is copied properly.
I think that’s because the build stage is not persisting the data after the completion.

What am I missing? Is this the correct approach?

What I tried before
My initial approach was to have the nginx in the dockerfile of the frontend:

# Stage 1
FROM node:16.13.0 as build-stage

WORKDIR /app

COPY package.json ./
COPY package-lock.json ./
COPY ./ ./
RUN npm i

ARG REACT_APP_API_BASE_URL
ARG REACT_APP_BACKEND_ENDPOINT
ARG REACT_APP_FRONTEND_ENDPOINT
ARG REACT_APP_FRONTEND_ENDPOINT_ERROR
ARG REACT_APP_CUSTOMER
ARG REACT_APP_NAME

ENV REACT_APP_API_BASE_URL=$REACT_APP_API_BASE_URL
ENV REACT_APP_BACKEND_ENDPOINT=$REACT_APP_BACKEND_ENDPOINT
ENV REACT_APP_FRONTEND_ENDPOINT = $REACT_APP_FRONTEND_ENDPOINT
ENV REACT_APP_FRONTEND_ENDPOINT_ERROR = $REACT_APP_FRONTEND_ENDPOINT_ERROR
ENV REACT_APP_CUSTOMER=$REACT_APP_CUSTOMER
ENV REACT_APP_NAME=$REACT_APP_NAME

#avoid javascript out of memory
ENV GENERATE_SOURCEMAP=false

RUN npm run build

# Stage 2
FROM nginx:1.17.0-alpine

COPY --from=build-stage /app/build /usr/share/nginx/html
EXPOSE $REACT_DOCKER_PORT

CMD nginx -g 'daemon off;'

But I suppose that this means that I’m deploying two Nginx images. One is defined in the docker-compose, and one is deployed with this Dockerfile. Am I right?

I don’t completely understand your goal here. What do you expect to be copied to where and why? Where are those lines in the code? I don’t see anything copied to the folder you mentioned.