skip to Main Content

So I want to have a single Nginx web server serving both frontend and backend with Docker.
Here is my docker-compose:

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
    networks:
      - frontend

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

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

volumes:
  db:

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

And here’s the Dockerfile for the frontend:

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

ENV GENERATE_SOURCEMAP=false

RUN npm run build

The problem is that the frontend container can’t seem to start. It exit always at startup.

From my understanding I should copy the build content of the build-stage into the nginx folder "/usr/share/nginx/html" but how can I do it from the docker-compose file?

Just using volumes won’t work. I need nginx in the docker-compose because it’s also serving the backend.

Please note that the backend is working correctly.

UPDATE

My first approach was to use a Dockerfile for the frontend where I copied the content of the build directly into an Nginx image

# 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 in this way I think I’m deploying two Nginx. One in the Dockerfile and one in the Docker-compose. Am I right?

2

Answers


  1. I mostly use Docker multi-build to configure my FE app. Hope this might help you!

    FROM node:16.13.0 as build-stage
    
    WORKDIR /app
    
    COPY package.json ./
    COPY package-lock.json ./
    COPY ./ ./
    
    RUN npm install
    RUN npm run dev
    
    
    
    #Build Files
    FROM nginx:1.19.10-alpine
    COPY nginx-conf /etc/nginx/conf.d/default.conf
    COPY --from=build /app /home/ubuntu/app/dist
    

    you can use default nginx configuration.

    Login or Signup to reply.
  2. @federico-arona

    As stated in my comment: If you want to have 1 nginx you need to share or copy the files from the container that is building the app.

    Based on your requirements and what you wanted to accomplish. The best solution is named volumes, as they can be shared across containers.

    They are the preferred mechanism for persisting data generated by and used by Docker containers. Plus you can manage volumes using Docker CLI commands and the Docker API. The Official docs show other benefits and additional information on how to use them.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search