dcsan
dcsan

Reputation: 12305

react router, nginx, node, static files

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

Answers (1)

dcsan
dcsan

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

Related Questions