Woops, that title is a bit of a mouthful. But I wanted to write a short piece on this since this was a problem I encountered recently. It was a lot fiddlier than I thought it would be!
I found quite a few articles online but I was still left with quite a few bugs to iron out.
So, here is what my Dockerfile for this looks like:
FROM node:18.12.1-buster-slim AS builder
WORKDIR /app
COPY package.json package-lock.json ./
COPY public/ public/
COPY src/ src/
RUN npm ci
RUN npm run build
FROM nginx:1.23.2-alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/build /usr/share/nginx/html
RUN touch /var/run/nginx.pid
RUN chown -R nginx:nginx /var/run/nginx.pid /usr/share/nginx/html /var/cache/nginx /var/log/nginx /etc/nginx/conf.d
USER nginx
EXPOSE 8080
CMD ["nginx", "-g", "daemon off;"]
This uses a multi stage build to first bundle up the production build of your react app. Once that’s done, in the second stage of the build nginx configuration file — nginx.conf
— is copied into the container along with the production bundle of the app.
Then a few things need to happen in order to give NGINX permissions to run as a non root user:
- It needs a new process id file
- The user we’ll use to run the application needs permissions to that file and other necessary files (cache, log, our react app).
Then you can change the user that is running the Docker container and you are pretty much good to go!
Of course, the main other thing you need for this a NGINX configuration file… Here is what a bare bones configuration file looks like for a React app:
server_tokens off;
server {
listen 8080;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri /index.html;
}
}
And once this is all done, you can run your app with these commands:
docker build -t react-app .
docker run -d -p 8080:8080 react-app
Then, navigate to http://localhost:8080
to view it!