Nginx Location based try files? - nginx

I was reading this page here https://help.sorryapp.com/en/articles/2783542-install-maintenance-pages-on-nginx that had a nifty idea of having a file present means nginx would route to a maintenance html page.
But then reading through the nginx docs it seems like if statements within the location block are not ideal, and instead to use try files. Whats the proper way to rewrite whats in the above to how nginx would like it? https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/
I assume is something like: but what about a rewrite?
try_files /my/file/path/maint.on
error_page 503 #maintenance_page;
location #maintenance_page {
rewrite ^(.*)$ /maintenance_page.html break;
?
UPDATE 1
this is my current config snippit, which happens to for some reason result in a 404 even through the maint.on file doesn't exist.
location / {
if (-f /opt/staytus/staytus/maint.on) {
return 503;
}
port_in_redirect off;
proxy_pass http://example.com:8787/;
}
error_page 503 #Performing-Maintenance;
location #Performing-Maintenance {
rewrite ^(.*)$ Performing-Maintenance.html break;
}
}
any thought on the issue?

As the same article states,
The only 100% safe things which may be done inside if in a location context are:
return ...;
rewrite ... last;
so the example you're found can be considered completely safe. (I'd say it is safe to use any directive from ngx_http_rewrite_module inside the if block which extends this list to break, return, rewrite and set). You can't do what you want with the try_files directive because it is requires at least one file argument before the last uri (or the name of named location or HTTP error code) argument which would be used if none of the files/directories from the list are actually exists. Well, I could imagine something like
location / {
try_files /maintenance.html #default;
}
location #default {
...
}
but you can't make it serving some location like
location = /maintenance.html {
...
}
, it would just return the contents of maintenance.html file. And if maintenance.html page would refer to some additional assets (like CSS, JS etc.) all user browser requests for that assets would lead to the maintenance.html contents (because that file exists and passed the try_files check). Just FYI, this directive
location / {
try_files $uri $uri/index.php =404;
}
...
location ~ \.php$ {
...
}
won't serve the $uri/index.php file through the PHP location handler (it just return its raw content), while this
location / {
index index.php;
try_files $uri $uri/ =404;
}
would.
However example you provided would have some performance impact (especially on the high-load servers) due to the extra stat kernel call made for every incoming request. I'd recommend this method of enabling maintenance mode with nginx.

Related

NGINX ignore hash css file and fetch any css that exists

I'm cache-busting with hashed css files (app-123456.css). The css file requests are proxied to a cdn with nginx. I need to keep the files statically named on the cdn, as there is a requirement to allow the customer to modify some css and re-upload the file. How can I pass the hashed file request to cdn and return the statically named file? For example a request to app-123456.css would return app.css, if it existed on the cdn. I'm trying to use try files but have been unsuccessful. Will cache-busting still work in this scenario, if the returned file is statically named? Thanks for any help.
location ~* (.+)\.(?:\d+)\.(css)$ {
try_files $uri $1.$2 #styles;
}
location #styles {
autoindex on;
proxy_pass http://[url].net; # needs to go to http://[url].net/styles/
}
EDIT
location ~* (.+)-(?:\d+)\.(css)$ {
try_files $uri $1.$2 #styles;
}
location #styles {
autoindex on;
rewrite ^(.+)-(?:\d+)\.(css)$ /styles$1.$2 break;
proxy_pass http://[url].net; # needs to go to http://[url].net/styles/
}
Fixed
^(.+)\-([a-zA-Z0-9]*)\.(css)$
You need to modify the URI within the named location before passing it upstream with proxy_pass. This can be accomplished using a rewrite...break statement. See this document for details.
For example, using your updated regular expression:
location ~* ^(.+)\-(?:[a-zA-Z0-9]*)\.(css)$ {
try_files $uri $1.$2 #styles;
}
location #styles {
rewrite ^(.+)\-(?:[a-zA-Z0-9]*)\.(css)$ /styles$1.$2 break;
proxy_pass http://...;
}
The above solution basically applies the same regular expression to the URI twice, which seems inefficient and redundant.
If the /styles/ URI prefix is unique to the upstream server, you could perform the translation in the original try_files statement. See this document for details.
For example:
location ~* ^(.+)\-(?:[a-zA-Z0-9]*)\.(css)$ {
try_files $uri $1.$2 /styles$1.$2$is_args$args;
}
location ^~ /styles/ {
internal;
proxy_pass http://...;
}
The ^~ operator give the prefix location a high precedence (see this document for details) and the internal directive prevents the URI from being directly accessible (see this document for details).

Nginx rewriting pushstate static resources wont load

