Thought leadership from the most innovative tech companies, all in one place.

How to Serve a React App with NGINX in a Non-Root Docker Container

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

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/
RUN chown -R nginx:nginx /var/run/ /usr/share/nginx/html /var/cache/nginx /var/log/nginx /etc/nginx/conf.d
USER nginx
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:

  1. It needs a new process id file
  2. 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!

Continue Learning