Resolving nginx 404 error in staging that didn't occur in development

4/7/2020

I don't have much experience with web servers and I'm finding out I'm not too good at setting them up or figuring out what is wrong with them. Hoping to change that.

I'm getting "unpredictable" routing behavior, described directly below, now that I've switched from npm start in dev to an npm builid -> nginx staging deployment:

  • User lands at / and signs in which brings them to /home
  • Once at home /home if you refresh the page you get a "404 Not Found: nginx/1.17.9" error
  • This leads me to believe it is the nginx for the FE and not ingress-nginx that is the issue
  • Further more I have routes like the following where the routing is working when you initially navigate to it. Then you refresh and get "404 Not Found: nginx/1.17.9". They all happen to be anchors that when the user clicks on the <a> it takes them to the route and expands a corresponding card:
    • /home#mydata
    • /documents#meeting
    • /documents#submit
    • /documents#resources
  • Then I have routes like the following that result in the "404 Not Found: nginx/1.17.9" immediately when you navigate to them:
    • /home/
    • /documents/

I'm struggling to understand why this happening or how to fix it.

Working in from ingress-nginx, this is what I have:

# ingress.yaml

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/add-base-url: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$1
    nginx.ingress.kubernetes.io/proxy-body-size: "0"
    nginx.org/client-max-body-size: "500m"
    nginx.ingress.kubernetes.io/use-regex: "true"
  name: ingress-service-dev
  namespace: default
spec:
  rules:
    - http:
        paths:
          - path: /?(.*)
            backend:
              serviceName: client-cluster-ip-service-dev
              servicePort: 3000
          - path: /admin/?(.*)
            backend:
              serviceName: admin-cluster-ip-service-dev
              servicePort: 4000
          - path: /api/?(.*)
            backend:
              serviceName: api-cluster-ip-service-dev
              servicePort: 5000
# client.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: client-deployment-dev
spec:
  replicas: 1
  selector:
    matchLabels:
      component: client
  template:
    metadata:
      labels:
        component: client
    spec:
      containers:
        - name: client
          image: testappacr.azurecr.io/test-app-client
          ports:
            - containerPort: 3000
          env:
          - name: DOMAIN
            valueFrom:
              secretKeyRef:
                name: test-app-dev-secrets
                key: DOMAIN 
---
apiVersion: v1
kind: Service
metadata:
  name: client-cluster-ip-service-dev
spec:
  type: ClusterIP
  selector:
    component: client
  ports:
    - port: 3000
      targetPort: 3000
# Dockerfile

FROM node:13-alpine as builder
WORKDIR /app
COPY ./package.json ./
RUN npm install
COPY . .
RUN npm run build

FROM nginx
EXPOSE 3000
COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/build /usr/share/nginx/html
# default.conf

server {
  listen 3000;

  location / {
    root /usr/share/nginx/html;
    index index.html index.htm;
  }
}
// index.js
ReactDOM.render(
  <Provider store={store}>
    <ConnectedRouter history={history}>
      <div className="content">
        <Navigation />
        <Messages />
        <App>
          <Switch>
            <Route 
              exact 
              path="/home/" 
              component={protectedRoute(Home)} 
            />
            <Route
              exact
              path="/documents/"
              component={protectedRoute(Documents)}
            />
            <Route 
              exact 
              path="/results/" 
              component={protectedRoute(Results)}  
            />
            <Route 
              exact 
              path="/contact/" 
              component={protectedRoute(Contact)}  
            />
            <Route
              exact
              path="/account/"
              component={protectedRoute(AccountSettings)}
            />
            <Route
              exact
              path="/auth/security_questions/f=:f&i=:id&k=:key/"
              component={SecurityQuestions}
            />
            <Route
              exact
              path="/auth/set_password/f=:f&i=:id&k=:key/"
              component={SetPassword}
            />
            <Route
              // exact
              path="/auth/setup_user/f=:f&i=:id&k=:key/"
              component={SetupUser}
            />
            <Route
              exact
              path="/auth/expired_key/f=:f&i=:id&k=:key/"
              component={ExpiredKey}
            />
            <Route 
              exact 
              path="/" 
              component={Auth}  
            />
            <Route 
              component={ErrorPage} 
            />
          </Switch>
        </App>
        <Footer />
      </div>
    </ConnectedRouter>
  </Provider>,
  document.querySelector("#root")
);

Any suggestions for how to get this working properly? Thanks in advance for the help!

EDIT

I'm working on this issue again after fixing some others. I noticed this in the nignx log:

[client-deployment-dev-775584cdf5-4ss98 client] 2020/04/08 16:47:23 [error] 6#6: *1 open() "/usr/share/nginx/html/home" failed (2: No such file or directory), client: 172.17.0.3, server: , request: "GET /home HTTP/1.1", host: "192.168.39.37"

Apparently, it is trying to navigate to a /home directory for some reason. when react-router-dom should be handling the app routing. At least some clue for me to look into.

-- eox.dev
docker
kubernetes
nginx
nginx-ingress
reactjs

1 Answer

4/8/2020

Ok, started googline "nginx react-router-dom" and came across this answer:

https://stackoverflow.com/a/43954597/3123109

I changed my default.conf to the following and it appears to be working now as expected:

server {
  listen 3000;
  root /usr/share/nginx/html;
  index index.html index.htm;

  location / {
    try_files $uri $uri/ /index.html;
  }
}
-- eox.dev
Source: StackOverflow