NGINX ignore hash css file and fetch any css that exists - css

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).

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 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: block directory but allow access to subdirectory

I am trying to figure out how I can block a particular directory with nginx, while allowing the resources (including any subdirectories) from that directory to be accessible. For example,
/static should be blocked, however
/static/whatever.css should be accessible.
I tried something like this, but it didn't work:
location ^~ /static/ {
deny all;
return 404;
}
location ^~ /static/* {
allow all;
}
Is there a way to do this?
That is incorrect syntax. You probably meant to write:
location = /static/ {
deny all;
}
location /static/ {
}
The return 404 is redundant as the deny all will return 403. The allow all is redundant as it is the default action. I have remove the ^~ modifier, which should be added to prevent the location being overridden by any potential regex location. See this document for location syntax.
However, it seems that the only URI you want to deny is the directory itself, perhaps to disable an inherited index directive. This may also work (with or without the ^~ modifier - see above):
location /static/ {
try_files $uri =404;
}
By omitting the $uri/ element (note trailing /) from the try_files directive, the index directive is ignored. See this document for more.

Nginx location block for specific path and certain file types

I am having trouble defining a location block for certain paths and file types.
I am using wordpress and using a plugin which generates dynamic sitemaps..It redirects to path like sitemapindex.xml, which do not actually exist and nginx is trying to serve it statically.
I need to be able to pass this to apache
I need to send anything that is http://example.com/blog/*.xml to apache. This is what i am trying, which does not work.. so for instance:
http://example.com/blog/post.xml or http://example.com/blog/sitemapindex.xml
nginx config
server {
location ~* ^/blog/*.xml$ {
include /etc/nginx/proxy_params;
proxy_pass http://127.0.0.1:8080;
}
}
what is the correct syntax
Thanks
I had similar problem with my images. In my applications, images were being served from two different locations.
You can specify different sources based on url pattern. Your solution would then look something like this.
location ~* ^/blog/.+\.(xml)$ {
root /some/path/;
expires 90d;
}
location ~* \.(xml|js|jpg|png|css|html|otf|eot|svg|ttf)$ {
root /some/other/path/;
expires 30d;
index index.html;
}
Gotta escape that period
server {
location ~* ^/blog/.*\.xml$ {
proxy_pass http://127.0.0.1:8080;
}
}

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
}

Resources