Nginx docker container serving a front end react app
Serving react front ends can be done in many ways, depending on your needs, but one effective way of doing it, if for sure using nginx, so stick with me
The way you might be doing it right now is using your rest api (express / rails), but this puts unwanted weight and traffic on your api, instead what we could do is seperate the serving of the front-end from the back-end.
as seen above nginx knows if you browser is asking for the html and javascript code, and obeys as follows, HOW? you might be wondering, well lets see:
FUN PART
prerequisite you only need docker installed on your machine to run the following
- create the nginx docker container:
In order for nginx to serve our front-end it needs to have its files first right? duh!, lets create a dummy client app using
npx create-react-app client
then we will need a Dockerfile:
FROM node:12-alpine as buildWORKDIR /appCOPY package*.json ./RUN npm install --productionCOPY . .RUN npm run build
what this code will actually do, assuming its inside your client app its ging to fetch an nginx image of node 12, alpine which is basically a lightweight version, copy the package files in order to install the dependencies, and copy the source code and build the final files that nginx is going to serve tp the public.
2. Inthe same file add the following.
FROM nginx:stable-alpineCOPY --from=build /app/build /bin/wwwCOPY nginx/nginx.conf /etc/nginx/conf.d/default.confEXPOSE 80CMD [ "nginx", "-g", "daemon off;" ]
“what gibberish is this”, you might be wondering, relax, basically for nginx in order to function correctly it need to have the a config file and servers them through port 80 (equivalent to “localhost ”without any appended ports), the above is going to copy the folder generated by our:
RUN npm run build
and paste it inside our little cute nginx Virtual machine-ish container, so the next time a user requests our website nginx doesnt have to look around a lot to responde. Next we need a config file to let nginx know where our app is located in the container:
3. create a file inside a folder called “nginx ”in your client folder and call it nginx.conf as we specified in our Dockerfile and paste the following
server {listen 80;location / { root /bin/www/; index index.html index.htm; try_files $uri $uri/ /index.html;} location /api { proxy_pass http://{YOUR_API}; #http://localhost:5054; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade;}}
so the above nginx.conf/ tells nginx, “alright listen up, requests that look like this => http://exemple.com/, get them to the index.html file inside the /bin/www NOTE: it needs to be an absolute path. paths that have a trailing /api , like http://exemple.com/api, go to the backend “
ALMOST DONE
okay if you’re going to use this, you most likely want to orchesrate it using docker-compose, if so make sure you have your ports specified and you’re on the correct network more on that later, but you might want something like this:
version: "3.5"services: api: build: . networks: - app-network ports: - "5054:5054" client: build: ./client/ restart: unless-stopped ports: - "80:80" networks: - app-networknetworks: app-network:
here we declared two services, our api and our client app, as you can see they share the same network so they can talk to each other like http://api:5054
rather than http://localhost:5054 , as we know that wouldn’t work because these two apps are not hosted on the HOST machine.
NEXT step:
here is a trick, open up chrome dev tools, and you’ll see that the html file is coming from “server: nginx” meanwhile route requests like /api are coming from “server: express” or rails api