How to fix 404 error when accessing a specific URL for create-react-apps ? (client-side routing)

Hello,

I am fairly new to the Fly.io experience and I’m having trouble figuring out how to fix this issue :
If I go to “https://example.com”, my whole website works, navigating to other pages etc. everything works correctly. But if I go directly to “https://example.com/dashboard”, I have a 404 error even if this page exists. This happens only on my Fly.io app which I deployed follow the static website example (using pierrezemb/gostatic docker image, etc.)

I found the origin of the issue on this stackoverflow topic (reactjs - How to fix "404" error when directly accessing a component in react - Stack Overflow) but I have no idea how to fix it on my Fly.io app.

How could I fix this please?

It looks like the container recommended for static sites is for “true” static sites instead of React / react router sites.

The solution is to set some web server configuration to route all requests to /index.html (that’s what the SO article you linked to is saying in its solution).

It’s similar to how in the PHP world, “pretty URL’s” were used so you didn’t use urls like /index.php/foo/bar but instead used Apache/Nginx rewrite rules to just use /foo/bar (which gets sent to the /index.php file after adjusting server configurations).

The base image used (gostatic) doesn’t appear to have that configuration available. (Unless I’m missing something!)

A few google results for “nginx container react router” show some promising examples of using Node and Nginx containers to get the job done (including the needed server config).

However give a shout if Docker / Nginx configs isn’t something you have experience with. (Unfortunately I don’t have much experience with React myself!)

oh ok yes, I’ll definitely look into it tomorrow and keep you posted, thanks!

I fixed everything with what you said, thanks !

For those interested, here is my new Dockerfile:

# Stage 0, "build-stage", based on Node.js to build the frontend
FROM node:16.17-alpine as build
WORKDIR /app
COPY package*.json /app/
RUN npm install
COPY . /app/
RUN npm run build

# Stage 1, based on NGINX to provide a configuration to be used with react-router
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx/nginx.conf /etc/nginx/conf.d
EXPOSE 8080
CMD ["nginx", "-g", "daemon off;"]

And adding the following nginx.conf file in a nginx folder :

server {
  listen 8080;
  location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
    try_files $uri $uri/ /index.html;
  }
}

And also updating the fly.toml file by specifying the 8080 port.

...
[[services]]
  http_checks = []
  internal_port = 8080
...

Thanks again :slight_smile:
[updated thanks to @fideloper-fly last asnwer]

1 Like

Great - I’m glad you got that working!

Two random things (you don’t necessarily need to care):

  • FROM node:alpine as build - That might change NodeJS versions on you since it’ll track the latest version of Node released. Up to you if you care. Find more tags with specific versions you can use here.
  • If you wanted to use another internal port that wasn’t 80 - say 8080 for example (I tend to not use port 80 as it makes debugging a little easier - but you’re allowed to!),
    • Change EXPOSE 80 to EXPOSE 8080
    • Change listen 80; to listen 8080;
    • Change internal_port = 80 to internal_port = 8080

No worries if you don’t need/want to change any of those, just thought I’d note that!

1 Like

Great thanks, I updated my previous answer using your input!

1 Like