React & nginx routing to subdirectory - reactjs

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.

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.
Update your BrowserRouter by adding a basename. Example: <BrowserRouter history={history} basename="/webapp">.
Specify a homepage on your package.json. Example: "homepage": "/webapp".
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:
Added "homepage": "/metronome", to the package.json file
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>
yarn run build
I uploaded the contents of the build directory to this location on my server /var/www/personalwebsite.com/metronome
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;
}

Related

Serve dynamic routes with nginx in a NextJS application

I use nginx as my static file server for my NextJS application, in order to test it in dev environment. My application follows a pattern in which I have, normaly, the following routes:
someRoute/
index.tsx
register.tsx
[id].tsx
My nginx.conf file has the following content:
worker_processes 4;
events { worker_connections 1024; }
http {
server {
listen 80;
root /usr/share/nginx/html;
include /etc/nginx/mime.types;
try_files $uri $uri/ /index.html /register.html;
}
}
What is happening is that, when I create a docker image of the application using nginx, if i try to access someRoute/register or someRoute/123, I always get the localhost/index page. someRoute/index works fine, but the other two don't.
My guess is that when I try to navigate to someRoute/123 nginx expects to find 123.html inside $uri/, which of course won't happen, since it is a dynamic route. As per register.html, I really don't know what's wrong.
How do I get someRoute/register and someRoute/[id] working?

Deploying React App created by CRA (Create React App) to different ENVIRONMENTS, that have different URL PATHS?

