Using try_files with uwsgi - nginx

I am trying to use the nginx try_files directive with uwsgi_pass and having a ton of difficulty.
Basically what I want is for try_files to ask the uWSGI container if the request URI is valid and if not, then serve up the index.html file instead. My nginx config is as follows:
server {
listen 80;
access_log /tmp/nginx.log;
location / {
try_files $uri $uri/ /index.html;
include uwsgi_params;
uwsgi_pass 127.0.0.1:5001;
}
}
But what this does is check the docroot for every request and if its not there, it simply bails and returns the index.html file.
What I want instead is the following:
Request comes in for www.myapp.com
nginx forwards this request onto the uWSGI container
If that is invalid, then return the index.html
Is there a way to 'ask' uWSGI to try the files instead?
What I'm ultimately trying to accomplish here is HTML5 Pushstate with React Router. I'm running a Flask app with a React front-end. If the user refreshes the browser at www.myapp.com/preferences/userid, then I want nginx to forward that to the container and if its invalid, to return the index.

So, after talking with #Chamindu, I realized I was probably going about this the wrong way. I prevented uWSGI from serving my index.html (even though it could) and instead relied on nginx to serve that instead.
server {
listen 80;
access_log /tmp/nginx.log;
location / {
root /var/www/myapplication/;
try_files $uri $uri/ /index.html;
}
location /api {
include uwsgi_params;
uwsgi_pass 127.0.0.1:5001;
}
}

Related

Site is not redirecting to backend node NGINX config

I have a react frontend with a node backend but my nginx setup is currently not working. What I want to do is redirect https://sales.example.com/api/stats/get_customer_count/2323232 to http://127.0.0.1:3000/stats/get_customer_count/2323232(Node backend server runs on http://127.0.0.1:3000) but I keep getting 404 errors stating that the api path is not found. Not sure how to go about fixing this. Appreciate it. Thanks
server {
root "/home/sales/frontend/dist";
index index.html index.htm;
server_name sales.example.com;
error_log /var/log/nginx/error.log;
listen 80;
location / {
index index.html index.htm;
try_files $uri $uri/ /index.html =404;
}
location ~* ^/api/ {
rewrite ^/api/(.*) /$1 break;
proxy_pass http://127.0.0.1:3000;
}
}
This seems to be answered here already, and the explanation written by #Dayo is good.
Translated it to your example, it looks like this: (notice, the main difference is the tailing slash in the proxy pass)
location ~* ^/api/ {
proxy_pass http://127.0.0.1:3000/;
}
But please, read through the linked answer, before copying this over.

Configuring NGINX location to include subpaths

I have an NGINX location block configured as below. This redirects to an angular Application and works fine. However, when I navigate to a subpath in the angular application such as /path/subdir, then NGINX returns 404.
Apparently this location block only sends requests to /path but not /path/other to Angular.
location /path {
try_files $uri $uri/ =404;
}
I've tried variations such as these with the same result
location /path/
location /path/.*
How do I get NGINX so send all traffic sent to anything under /path to the same Angular application, so that the Angular application can then handle routing to sub-directories such as/path/subdir?
Well I ended up with this little horror show, but it seems to work.
location ~ ^/path(?:/(.*))?$ {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /path/index.html =404;
}

Reverse proxy nginx to itself

