I'm trying to find a way how to host multiple (currently 2) React applications, each created with CRA. Both apps should run behind a single instance of NGINX and be accessible in a separate directory:
app1 -> http://localhost/app1
app2 -> http://localhost/app2
The 2 React applications where created like this:
npx create-react-app app1
npx create-react-app app2
To host both React applications using NGINX, the production build of each CRA app (npm run build
) is copied to NGINX static directory /var/www/app[1|2]
# App1
npm run build
cp build/* /var/www/app1
# App2
npm run build
cp build/* /var/www/app2
This is how NGINX can be setup to host a single CRA app:
# /etc/nginx/conf.d/default.conf
server {
listen 80;
listen [::]:80;
server_name localhost;
location / {
root /var/www/app1;
index index.html;
}
}
Now I'm trying to extend this example so both CRA apps are hosted by one NGINX.
Which modifications are necessary, both to NGINX site.conf
and each React application itself?
I pushed a code showing my (incomplete) example above to Github for reference: https://github.com/wolkenarchitekt/multiple-cra-apps-behind-nginx. The code is using docker-compose for simplicity, but in the end the whole stack should run without Docker, so running separate Docker services for each React app is not an option.
CodePudding user response:
In order to run both React apps on the same domain but different subfolders, you should just need two location
blocks:
root /var/www;
location /app1/ {
index index.html;
}
location /app2/ {
index index.html;
}
The necessary changes in the React apps usually include:
- changing the
homepage
field in thepackage.json
as described here - (only applies if react-router is used, older versions should work similarly) change the
basename
forBrowserRouter
to your subdirectory:<BrowserRouter basename='/app1'>
EDIT:
After checking out your repo (before you pushed the new branch) I just got it working with the following Dockerfile (way worse for development since every code change requires a rebuild, I just like multistage builds and this would be more suited for a production environment):
FROM node:16 as builder1
WORKDIR /var/app
COPY app1/package.json .
COPY app1/package-lock.json .
RUN npm i
COPY app1/public/ ./public
COPY app1/src/ ./src
RUN npm run build
FROM node:16 as builder2
WORKDIR /var/app
COPY app2/package.json .
COPY app2/package-lock.json .
RUN npm i
COPY app2/public/ ./public
COPY app2/src/ ./src
RUN npm run build
FROM nginx:mainline-alpine
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf
COPY ./nginx/site.conf /etc/nginx/conf.d/default.conf
COPY --from=builder1 /var/app/build/ /var/www/app1
COPY --from=builder2 /var/app/build/ /var/www/app2
The following site.conf
worked for me:
server {
listen 80;
listen [::]:80;
server_name localhost;
root /var/www;
location /app1 {
index index.html;
}
location /app2 {
index index.html;
}
}
I just had to change homepage
to /app1
and /app2
respectively, change app2/App.js
to actually output App2
, and then
docker build . -t testreactmultiple:latest
docker run -it -p 3000:80 docker.io/library/testreactmultiple:latest
I hope this helps you reproduce the working container that errors when the index is requested but works fine when /app1
or /app2
is requested.