207

I am transitioning my react app from webpack-dev-server to nginx.

When I go to the root url "localhost:8080/login" I simply get a 404 and in my nginx log I see that it is trying to get:

my-nginx-container | 2017/05/12 21:07:01 [error] 6#6: *11 open() "/wwwroot/login" failed (2: No such file or directory), client: 172.20.0.1, server: , request: "GET /login HTTP/1.1", host: "localhost:8080"
my-nginx-container | 172.20.0.1 - - [12/May/2017:21:07:01 +0000] "GET /login HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:53.0) Gecko/20100101 Firefox/53.0" "-"

Where should I look for a fix ?

My router bit in react looks like this:

render(

  <Provider store={store}>
    <MuiThemeProvider>
      <BrowserRouter history={history}>
        <div>
          Hello there p
          <Route path="/login" component={Login} />
          <App>

            <Route path="/albums" component={Albums}/>

            <Photos>
              <Route path="/photos" component={SearchPhotos}/>
            </Photos>
            <div></div>
            <Catalogs>
              <Route path="/catalogs/list" component={CatalogList}/>
              <Route path="/catalogs/new" component={NewCatalog}/>
              <Route path="/catalogs/:id/photos/" component={CatalogPhotos}/>
              <Route path="/catalogs/:id/photos/:photoId/card" component={PhotoCard}/>
            </Catalogs>
          </App>
        </div>
      </BrowserRouter>
    </MuiThemeProvider>
  </Provider>, app);

And my nginx file like this:

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;

    server {
        listen 8080;
        root /wwwroot;

        location / {
            root /wwwroot;
            index index.html;

            try_files $uri $uri/ /wwwroot/index.html;
        }


    }
}

EDIT:

I know that most of the setup works because when I go to localhost:8080 without being logged in I get the login page as well. this is not through a redirect to localhost:8080/login - it is some react code.

martin
  • 3,289
  • 5
  • 22
  • 27
  • 1
    The parameters to `try_files` should be URIs and not pathnames. Try: `try_files $uri $uri/ /index.html;` – Richard Smith May 13 '17 at 10:53
  • @RichardSmith OK... I saw it as the pathname to the index.html file. I have tried changing it to what you suggested - but getting the same result. ## /wwwroot/login" failed (2: No such file or directory) ## do you have other suggestions. I'll dive into it tonite... – martin May 13 '17 at 11:52

16 Answers16

436

The location block in your nginx config should be:

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

The problem is that requests to the index.html file work, but you're not currently telling nginx to forward other requests to the index.html file too.

Toby
  • 12,743
  • 8
  • 43
  • 75
  • 20
    Check this out for more advanced configuration (caching, 404 for missing .js, .css files, etc.) https://gkedge.gitbooks.io/react-router-in-the-real/content/nginx.html – Gianfranco P. Jul 24 '18 at 20:34
  • It seems like React Router shouldn't cause a round trip to the server at all... can this be stymied locally? – Scotty H Oct 01 '18 at 20:18
  • 2
    if nginx doesn't route the request to the index.html file, then the JS inside React Router will never even be aware of the request. This answer routes all requests to React, allowing for React Router to handle all requests. – Toby Oct 01 '18 at 20:25
  • 2
    It is also important to use the default homepage setting in package.json, which uses the server root. I had set it to '.', (use relative paths), but then nginx tried to serve /custompath/static/main.js, which obviously will fail, giving a non working site. – boerre Nov 22 '18 at 13:01
  • 1
    just a heads up, make sure you config is actually being loaded, mine was conflicting with default and just being skipped. sigh – 4c74356b41 Feb 12 '19 at 12:22
  • 1
    Make sure to include the leading `/` in `/index.html`. I left this off thinking it's optional, when it's not. – Cameron Gagnon Mar 09 '20 at 01:58
  • Hi, this command works fine until I force clear browser cache then there's an exception thrown by the static files of the index.html generated by react (static/....chunk.js ...) the error is Unexpected token '>'. Any other configuration suggestion? – Pistachio Dec 15 '20 at 12:41
  • This works fine for me when I have a trailing slash, like `https://www.myapp.com/app/` But doesn't work without it: `https://www.myapp.com/app` Any ideas how to fix this? – Cathal Mac Donnacha May 24 '21 at 15:53
  • You have saved me from lots of troubles, thank you <3 – K. Mouad Feb 14 '23 at 11:22
