Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Connect React App served on dockerized Nginx to Express server

For production, I have a Dockerfile which serves a React app using Nginx:

# Stage 1

FROM node:15.6.0-alpine3.10 as react-build
WORKDIR /app/client/
COPY package*.json ./
RUN npm install
COPY ./ ./
RUN npm run build

# Stage 2 - the production environment

FROM nginx:1.19.6
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=react-build /app/client/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

While for the backend written in Node / Express, I have the following Dockerfile:

FROM node:15.6.0-alpine3.10
WORKDIR /app/server/
COPY package*.json ./
RUN npm install
COPY ./ ./
EXPOSE 8080
CMD ["npm", "start"]

These containers are managed with this docker-compose.yml:

version: "3.0"

services:
  # React Client
  web:
    image: xxx.dkr.ecr.eu-west-2.amazonaws.com/client:latest
    ports:
      - "80:80"

  # Node Server
  server:
    image: xxx.dkr.ecr.xxx.amazonaws.com/server:latest
    command: npm start
    ports:
      - "8080:8080"

Here the nginx.conf:

server {
  listen 80;
  
  location / {
    root /usr/share/nginx/html;
    index index.html index.htm;
    try_files $uri $uri/ /index.html =404;
  }
  
  include /etc/nginx/extra-conf.d/*.conf;
}

PREMISES

  • On local everything works fine, I run React through react-scripts and the backend with docker-compose (and so without the React client)
  • Both images have been pushed to AWS ECR, their content is the equivalent of the Dockerfile above
  • When fetching the server, endpoints look like fetch("/users/:id", {..})
  • On package.json, I've set "proxy": "http://localhost:8080/"
  • Both images have both been tested and are working, both on dev and prod

PROBLEM

When hitting an api endpoint from the client, I get a 405 (Not Allowed).

That's actually expected, as I'm not really telling the client (Nginx) where to redirect these calls to.

Inspecting the network tab I can see the request is made against xxx.xxx.xxx.xxx:80 (which represents the client), when it should be redirected to same address but port 8080 instead (where the Express server stands).

On development it works since there's proxy set on package.json, but that's for development only, so it won't affect production.

WHAT I TRIED

  • Using links on docker-compose, not supported from AWS
  • Using driver networks on docker-compose, not supported from AWS
  • Adding proxy_pass on nginx.conf, but haven't been able to make it working

CONCLUSIONS

So premised all this, how can I connect a React build served with Nginx (client) to a Node server when both dockerized and on production?

I believe it should need some configuration on nginx.conf, but what I tried didn't land me that far.

Thank you in advance for your help!

like image 900
ale917k Avatar asked Oct 27 '22 14:10

ale917k


1 Answers

First you need to specify proxy pass directive for your api calls - I would propose to add /api in your fetch calls. Than provide upstream using the same name for your backend service as specified in docker-compose.yml. It is important that backend service proceed the web service in docker-compose.yml, otherwise you would get connection error in nginx like this nginx: [emerg] host not found in upstream "backend:8080" You can update your nginx.conf as follows:

upstream backend {
  server backend:8080;
}

server {
  listen 80;
  
  location / {
    root /usr/share/nginx/html;
    index index.html index.htm;
    try_files $uri $uri/ /index.html =404;
  }

  location /api {
    rewrite /api/(.*) /$1 break;
    proxy_pass http://backend;
  }
  
  include /etc/nginx/extra-conf.d/*.conf;
}

Or simply in your case provide a proxy pass to localhost as follows:

server {
   listen 80;
      
   location / {
     root /usr/share/nginx/html;
     index index.html index.htm;
     try_files $uri $uri/ /index.html =404;
   }
  
   location /api {
     rewrite /api/(.*) /$1 break;
     proxy_pass http://localhost:8080;
   }
      
   include /etc/nginx/extra-conf.d/*.conf;
}
like image 184
Konstantin Samarin Avatar answered Oct 29 '22 16:10

Konstantin Samarin