react-router + nginx ingress refresh causes white screen when path is not "/"

9/12/2021

So I've been trying to fix this for days now and I'm beyond stuck.

My app is running, and I can access the site when I go to the default url (example.com). I can refresh on this url without issues, and I can navigate through the pages being rendered through react router as long as I don't refresh on any other page. (e.g.) refreshing on example.com/path1 doesn't work, I get a 404 error.

My current ingress file looks like:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myApp-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/use-regex: "true"
spec:
  tls:
    - hosts:
        - my.app.com
      secretName: myApp-tls
  rules:
    - host: "my.app.com"
      http:
        paths:
          - pathType: Prefix
            path: /.*
            backend:
              service:
                name: myApp
                port:
                  number: 80

I've added many of the most common replies to issues such as this, but it only makes matters worse, such as white screen with "Unexpected token '<'" errors for all javascript files it tries to load, and none of the pages loading at all.

For example, I've tried:

    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/rewrite-target: /$1
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/configuration-snippet: |
      try_files $uri $uri/ /index.html;

I've tried adding additional paths to the controller for each route available in the app, I've tried setting the path to just "/" or "/(.*)", nothing is working.

Any help would be greatly appreciated! thank you!

EDIT:

# latest active node image
FROM node:14-alpine

# Create app directory
RUN mkdir /app
RUN mkdir -p /app/node_modules && chown -R node:node /app

WORKDIR /app

COPY package.json /app
COPY tsconfig.json /app
COPY webpack.config.js /app
COPY .env.prod .env
ADD src /app/src
ADD dist /app/dist
RUN mkdir -p /app/dist/js && chown -R node:node /app/dist/js

ADD server /app/server
ADD assets /app/assets
ADD config /app/config

ARG NPM_TOKEN
COPY .npmrc_docker .npmrc
RUN npm cache verify
RUN npm install
RUN npm run build:prod
RUN rm -f .npmrc

# Expose necessary port
EXPOSE 3000

# Compile typescript and start app
CMD ["cross-env", "NODE_ENV=production", "PORT=3000", "ts-node", "server/server"]

I've also tried doing it with CMD ["npx", "http-server", "./dist", "-p", "3000"] since the server part is only doing the following:

      this.app.use(express.static(path.resolve(__dirname, "../dist")));
      this.app.get("*", (request: express.Request, response: express.Response) => {
        response.sendFile(path.resolve(__dirname, "../dist/index.html"));
      });
-- Thomas Colbert
kubernetes
nginx
react-router
reactjs

3 Answers

9/12/2021

So I think I found the issue, it seems to be working now, I still run into a problem of cmd shift r occasionally giving an unexpected token, but as a whole it seems to work.

I added the run script to the package.json, and I'm using that as the CMD now

CMD ["npm", "run", "start:prod"]

I also moved the javascript from the webpack build back to the root of the dist directory.

I don't really understand why it works now, and if I find anymore information on it, I'll update it here.

Edit:

It turns out this didn't work, I think at some point the app was cached and it just seemed like it was working, still stuck and hoping to find a fix for this.

-- Thomas Colbert
Source: StackOverflow

9/15/2021

Alright, so I found the real problem.

My domain uses both DigitalOcean and Microsoft name servers. I had the A record added on DO, but I guess it needs to be on both. So I added the A record to the other and now my config in my question works perfectly.

-- Thomas Colbert
Source: StackOverflow

9/12/2021

Your path: /.* has no capture groups, so /$1 and /$2 are undefined.

Try the following:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myApp-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
  tls:
    - hosts:
        - my.app.com
      secretName: myApp-tls
  rules:
    - host: "my.app.com"
      http:
        paths:
          - pathType: Prefix
            path: /(.*)
            backend:
              service:
                name: myApp
                port:
                  number: 80
-- John
Source: StackOverflow