Reputation: 686
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.
Upvotes: 28
Views: 31317
Reputation: 1
Thank you Juan García, in my case i was using vite and added
base: "/webapp"
in vite.config.ts file instead of adding homepage in package.json
Upvotes: 0
Reputation: 81
I did the following to get it working
PUBLIC_URL=/analytics/ npm run build --production
location /analytics {
# Maps /analytics to /
rewrite ^/analytics$ / break;
# Maps /analytics/.. to /..
rewrite ^/analytics(/.*) $1 break;
try_files $uri /index.html =404;
}
Upvotes: 2
Reputation: 1878
I was struggling with the same problem. Finally I was able to solve it using official documentation and a combination of answers:
Assumptions:
create-react-app
package (you are using react-router-dom
).React App Changes:
Based on official documentation.
BrowserRouter
by adding a basename
. Example: <BrowserRouter history={history} basename="/webapp">
.homepage
on your package.json
. Example: "homepage": "/webapp"
.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;
}
Upvotes: 59
Reputation: 522
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:
"homepage": "/metronome",
to the package.json
file<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
/var/www/personalwebsite.com/metronome
/etc/nginx/sites-available/personalwebsite.com
looks likeserver {
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;
}
Upvotes: 4
Reputation: 874
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;
}
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 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 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.
Upvotes: 5