I am currently hosting a single-page react app that is hosted in the URL root like so:
server {
listen 80;
server_name localhost;
location / {
root /var/www/html;
try_files $uri /index.html;
}
}
I need to put the site behind an AWS elastic load balancer and at the same time change the path so everything is within a /support directory e.g. http://example.com/index.html -> http://example.com/support/index.html.
AWS ALBs do not support URL rewriting so I have to do this within the nginx config on the server. First of all I tried changing the config to:
server {
listen 80;
server_name localhost;
location /support {
alias /var/www/html;
try_files $uri /index.html;
}
}
This sort-of works but the URLs within the javascript content don't contain the /support path (e.g. they contain http://example.com/script.js instead of http://example.com/support/script.js).
I then tried creating a reverse-proxy config to proxy /support to /, which sadly put nginx in an infinite loop until it ran out of worker threads:
server {
listen 80;
server_name localhost;
location /support {
proxy_pass http://localhost:80;
}
location / {
root /var/www/html;
try_files $uri /index.html;
}
}
I'm confused why requests are going into a reverse-proxy loop? Shouldn't proxy_pass remove the /support prefix before proxying the request, and therefore it shouldn't be "caught" again by the /support location?
Just a guess.
Do you want to serve something on /?
If not - it is easy:
server
{
listen 80;
server_name localhost;
location /support/
{
alias /var/www/html/;
try_files $uri $uri/ /index.html;
}
location /
{
return 303 http://localhost/support$request_uri;
}
}
Fiddle around with the ending slashes if it does not work (using them - or not - makes often a difference).
Use alias instead of root so that /support is not added to the /var/www/html folder.
Everything gets redirected to /support.
If you want to serve something on / which is different from /support:
Use sub_filter or subs_filter in /support to rewrite your source code links on-the-fly so that they will never use /.
If you have redirects inside your source code (or proxy_pass backend) - you need proxy_redirect and/or Lua to catch and change them on-the-fly.

nginx: fallback to try_files when proxy_pass fails requires unusual config

I am using Nginx to server a single page app. Basically we just need to serve the index.html page whenever no matching file is found. The location looks like this and has been working just fine:
location / {
try_files $uri $uri/ /index.html
}
Now I would like to query an upstream server, and only if that fails, use the try_files directive as above
If the try_files is just moved to a fallback location like
location #fallback {
try_files $uri $uri/ /index.html;
}
location / {
proxy_pass http://127.0.0.1:8080;
proxy_intercept_errors on;
error_page 400 403 502 503 504 #fallback;
}
then - when the upstream server is unavailable - the client sees the Nginx 502 error page instead of the files served from the file system.
I finally found a solution that works by using a double slash in front of the /index.html fallback. This is the whole config file which can be used with the official nginx docker image for testing
events {
}
http {
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
server {
listen 80;
root /usr/share/nginx/html/;
location / {
proxy_pass http://127.0.0.1:9990;
proxy_intercept_errors on;
error_page 400 403 502 503 504 = #fallback;
}
location #fallback {
try_files $uri?$args /index.html //index.html;
}
}
}
which can be run with a command like
docker run -v /path/to/www/folder:/usr/share/nginx/html:ro -v /path/to/config/nginx.conf:/etc/nginx/nginx.conf -d -p 8080:80 nginx
In case no double slash is present before the last index.html fallback like
location #fallback {
try_files $uri?$args /index.html;
}
Then nginx constructs a path on the filesystem like <root>index.html, which has a missing delimiter instead of the correct <root>/index.html, whenever a url which is not the root url is requested.
Final question: why does this setup require a double slash within the try_files directive? Why can't one just use the try_files section from a regular config and move it to a fallback location used when intercepting errors?
I was presented with a similar situation, and I solved this going the other way around, using the suggestion from this page of common pitfalls. That is, first serve the static files, and then fallback to the proxy:
location / {
try_files $uri $uri/ #proxy;
}
location #proxy {
proxy_pass http://127.0.0.1:9990;
}
In this case, this would first look for the presence of the files as static files in the root, then proxy the request to http://127.0.0.1:9000. This is functionnally equivalent unless you want the files from the proxy to shadow the static files.

nginx to always serve the root index.html in every path

I have currently the code below. I am wondering if it's possible to still service this root even though I go to other pages like http://localhost/dog. The problem with my command below is it will return 404
server {
listen 80;
server_name localhost;
location / {
root /usr/src/app/angularjs/dist;
}
}
It is possible. Add the try_files directive to your location block, this will tell nginx to load all requests that cannot be matched to a filesystem path with your index.html:
try_files $uri /index.html;

Resources