Search code examples
phpreactjsnginxnginx-confignginx-location

Nginx root location with proxy_pass and subpath with try_files


I have an Nginx server that must combine one React app and another Nginx with a PHP configuration as follows:

  1. On /client path serves a React app with the files hosted on the current Nginx instance.
  2. On / (root) path must serve another app from an internal IP.

This is the current configuration:

worker_processes     2;
worker_rlimit_nofile 32768;

events {
  worker_connections 16384;
}

http {

  server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;
    server_name domain.com;
    location / {
      return 301 https://$host$request_uri;
    }
  }

  server {

    include mime.types;

    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
    gzip_disable "MSIE [1-6]\.";

    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server ipv6only=on;

    ssl_certificate       /app/ssl/cert.pem;
    ssl_certificate_key   /app/ssl/key.pem;
    ssl_session_timeout   5m;
    ssl_protocols         TLSv1 TLSv1.1 TLSv1.2;

    server_name domain.com

    location /client {
      root /app/build/;
      index index.html index.htm;
      try_files $uri $uri/ /index.html;
    }

    location / {
        proxy_pass http://192.168.1.1;
        proxy_http_version  1.1;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_connect_timeout 159s;
        proxy_send_timeout   120;
        proxy_read_timeout   120;
        proxy_buffer_size    64k;
        proxy_buffers     16 32k;
        proxy_busy_buffers_size 64k;
        proxy_temp_file_write_size 64k;
    }

  }
}

And the following Nginx for 192.168.1.1 instance:

server {
    listen 80;
    index index.php index.html;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/html/public;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";

    index index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass 192.168.1.2:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

In this configuration it will display only the proxy_pass, even if I type the /client path. If I remove the proxy_pass location directive, the client path with try_files is working.

Note 1: React has a basename /client in createBrowserHistory.

Note 2: The first Nginx it worked before, but proxy_pass source was a public URL.


Solution

  • Your current location /client block is looking for files in the wrong place, so always defaults to /index.html which is processed by the location containing proxy_pass.

    The root directive forms the path to the file by concatenating the root value with the path element of the URL. So the URL /client/foo will resolve to a pathname /app/build/client/foo, which is not what you want.

    The alias directive works with the location value to translate the URL into a pathname by substitution.

    For example:

    location /client {
      alias /app/build;
      index index.html index.htm;
      try_files $uri $uri/ /client/index.html;
    }
    

    So the URL /client/foo will resolve to a pathname /app/build/foo.

    Note that the location and alias values should both end with a / or neither end with a / for correct substitution.

    Note that the last parameter of a try_files directive is a URI, error code, or named location. In this case, the correct URI should be /client/index.html.