Using try_files alongside rewrite in nginx location block - nginx

I already make extensive use of rewrite in nginx to perform this sort of thing:
/photos/123344 -> /photos/photos.php?id=123344
/photos/london-2016 -> /photos/photo-shoot.php?name=london-2016
Currently I have no rule for other (non-dynamic) pages. E.g
/photos/shoot-register.php -> /photos/shoot-register.php
Which I'd like to become
/photos/shoot-register.php -> /photos/shoot-register
But without specifying an individual rewrite rule for each .php file.
It seems that try_files is the correct directive here:
location ~ ^/photos {
try_files $uri $uri.php?$args;
rewrite ^/photos/([0-9]+)(/?)$ /photos/photo.php?id=$1;
rewrite ^/photos/([^/\.]+)(/?)$ /photos/photo-shoot.php?name=$1;
}
But this doesn't work, unless I delete the two rewrite lines.
I assume that means that execution doesn't stop after try files? It finds "shoot-register.php" but then carries on executing and ends up with /photos/photo-shoot.php?name=shoot-register.php?
How can I make it stop after try_files succeeds in finding a match?
Thanks

what if you move the rewrites to separate named location, and then change your try_file directive to try the file, then the php file and then directing to the new location?
location ~ ^/photos {
try_files $uri $uri.php?$args #rewrites;
}
location #rewrites {
rewrite ^/photos/([0-9]+)(/?)$ /photos/photo.php?id=$1;
rewrite ^/photos/([^/\.]+)(/?)$ /photos/photo-shoot.php?name=$1;
}

Related

Nginx Location based try files?

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.

Nginx two angular apps

I'd like to add separated angular app under a specific path (the path should be at the end of an URL to be matched) - I want to keep both versions which are current and a new one but the new should only be available under the specified path. I tried using alias + try_files. My config:
server {
listen 80;
root /dir/project1
server_name ...;
index index.html;
location ~ /path {
alias /dir/project2
try_files $uri $uri/ /index.html;
}
The thing is that when try_files fires up, it takes the path from the root directive - not from the alias. How to fix it? I can only add I cannot use proxy_pass here and root instead of the alias does not work either as it adds paths etc.
The alias directive works differently when placed inside a regular expression location, but you should probably be using a prefix location anyway. See this document for details.
Also, the use of alias and try_files together can cause problems (see this long standing bug).
You are rewriting the URI to /index.html which is the wrong application, and should instead be /path/index.html.
Try:
location ^~ /path {
alias /dir/project2;
if (!-e $request_filename) {
rewrite ^ /path/index.html last;
}
}
See this caution on the use of if.

Nginx remove leading slash and trailing file type suffix and pass to php

I have received to migrate an existing website written in old php hosted on Apache, and I will deploy to an Nginx.
I wish to have URL like this: http://example.com/about.html
To be executed like this http://example.com/content.php?page=about
So I need to remove leading slash and remove html. The config below works if I hardcode a specific page:
location / {
try_files $uri $uri/ /content.php?page=about;
}
But of course it always serve about regardless if I access our-company.html, or our-services.html. I am not sure what I need to replace the "about" string in the config.
You should use a rewrite directive to perform the actual translation. You can invoke it from a named location specified as the last parameter on the try_files statement.
For example:
location / {
try_files $uri $uri/ #rewrite;
}
location #rewrite {
rewrite ^/(.*)\.html$ /content.php?page=$1 last;
}
See this document for more.

nginx same location but with different directives

Trying to see if this is possible.
We have an app and a wordpress install.
Is it possible to use 2 locations for the same folder but under different circumstances. Example..
http://domain.com/subfolder/ - This shows the APP
http://domain.com/subfolder/anything - This shows WP permalink
Right now, we have it so
http://domain.com/subfolder (without the /) shows the app
http://domain.com/subfolder/ (witht the /) shows WP.
This does work, but would it be possible to have it so, it will only show WP IF the URL contains text after subfolder/*
Current Nginx conf:
location ^~ /knowledge {
root /opt/domain.com/public/;
try_files $uri #backend;
}
location /knowledge/ {
index index.php index.html index.htm;
root /opt;
include /etc/nginx/php-wpsc.conf;
try_files $uri $uri/ /knowledge/index.php?q=$uri&$args;
}
Obviously it makes sense to keep the location /knowledge/ block for WordPress, as that matches the majority of cases, with just one case that needs to be overridden.
A specific URI can be taken away from that location block by using a location block with a higher precedence. See this document for details.
One possibility would be an exact match location block:
location = /knowledge/ {
rewrite ^ /knowledge last;
}
Or possibly, change your existing location ^~ /knowledge block from a prefix location to a regular expression location, making the trailing / optional.
location ~ ^/knowledge/? { ... }
Note that this changes the order of evaluation of this location block, so there may be side-effects that need to be considered.

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