Nginx locations - reactjs

I'm working on a multi-tenant application in React and some clients want to upload .html files to the root of the project to use google console and things like that. I would not like all those files to be mixed with the application code so apart from the following code:
location / {
try_files $ uri /index.html = 404;
}
I would like to add in NGINX a location block that allows me to divert to another folder any other .html file that starts in /, excluding cases like /static/example.html.
Example:
/ -> React default
/static/*.html -> React default
/*.html -> Derive to new folder
I would appreciate any help in this regard.
I tried something like this...
location /*.html {
root /extras_folder;
}
location / {
root /project_folder;
try_files $uri /index.html =404;
}
But does not work

This adheres to the rules you described:
location ^~ /index.html {
root /project_folder;
try_files $uri /index.html =404;
}
location ~ ^/[^/]+\.html {
root /extras_folder;
try_files $uri /index.html =404;
}
location / {
root /project_folder;
try_files $uri /index.html =404;
}
Second block is a regex match only on *.html in the root path
Third block is for all other paths
First block is to cover the edge case of / being /index.html - regex rules otherwise always get priority over path location blocks

What about this?
server {
listen 80;
root /project_folder;
location / {
try_files $uri #extras_folder;
}
location #extras_folder {
root /extras_folder;
try_files $uri #index_html;
}
location #index_html {
try_files /index.html =404;
}
}
This looks in /project_folder first, in /extras_folder second and, if still no file is found finally serves /project_folder/index.html (or 404 if that file doesn't exist).
You'd put uploaded files into /extras_folder in this case.

Related

Nginx conflicts static files when serving multiple React apps

I'm currently trying to set up multiple projects of React Apps using Nginx. So far, whenever I had static files conflicting, I'd just copy everything from a folder into the other (yes, it's an awful solution, but it was working so far). The problem is that now I have multiple projects on the same server, and although the previous solution would still work, it wouldn't be long before it's a complete mess. I've looked up Stack Overflow and many websites, and I've come to a configuration that looks like what I want to do, but it's not working properly.
This is my nginx.conf file:
#user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
server_names_hash_bucket_size 64;
#gzip on;
index index.html index.htm;
map $http_referer $webroot {
"/project1/main" "/home/username/project1main/build";
"/project1/admin" "/home/username/project1admin/build";
"/project2/main" "/home/username/project2main/build";
"/project2/admin" "/home/username/project2admin/build";
}
include /etc/nginx/conf.d/*.conf;
}
This is my server.conf file:
server {
listen 80;
server_name gcloud-server;
location /project1/main {
alias /home/username/project1main/build;
try_files $uri $uri/ /index.html =404;
}
location /project1/admin {
alias /home/username/project1admin/build;
try_files $uri $uri/ /index.html =404;
}
location /project2/main {
alias /home/username/project2main/build;
try_files $uri $uri/ /index.html =404;
}
location /project2/admin {
alias /home/username/project2admin/build;
try_files $uri $uri/ /index.html =404;
}
location /static {
root $webroot;
}
}
Is there a way to solve this problem like this? Or am I stuck into setting one /static location in which I'll have to copy every single projects' static files?
Thanks in advance.
As far a I can remember how an alias directive worked, you came into the following problem. Lets assume you've got a /project1/main/some/path/file request:
location /project1/main {
alias /home/username/project1main/build;
# here our internal variables are:
# $document_root = "/home/username/project1main/build"
# $uri = "/project1/main/some/path/file"
try_files $uri $uri/ /index.html =404;
# 1) try_files checks the existence of $document_root$uri physical file
# this is "/home/username/project1main/build/project1/main/some/path/file"
# which is absent
# 2) try_files checks the existence of $document_root$uri/ directory
# this is "/home/username/project1main/build/project1/main/some/path/file/"
# which is absent
# 3) you've got a 404 HTTP error
}
This problem didn't happen when you are using a root directive, but alias works this way. What you can do is
# use regex location match and capture URI suffix in a $1 variable
location ~ /project1/main(.*) {
alias /home/username/project1main/build;
# here our internal variables are:
# $document_root = "/home/username/project1main/build"
# $uri = "/project1/main/some/path/file"
# $1 = "/some/path/file"
try_files $1 $1/index.html =404;
# checked file is $document_root$1
# this is "/home/username/project1main/build/some/path/file"
# request would be served if this file exists
}

Nginx getting file not found on dynamic root

I am trying to load two different react app one on root level and one on sub location i.e /in. What I am doing is I am checking if $uri consist /in /t if that condition is true it will change root path after setting root path I am serving index file. Its not working its throwing 404 not found when i am trying to access domain.com/in/something and domain.com is working fine.
I don't know is it right way to do this or not. I tried this
Here is my nginx config file:
server {
server_name domain.com;
rewrite ^/(.*)/$ /$1 permanent;
set $rootpath "/var/www/html/website/public";
location / {
if ($uri ~ \/(in|t)\/){
add_header X-uri "$uri";
set $rootpath "/var/www/html/app/build";
}
root $rootpath;
try_files $uri /index.html;
}
}

Subfolder installation

I'm trying to add on cakephp on to an existing server, but the location / block is being used. I'm following the pretty url on nginx section on the cakephp cookbook. On my test environment, I have the server block looking like
server {
listen 80;
server_name localhost;
access_log /var/www/html/log/access.log;
error_log /var/www/html/log/error.log;
location / {
root /var/www/html/cakephp/app/webroot/;
index index.php;
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
root /var/www/html/cakephp/app/webroot/;
index index.php;
try_files $uri =404;
include /etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
From this, I'm able to run my testsController through the url localhost/tests
However, the server that I'm trying to add cakephp to, there is already another application installed at the domain root.
location / {
proxy_pass https://localhost/somepage;
}
I tried setting up a location block like
location /cakephp {
root /var/www/html/cakephp/app/webroot/;
index index.php;
try_files $uri $uri/ /index.php?args;
}
I understand that this wouldn't work because it's looking for cakephp in the url, which it wouldn't be there. Since root is set to be /var/www/html/cakephp/app/webroot, when I access the url localhost/cakephp, is it looking for /var/www/html/cakephp/app/webroot/cakephp?
I'm getting confused about how to set this up. I read about url rewriting and cakephp running in some subdirectory, but I'm not sure if that's what I am looking for. Right now, the application runs with http://localhost/someController. I would like to have the the application run with the url http://localhost/cakephp/someController. How should I setup my nginx config?
Fix static files first
With the config in the question, what you'll find is that nothing really works - not even requests for static files.
Consider:
server {
...
root /wherever/;
error_log /tmp/cakephp.err.log debug; # <- add this
location /cakephp {
root /var/www/html/cakephp/app/webroot/;
index index.php;
try_files $uri $uri/ /index.php?args;
}
}
This will produce:
$ curl -I http://cakephp.dev/cakephp/favicon.ico
HTTP/1.1 404 Not Found
The debug log will help to clarify why this occurs:
-> cat /tmp/cakephp.err.log
...
2015/08/23 10:53:43 [debug] 9754#0: *87 http script var: "/cakephp/favicon.ico"
2015/08/23 10:53:43 [debug] 9754#0: *87 trying to use file: "/cakephp/favicon.ico" "/var/www/html/cakephp/app/webroot/cakephp/favicon.ico"
Nginx is using the whole url as the path to a file, not just the bit after the location prefix. This is where understanding the difference between the root directive and the alias directive is important, and is also a common question (random result, there are many).
So, fixing that first:
server {
...
error_log /tmp/cakephp.err.log debug;
location /cakephp {
alias /var/www/html/cakephp/app/webroot/; # <- alias, not root
index index.php;
try_files $uri $uri/ /index.php?args;
}
}
Will produce:
$ curl -I http://cakephp.dev/cakephp/favicon.ico
HTTP/1.1 200 OK
Then fix php requests
The problem with php requests is more or less the same thing; though the request finds the right php file it's configured such that CakePHP will assume it's installed in the root. There are various solutions to this - here's one:
server {
...
error_log /tmp/cakephp.err.log debug;
location /cakephp {
alias /var/www/html/cakephp/app/webroot/;
index index.php;
try_files $uri $uri/ /cakephp/index.php; # <- redirect to the actual equivalent request
}
location /cakephp/index.php {
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
# Explicit script filename
fastcgi_param SCRIPT_FILENAME /var/www/html/cakephp/app/webroot/index.php;
}
}
In this way static files and dynamic requests both work - and the environment variables that CakePHP receives are such that it understands the root of the application to be /cakephp/.

nginx try_files and index not performing as expected

location /social {
index index.php;
try_files $uri /social/index.php;
}
When a user hits up a directory, it needs to run the local ./index.php
So far, when people hit up /social/ it runs index.php
When the user visits all unknown URLs, they get /social/index.php
However, when a user vists /social/subdir/ and there is a /social/subdir/index.php, it still runs /social/index.php. I need it to run /social/subdir/index.php
if I change the config to:
location /social {
index index.php;
try_files $uri $uri/index.php /social/index.php;
}
Then nginx serves up the CONTENT of social/subdir/index.php as content-type: octet/stream.
I thought index index.php would look for the paths index file.
php rendering block:
location ~ .php$ { ## Execute PHP scripts
if (!-e $request_filename) { rewrite / /index.php last; } ## Catch 404s that try_files miss
expires off; ## Do not cache dynamic content
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
}
I think your main issue is that you didn't use http:// before 127.0.0.1:9000 , also make sure that your php uses port 9000 not a sock file, otherwise you change the fastcgi_pass to unix socket.
Here's my simplified config.
Remove the index index.php from the /social block if it's the same value in the server block.
location /social {
# index index.php; # remove if not needed
try_files $uri $uri/ /social/index.php;
}
location ~* \.php$ {
include fastcgi_params;
fastcgi_pass http://127.0.0.1:9000;
}
First remove the index.php from the try_files directive so it will look like this
location /social {
index index.php;
try_files $uri $uri/ /social/index.php =404;
}
Also make sure that no other location block catches the /social/subdir/ request.
Lastly (irrelevant to your question, but very important) remove this line
if (!-e $request_filename) { rewrite / /index.php last; } ## Catch 404s that try_files miss
It is totally redundant and evil. try_files does not miss 404s. Have a look at this for more info IfIsEvil

Making pushState for backbone work in subpaths for nginx

I have two backbone applications and one API on the same subdomain but i am having trouble making pushStates work for the applications with correct location regex.
This is the paths im trying to accomplish
subdomain.domain.org/admin
subdomain.domain.org/client
subdomain.domain.org/api
I have tried to configure rewrite rules for client and admin but it always fail with 404 or 500 error. What would be the correct way to do this?
Here is just one example of all the combinations i have tried:
location ~ ^/admin.*$ {
alias /var/www/project/admin/public
rewrite ^(.+)$ /index.html last;
}
I figured it out after reading this https://serverfault.com/questions/361159/nginx-multiple-location-issues#361426
and ended up with this:
location ^~ /admin {
access_log /var/log/nginx/admin.access.log;
error_log /var/log/nginx/admin.error.log notice;
alias /var/www/project/admin/public/;
try_files $uri $uri/ /index.html;
rewrite ^/admin/(.+/)$ /admin/index.html last;
}
location ^~ /client {
access_log /var/log/nginx/client.access.log;
error_log /var/log/nginx/client.error.log notice;
alias /var/www/project/client/public/;
try_files $uri $uri/ /index.html;
rewrite ^/client/(.+/)$ /client/index.html last;
}

Resources