Reputation: 12305
I know similar questions have been asked but I can't find an answer for the most common node/react/nginx config.
Backend node app I want to reverse proxy to on :port client is built with create-react-app and built I want "deep links" with react-router to work I want to serve static files with nginx not node
After compiling the client, I move it into server/build
and then deploy the whole server
folder.
So question 1 is if this is the best final structure for deployment?
The reason I like this is that the built files are cleanly in a build
directory, and not munged up in public
with other server side files such as images so can be replaced on next build easily.
So the server looks something like this:
/mnt/ext250/web-apps/cbg.rik.ai/
├── build
│ └── index.html
│ └── static
│ ├── css
│ ├── js
│ └── media
// files that were in server/public
├── public
│ └── images
│ ├── items
│ ├── logo
│ └── rooms
server.js
So I pm2 start up the server.js
App works fine directly on :port:
App works fine at the root eg domain.com and I can use client links.
But when I directly load a "deep link" the server times out.
So the question is how to configure the index
to be served for deep links
and still keep API routes working to the node backend.
Do I need to have clear different routes, eg:
# declare API routes first
location /api {
try_files $uri @backend ;
}
# then everything else?
location / {
try_files $uri build/index.html;
}
When I do set this it seems the main site gets served as the wrong mimetype or something...:
Uncaught SyntaxError: Unexpected token '<'
main.dd03fa6d.chunk.js:1 Uncaught SyntaxError: Unexpected token '<'
cbg.rik.ai/:1 Resource interpreted as Stylesheet but transferred with MIME type text/html: "https://cbg.rik.ai/static/css/main.573d8e92.chunk.css".
Full config:
server {
listen 80;
server_name cbg.rik.ai;
root /mnt/ext250/web-apps/cbg.rik.ai;
access_log /var/log/nginx/cbg.access.log;
error_log /var/log/nginx/cbg.error.log;
index index.html;
# for other browser deep link routes serve the index file
location / {
try_files $uri build/index.html @backend;
}
# proxy to node app @backend
location @backend {
proxy_pass http://localhost:33010;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Following is necessary for Websocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# certbot stuff
}
related: React-router and nginx
try_files documentation https://docs.nginx.com/nginx/admin-guide/web-server/serving-static-content/#trying-several-options
Upvotes: 2
Views: 6080
Reputation: 12305
OK the problem for me after much hair pulling was that some source static files had the wrong permissions. This may save someone else some time.
I use a Makefile
for these tasks and added a fixPermissions
task. The Makefile is nice to handle dependent tasks so I can have:
clean:
rm -rf client/build
rm -rf server/build
# image files can have wrong permissions when copied from internet
fixPermissions:
# directories 755
find server/cdn -type d -exec chmod 755 {} \;
# files 644
find server/cdn -type f -exec chmod 644 {} \;
build: clean fixPermissions
cd client && npm run build
move:
mv client/build server
prep: clean build move
sync:
rsync -avi --delete \
server/ ${login}:${deploydir}
echo "done"
deploy: prep sync pm2restart
Then deploy is just make deploy
and even with filename completion with zsh. Old Skool but it works!
final nginx config:
# cbg.rik.ai
# port: 33010
server {
listen 80;
server_name cbg.rik.ai;
access_log /var/log/nginx/cbg.access.log;
error_log /var/log/nginx/cbg.error.log;
root /mnt/ext250/web-apps/cbg.rik.ai/build;
# static files from server/cdn
# make sure files are 644
# better to use alias than have two roots
location /cdn/ {
alias /mnt/ext250/web-apps/cbg.rik.ai/cdn/;
try_files $uri $uri/ default.png;
}
# for other browser deep link routes serve the index file
location / {
try_files $uri $uri/ /index.html;
}
# proxy to node app @backend
location /api {
proxy_pass http://localhost:33010;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Following is necessary for Websocket support
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# followed by certbot stuff
}
I'm not quite sure if the ordering of the locations has impact. Anyway a few hours wasted on this stuff so hopefully helps someone else. Or probably later me :0
Upvotes: 2