I am trying to get nginx to work with a pushstate based uri handled by react-router.
Everything works fine until I try to F5 on a second level uri example.com/MyApp/users.
My static resources are in example.com/MyApp/resources.
The problem is that nginx is trying to load my resources in example.com/MyApp/users/resources whenever I try to access directly (or F5) the users's view.
Here is my nginx conf :
location ~ ^/MyApp/ {
try_files $uri /MyApp/index.html last;
}
I am new to nginx so I don't really know how everything works...
EDIT :
I changed my conf to this:
location / {
if (!-e $request_filename){
rewrite ^(.*)$ /MyApp/index.html break;
}
}
Now accessing to example.com/MyApp/users works but example.com/MyApp/users/ doesn't.
With client side app paths:
/
/foo
/foo/bar
/foo/bar/baz
/foo/bar/baz/123
/tacos
/tacos/123
Use nginx configuration:
server {
listen 80;
server_name example.com;
root /var/www/example.com;
gzip_static on;
location / {
try_files $uri $uri/ /index.html;
}
# Attempt to load static files, if not found route to #rootfiles
location ~ (.+)\.(html|json|txt|js|css|jpg|jpeg|gif|png|svg|ico|eot|otf|woff|woff2|ttf)$ {
try_files $uri #rootfiles;
}
# Check for app route "directories" in the request uri and strip "directories"
# from request, loading paths relative to root.
location #rootfiles {
rewrite ^/(?:foo/bar/baz|foo/bar|foo|tacos)/(.*) /$1 redirect;
}
}
This configuration will work within a pushState "directory" such as example.com/foo/bar/baz/213123 and resolve static files at relative paths like js/app.js to example.com/js/app.js instead of example.com/foo/bar/baz/js/app.js.
For cases with directory depth beyond the first level such as /foo/bar/baz, note the order of the directories declared in the #rootfiles directive: the longest possible paths need to go first, followed by the next shallower path /foo/bar and finally /foo.
See this related answer to a similar question regarding Backbone.
I think you will have to do something like this:
location ~ ^/MyApp/ {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ /index.html =404;
}
location ~ ^/MyApp/resources {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ /resources/index.html =404;
}

nginx rewrite with try_files 403

I have a webserver with /usercp/ and usercp.php. I'm using tryfiles and re-write to see if file.php exists do file, otherwise goto /file/ (in my case file = usercp)
Here is my nginx conf.
location / {
try_files $uri $uri/ #extension-php;
}
location #extension-php {
rewrite ^(.*)$ $1.php last;
}
This also makes site.com/usercp/ give a 403 error. Any ideas?
The problem is that you are prioritizing the folder indexing over the php file if you want the opposite I recommend not to use the autoindex on because it exposes the contents of your folder and swap the last 2 items in the try_files, try this
location / {
try_files $uri $uri.php $uri/;
}
PS: $uri/ will always return 403 if it doesn't contain the index file specified in index because by default it forbids folder listing, you should either put the index file if that's what you intend to do, or just remove the whole $uri/ from the try_files so that it would return 404 instead of 403
http://nginx.org/r/try_files
What it does is simply checks the existence of files, and then serves the file that exists.
You claim /usercp/ exists. As such, that's what it'll try to serve. But you probably don't have autoindex on, hence, directory listing is disallowed — 403 Forbidden.

How to configure nginx to try_files first, if not exists follow the request_uri

We have page caches with id partitioning and subdomain. Say for requests like ny.site.com/cat/12345 or la.site.com/dog/234, nginx need to
check if file /cat/ny/1234/5.html exists, return it
otherwise, just use the original request_uri to hit the app server, and the cache file will be created
We managed to figure out the subdomain and id partitioning part, but didn't get any luck on the try_files part. Always get indefinite loop errors like rewrite or internal redirection cycle while internally redirecting to
our nginx.conf file is like
rewrite "/cat/([0-9]{4})([0-9]{1,4})" /system/cache/cat/$subdomain/$1/$2.html break;
rewrite "/cat/([0-9]{1,4})" /system/cache/cat/$subdomain/$1.html break;
try_files $uri $request_uri;
Any hints? Thanks!
UPDATE:
I tried the following. Nginx was looking for $request_uri (e.g., /cat/12345) in the file system instead of hitting the app server. Any thoughts?
try_files $uri #old;
location #old {
rewrite ^ $request_uri break;
}
Try with this
location ^~ ^/cat/([0-9]{4})([0-9]{1,4}) {
try_files "/cat/ny/$1/$2.html" #app_server;
}
location #app_server{
# pass this to your app server for processing.
}
Use ^~ as this will also include the edge case like /cat/12345/ (ending slash).
And just be sure whether you want $uri (which is without query string) or $request_uri
( which contains query string).
I never tried this my self before but this is how I would write it
location / { # or whatever location you see fit to your requirements
try_files $uri.html $uri;
# I don't know if the `.` needs to be escaped `$uri\.html`, you can try both
}

nginx rewrite nice urls with homemade CMS

I have a home-made CMS, serving a site which I inherited. I'm not really familiar with nginx rewrite rules, although I could set up tiny URLs. Here is my relevant part of the configuration:
*location / {
index index.php index.html;
root /var/www/www.valami.hu;
try_files $uri $uri/ #seo;
}
location #seo {
rewrite ^/([a-z]+)$ /index.php?oldal=$1 last;
break;
}*
The problem is that the site has a blog which is located on blogspot.com and the stuff from the blog is taken from there. So what I need help with is a rule for this sort of URL:
http://www.valami.hu/index.php?oldal=blog&options=2012/01/some-title-here.html
So, it would be fine like:
http://www.valami.hu/blog/2012/01/some-title-here
The most important is the first rule should be work also as it is more frequently used.
This is actually trivial. Watch and learn!
location / {
try_files $uri $uri/ #site;
}
location #site {
rewrite ^/blog/(.+)$ /index.php?oldal=blog&options=$1 last;
rewrite ^(.+)$ /index.php?oldal=$1 last;
}
The order makes all the difference. You can also do it by removing the last flag and redirecting to /blog with the options query string parameter explicitely set. No if is needed.
well seems we only have 2 cases, the /blog and the non /blog, I'd write 2 location blocks
location ~ ^/blog/(.*) {
try_files $uri /index.php?oldal=blog&options=$1;
}
location ~ /(.*) {
try_files $uri /index.php?oldal=$1;
}
I would have used just / and $request_uri in the second location but that would put a preceeding / in olda1, if that wouldn't matter with you then i'd prefer that method, cause it doesn't involve regex.
About index index.php index.html; and root /var/www/www.valami.hu;, it's better if you move them to the server block instead of the location block, if possible of course.

Resources