25

Here are my solutions

simple trying:

location / {
    root /var/www/mysite;
    try_files $uri /index.html;
}

no more trying for non-html types:

location / {
    root /var/www/mysite;
    set $fallback_file /index.html;
    if ($http_accept !~ text/html) {
        set $fallback_file /null;
    }
    try_files $uri $fallback_file;
}

no more trying for non-html types and directory (making try_files compatible with index and/or autoindex):

location / {
    root /var/www/mysite;
    index index.html;
    autoindex on;
    set $fallback_file /index.html;
    if ($http_accept !~ text/html) {
        set $fallback_file /null;
    }
    if ($uri ~ /$) {
        set $fallback_file /null;
    }
    try_files $uri $fallback_file;
}
fuweichin
  • 1,398
  • 13
  • 14
23

Maybe this is not the exact case here but for anyone running a docker container for their react project with react-router and webpack-dev-server, in my case I had everything I needed in my nginx.conf:

server {
    listen 80;
    location / {
      root   /usr/share/nginx/html;
      index  index.html index.htm;
      try_files $uri $uri/ /index.html;
    } 
    error_page 404 /index.html;
    location = / {
      root /usr/share/nginx/html;
      internal;
    }
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
      root   /usr/share/nginx/html;
    }
  }

But still nginx wouldn't send 404 erros to the root /. After looking into the container I noticed that there's some configs in /etc/nginx/conf.d/default.conf which would somehow overrides my configs, so deleting that file in my dockerfile solved the problem:

...
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
RUN rm /etc/nginx/conf.d/default.conf  # <= This line solved my issue
COPY nginx.conf /etc/nginx/conf.d
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Ghasem
  • 14,455
  • 21
  • 138
  • 171
8

Here is the solution that works for me in the live server:

I have just followed this tutorial and with the basic Nginx configuration simply just configured the location block.

location / {
    try_files $uri $uri/ /index.html;
}
Fatema Tuz Zuhora
  • 3,088
  • 1
  • 21
  • 33
7

