React & nginx routing to subdirectory

Viewed 16857

Just started with using React. I have an app created with create-react-app which should be running on a sub-directory while making API calls to a different path.

React App:

location on server: /var/www/myapp/build

endpoint: https://foo.example.com/analytics

Data API endpoint: https://foo.example.com/api/data

Nginx setup

    location /analytics {
           root /var/www/myapp/build;
           try_files $uri /index.html;
    }

When setting "homepage":"https://foo.example.com/analytics" in the client's package.json, all the resource paths seem to be correct (i.e. https://foo.example.com/analytics/static/...), but when checking networking no request to .../api/data shows up in my browser's networking inspector and the app doesn't properly spawn.

Using absolute paths in the App's API call (fetch('https://foo.example.com/api/data') instead of fetch('/api/data')) doesn't seem to help, either.

When instead I set "homepage":"." in package.json and also change the Nginx config to serve the react build directory on server root, the app works.

server {
        root /var/www/myapp/build;
}

However, in this case, the app is also available under https://foo.example.com, which is something I don't want.

I strongly suspect this has to do with routing, but couldn't figure out how to fix it. So any help would be much appreciated!

--- Edit / Solution ---

I doubt it's the most straight forward solution, but the following setup works for me:

React App

In package.json, set "homepage":"./analytics" before running npm run build

Nginx config:

    location =  /analytics {

            root /var/www/myapp/build;
            try_files /index.html =404;
    }

    location ~ ^/analytics(.*) {

            root /var/www/myapp/build;
            try_files $1 $1/ /index.html =404;
    }

My understanding is that the initial setup using try_files $uri was looking for files in the root directory /var/www/myapp/build for the full uri rather than only the path that follows /analytics. E.g. when requesting ../analytics/css/styles.css it would check if a file (or directory) is available under /var/www/mayapp/build/analytics/css/styles.css which doesn't exist, so it kept serving the index.html as fallback. Hence the regex workaround.

Feedback to improve this solution still very welcome, though.

4 Answers

I was struggling with the same problem. Finally I was able to solve it using official documentation and a combination of answers:

Assumptions:

  • Your React App is based on create-react-app package (you are using react-router-dom).
  • You are using Nginx and the root path is being used by another service (or even another React/Gatsby App which is my case).
  • You want to deploy the React App on a subdirectory and be able to serve all statics of your React App from that subdirectory.

React App Changes:

Based on official documentation.

  1. Update your BrowserRouter by adding a basename. Example: <BrowserRouter history={history} basename="/webapp">.
  2. Specify a homepage on your package.json. Example: "homepage": "/webapp".
  3. If you are referencing a static file by its relative path, you should add the subdirectory to that reference. Example: src="/static/logo/logo.png" becomes src="/webapp/static/logo/logo.png".

Nginx Changes:

location ^~ /webapp {
   alias /var/www/myapp/build;
   try_files $uri $uri/ /webapp/index.html;
}

Here is an example of nginx location configuration:

location ^~ /analytics  {
    alias /var/www/myapp/build;

    subs_filter href="/ href="http://foo.example.com/analytics;
    subs_filter src="/ src="http://foo.example.com/analytics;
}
  • The location is set to ^~ /analytics , meaning that the rules created in the location braces will become effective when somebody visits http://foo.example.com/analytics
  • The alias is set to the static build folder of create-react-app site /var/www/myapp/build. That’ll be served when the visitor hits your subdirectory url foo.example.com/analytics
  • Next, the two subs_filter lines replace any reference to href and src urls that start with the React app’s home directory / with the new complete URL. That will ensure all your CSS and JS files are located and served correctly by NGINX.

The final thing, in the case of Create-React-App is that any references to createBrowserHistory in your react router need to be replaced by createHashHistory, as Browser History won’t work with the above NGINX configuration.

My website is called derekdawsonspersonalwebsite.com and I wanted to serve a react app I made at derekdawsonspersonalwebsite.com/metronome/

I got this working by doing the following:

  1. Added "homepage": "/metronome", to the package.json file
  2. If you are using react router, add <BrowserRouter basename="/your_subdirectory">, in my case:
<BrowserRouter basename="/metronome">
    <div>
        <nav>
            <Link to="/"></Link>
        </nav>
        <Switch>
            <Route exact path="/" component={Metronome} />
        </Switch>
    </div>
</BrowserRouter>
  1. yarn run build
  2. I uploaded the contents of the build directory to this location on my server /var/www/personalwebsite.com/metronome
  3. This is what my server block /etc/nginx/sites-available/personalwebsite.com looks like
server {
    listen 443 ssl;

    server_name derekdawsonspersonalwebsite.com www.derekdawsonspersonalwebsite.com;
    ssl_certificate /home/derek/ssl/derekdawsonspersonalwebsite.com_chain.crt;
    ssl_certificate_key /home/derek/ssl/derekdawsonspersonalwebsite.com_tld.key;

    location / {
        root /var/www/personalwebsite.com;
        index index.html;
    }

    location /metronome {
        root /var/www/personalwebsite.com;
        index index.html;
    }
}

server {
    listen 80 default_server;
    server_name derekdawsonspersonalwebsite.com www.derekdawsonspersonalwebsite.com;
    return 301 https://$host$request_uri;
}

Deploy Reactjs & Laravel with subdirectory using NGINX

What we try to achieve here is to run the Laravel and reactjs applications in a subdirectory of the main domain. For example: domain.com/second/.

Finally, I was able to solve it using official documentation and a combination of answers.

in this GitHub repo, I define both reactjs and laravel configuration and attached the real configuration file. https://github.com/SyedAsadRazaDevops/How-to-Deploy-Reactjs-and-Laravel-with-subdirectory-using-NGINX

@syedasadrazadevops

Related