Problem:
We have a CRA (Create React App) application that we need to deploy to many different environments. We're using Kubernetes to spawn these environments so we will have many of them, the number is not fixed.
The problem is that those environments must be under the same domain name and must have the same path structure. (this is a business requirement and we cannot influence it).
Example of environments:
https://www.example.com/company/app-env01/react_application/
https://www.example.com/company/app-env02/react_application/
https://www.example.com/company/app-env03/react_application/
https://www.example.com/company/app-env-foo/react_application/
https://www.example.com/company/app-env-bar/react_application/
https://www.example.com/company/app/react_application/
So the fixed structure is: https://www.example.com/company/app[-____]/react_application/
The way to make it work on a single environment would be to specify PUBLIC_URL in package.json build script:
...
"build": "PUBLIC_URL=/company/app-env01/react_application react-scripts build",
...
This works fine for ONE environment only (env01 in this case), but we need to deploy a single build artifact (static file bundle) to MANY different environments, which have different PUBLIC_URLs.
Is this possible to achieve without building the application for every environment?
How we build the artifact:
Our deployment artifact is a Docker image, which is just Nginx serving previously built React static files.
How we perform routing:
The Browser is hitting our Kubernetes Ingress, which strips the path away and forwards the request to a Docker Container (in a K8S Pod) which is running Nginx. Nginx is serving the CRA static files under the root directory /.
Example:
Browser
↓
https://www.example.com/company/app-env01/react_application/
↓
Ingress
/
↓
Nginx
↓
Serves the CRA static files
This works fine, the problem (to me at least it seems) is in React Router. We are setting the basename dynamically, and it is being set correctly (https://reactrouter.com/web/api/BrowserRouter/basename-string). The problem (I assume) is in this PUBLIC_URL. Deploying the application without specifying it does not work. And it needs to be known at build time. That's the main issue.
IMPORTANT:
We are using React Router, so it must work properly when the application is deployed
We want to deploy a single build artifact (a single Docker Image) across all environments
Solution
#Emile got me thinking about using relative URLs again, along with configuring Nginx to handle it correctly. Thank you!
Adding this location block to the Nginx configuration solved the problem:
location ~ .(static)/(js|css|media)/(.+)$ {
root /usr/share/nginx/html;
try_files $uri $uri/ /$1/$2/$3;
}
Here's the full configuration (simplified for the sake of clarity):
server {
listen 80;
# This rule internally redirects any relative requests for static files so that they start from the root
# Example, it internally redirects `/RANDOM/SUBPATH/static/js/main.xxx.chunk.js` to `/static/js/main.xxx.chunk.js`
# Effectively, it strips everything that comes before `/static...`
location ~ .(static)/(js|css|media)/(.+)$ {
root /usr/share/nginx/html;
try_files $uri $uri/ /$1/$2/$3;
}
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Further explanation
The reason that using relative URLs originally did not work is:
This would work just fine:
/company/app-env01/react_application/static/js/xxxxxxxx.chunk.js
but this would not:
/company/app-env01/react_application/RANDOM/SUBPATH/static/js/xxxxxxxx.chunk.js
I needed a way to "strip off" the /RANDOM/SUBPATH part, whatever that part is, and I achieved it adding the Nginx location block listed above.

How to Serve "out" (next export) folder Nextjs with Nginx

I am currently learning to deploy applications made with NextJs to VPS. I have been successful, running some REST APIs on the Nginx server, I am not using the NextJs api feature, this is separate using Express. This is executed using PM2.
But I am confused, how do I serve NextJs "out" the results folder "next build && next export", this is a dashboard page that fetches data on the client side.
Do I have to treat the same with the REST API using PM2 or a different treatment, can you please provide an example configuration file of nginx for this.
I have tried googling but there is no exact answer about this.
Thanks in advance, I appreciate any answer.
server {
server_name your-website.com;
location / {
root /app; # name of the folder where you put content of out directory, try files will be relative to this path
try_files $uri $uri.html $uri/ =404; # try different strategies to find matching file in the folder with build, otherwise throw 404 error
}
error_page 404 /404.html; # if 404, serve this file
}

NGINX react app served in subdirectory endless redirect outside server

I have created React application using create-react-app and react-router-dom. I have deployed it on my UAT server using NGINX and want to serve it in subdirectory myUatServerDomainUrl/MyPortal.
I can access it without problems by Chrome on my UAT Server using addresses like: localhost/MyPortal (redirects to localhost/MyPortal/), localhost/MyPortal/ myUatServerDomainUrl/MyPortal/.
If I try to access the site from other computer using in Chrome URL
http://myUatServerDomainUrl/MyPortal/ then I get endless loop asking for
http://myUatServerDomainUrl/MyPortal/index.html/index.html/index.html/index.html/index.html/index.html(...)
The first request I send is http://myUatServerDomainUrl/MyPortal/ It returns 301(Moved pernamently), and adds in response headers 'Location' = http://myUatServerDomainUrl/MyPortal/index.html/ The next request returns 'Location' = http://myUatServerDomainUrl/MyPortal/index.html/index.html/ , and so on.
I can access from my other computer single files like:
http://myUatServerDomainUrl/MyPortal/static/js/2.3d3c3914.chunk.js,
http://myUatServerDomainUrl/MyPortal/manifest.json
and
http://myUatServerDomainUrl/MyPortal/index.html (displays white screen, body contains message "You need to enable JavaScript", but this request downloads 2.3d3c3914.chunk.js and 2.3d3c3914.chunk.js.chunk.js too)
nginx.conf
server {
listen 80;
server_name ~.;
(...)
root C:/fold1/fold2/MyPortalProjectDeploymentFolder;
location /MyPortal/ {
try_files $uri $uri/ index.html /index.html /MyPortal/index.html;
}
}
App.tsx
<BrowserRouter basename="/MyPortal">
<Switch>
<Route exact path="/" component={process.env.NODE_ENV === "development" ? require("react-hot-loader/root").hot(Home) : Home} />
</Switch>
</BrowserRouter>
manifest.json
start_url: "./index.html",
package.json
"homepage": "/MyPortal", # also tried "."
Why when I try to access my app outside my server I get this strange behaviour?

CakePHP 3 on nginx not loading css and js files

I am trying to configure CakePHP 3 on OSX running nginx. The default page reports that everything is working except URL rewriting. However, I have URL rewriting working for page URLs (just followed the instructions for nginx setup). The only thing that's not working is loading static assets from webroot. I've been digging through a ton of similar stackoverflow questions and none of the responses seem to work.
vhost file:
server {
listen 80;
server_name albums.dev;
root /Users/username/Sites/albums;
access_log /Library/Logs/default.access.log main;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include /usr/local/etc/nginx/conf.d/php-fpm;
}
}
Again: The entire CakePHP application seems to be working correctly, except the static assets in /webroot/ are coming up as 404.
change the root .. you must point to webroot of your project
if you want i can give my conf to you

Resources