If you are serving from a sub-directory (e.g. http://localhost:8080/jobs/):

use your / block as following:

server {
    listen              8080;
    server_name         localhost;
    absolute_redirect   off;
    root                /usr/share/nginx/html;
    index               index.html;

    location / {
      expires         5m;
      add_header      Cache-Control "public";
      try_files $uri $uri/ /jobs/index.html;
    }

}
Nitin Jadhav
  • 6,495
  • 1
  • 46
  • 48
4

The location block in your nginx config should be like

location / {
       root   /path/to/root/dir;
       index  index.html index.htm;
       try_files $uri $uri/ /index.html;

to forward all requests to the index.html( your React SPA APP ).

And

The package.json of your react app project, add the "homepage":"http://your.website.go" to make nested path forward to correct static file.

{
  "name": "React App",
  "version": "0.0.0",
  "homepage": "http://your.website.go",
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-router-dom": "^6.1.1",
    "react-scripts": "5.0.0",
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  }
}
Jay Lu
  • 1,515
  • 8
  • 18
2

For me nothing worked until I added a root directive. This worked for me also using a reverse proxy to hit up an /api/ webserver endpoint.

location / {
    root   /usr/share/nginx/html;
    try_files $uri /index.html;
}
Jazzepi
  • 5,259
  • 11
  • 55
  • 81
  • Any chance it was an Express API server? If so, would you mind sharing your config/Dockerfile please? – Mike K Nov 25 '20 at 09:01
2

I had some issues with create-react-app using service workers and this exact nginx config. After publishing a new version of the site, the service worker would refetch the JS and be sent the index.html file instead of a 404. So my updated version of the nginx config is this:

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

location /static/ {
        try_files $uri =404;
}

It ensures that anything in /static/ will not return the index.html.

Martin Brisiak
  • 3,872
  • 12
  • 37
  • 51
Ralle
  • 21
  • 1
1

Nginx will try to find the index.html in the root, if you are using a different location you might need to add it to the try_files instruction:

So instead of:

location /MyLocation {
    root /var/www/html;
    try_files $uri /index.html;
}

You should do:

location /MyLocation {
    root /var/www/html;
    try_files $uri /MyLocation/index.html; # Make sure to add the folder to the path
}

By adding MyLocation to the try_files you make nginx use the correct index.html when redirecting routes.

1

I know this question has been answered to the death, but it doesn't solve the problem where you want to use your browser router with proxy pass, where you can't use root.

For me the solution is pretty simple.

say you have a url that's pointing to some port.

location / {
  proxy_pass http://127.0.0.1:30002/;
  proxy_set_header    Host            $host;
  port_in_redirect    off;
}

and now because of the browser router sub paths are broken. However you know what the sub paths are.

The solution to this? For sub path /contact

# just copy paste.
location /contact/ {
  proxy_pass http://127.0.0.1:30002/;
  proxy_set_header    Host            $host;
}

Nothing else I've tried works, but this simple fix works like a charm.

Yana Trifonova
  • 586
  • 7
  • 28
danieltan95
  • 810
  • 7
  • 14
0

I was dealing with the same problem and I thought that was a conf error but no. I was copying the conf file to the /etc/nginx/conf.d/ folder. That works in dev but in build version cause that problem. When the route fails the nginx doesn't fallback to index.

Just copy the conf file to the right folder: /etc/nginx/conf.d/default.conf

Example Dockerfile instruction: COPY .docker/prod/nginx.conf /etc/nginx/conf.d/default.conf

Hope it helps.

Alireza
  • 2,319
  • 2
  • 23
  • 35
diogopalhais
  • 369
  • 1
  • 4
  • 14
0

Here are some steps that I took that might help if you are starting out

  1. Once in SSH need to go back to root / using cd .. then you should be in /
  2. Then find the .conf file usually located in /etc/nginx/sites-available/{yoursitename or default} cd in front to navigate to it
  3. edit that file using nano or vim I used Vim like this vi {your site.conf}
  4. Here the content of the entire file that should work
server {
        listen       80;
        server_name www.yourDomainName.com, yourDomainName.com;
        location / {
            root   /usr/share/nginx/{location of the build of your react project};
            index  index.html index.htm;
            
            try_files $uri $uri/ /index.html;

            passenger_enabled on;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
}
Jonathan Sanchez
  • 7,316
  • 1
  • 24
  • 20
0

Add file named "Staticfile" in your home directory and add below code to this file.

    pushstate: enabled
Saurabh
  • 13
  • 5
  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 13 '22 at 11:14
0

I just change :
problem: ---> try_files $uri $uri/index.html =404;
solution: ---> try_files $uri $uri /index.html;
and problem solved. my website running now without problem

  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 05 '22 at 08:55
0

for react app, do not give alias directive, instead use root directive is the way to resolve this.

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 25 '22 at 14:18
-1
location / {
    root /path/to/root/directory/of/staticfiles;
    index index.html;
    try_files $uri /index.html;
}
sagarpatidar
  • 1,532
  • 1
  • 16
  • 19
  • Code-only answers are discouraged on Stack Overflow because they don't explain how it solves the problem. Please edit your answer to explain what this code does and how it improves on the existing upvoted answers, so that it is useful to the OP as well as other users with similar issues. – FluffyKitten Aug 21 '20 at 19:46