Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't nginx serving my react index.html as fallback

I have two docker images, one is my a nginx serving my react app built files, another one is a back-end express server, both running on a same machine. The issue I have right now is my front-end app uses react router to create front-end routes as rooms. The first time I access the route via the react-router useHistory api, it works as expected. But after I refresh, I get 404 not found from nginx.

This is my nginx.conf file. From what I understand, when a request comes in, nginx looks for the longest matching path, in my case the route is something like HqHvNw. So nginx finds location / as the matching route. And because it doesn't find the directory HqHvNw, it falls back, and serve the file index.html' in /usr/share/nginx/html`. But currently, it's not working as I expected, it's returning 404 not found.

http {
    server {
        listen 80;
        root  /usr/share/nginx/html;

        location / {
            try_files $uri $uri/ /index.html;

            if ($request_method = 'OPTIONS') {
                add_header 'Access-Control-Allow-Origin' '*';
                add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
                add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
                add_header 'Access-Control-Max-Age' 1728000;
                add_header 'Content-Type' 'text/plain; charset=utf-8';
                add_header 'Content-Length' 0;
                return 204;
            }
            if ($request_method = 'POST') {
                add_header 'Access-Control-Allow-Origin' '*';
                add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
                add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            }
            if ($request_method = 'GET') {
                add_header 'Access-Control-Allow-Origin' '*';
                add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
                add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            }
        }
    }
}

The logs I get is this, why won't it serve the index.html file?

2023/04/02 19:50:35 [error] 9#9: *1 open() "/usr/share/nginx/html/HqHvNw" failed (2: No such file or directory), client: xx.xxx.xx.xx, server: , request: "GET /HqHvNw HTTP/1.1", host: "yy.yy.y.yy"

Things I've tried:

  • I've docker exec into the container to make sure the files needed are in the directory.
  • I've even chmod -R 777 the whole html directory to make sure it's not any permission issues.

Please correct me if I have misunderstood anything, any advice would also be appreciated! Thanks!

Edit: Here is my front-end dockerfile

FROM node:alpine as builder
WORKDIR /client
COPY package.json ./
COPY package-lock.json ./
COPY ./ ./
RUN npm install --force
RUN npm run build

FROM nginx:alpine

COPY ./.nginx/nginx.conf /etc/nginx/nginx.conf

## Remove default nginx index page
RUN rm -rf /usr/share/nginx/html/*

# Copy from the stage 1
COPY --from=builder /client/build /usr/share/nginx/html

RUN ls -la /usr/share/nginx/html

ENTRYPOINT ["nginx", "-g", "daemon off;"]
like image 676
hkisthebest Avatar asked Nov 16 '25 21:11

hkisthebest


1 Answers

I don't recommend overwriting the main nginx conf file unless you're going to do it properly (yours is missing several important directives like events).

Instead, provide the default site config in /etc/nginx/conf.d/default.conf

server {
    listen       80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri /index.html; # 👈 this is all I added to the existing file
    }

    # etc...
}

Your Dockerfile could also be more optimised by taking better advantage of the layer cache

FROM node:alpine as builder
WORKDIR /client

# Copy build files first
COPY package.json .
COPY package-lock.json .

# Install dependencies
RUN npm ci

# Copy source code
COPY . .

# Build
RUN npm run build

FROM nginx:alpine

COPY ./.nginx/nginx.conf /etc/nginx/conf.d/default.conf

# Copy from the stage 1
COPY --from=builder /client/build /usr/share/nginx/html

Finally, don't forget to set a .dockerignore file to avoid copying over unnecessary files

.git/
build/
node_modules/
Dockerfile
like image 152
Phil Avatar answered Nov 18 '25 10:11

Phil



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!