nginx: block directory but allow access to subdirectory - nginx

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.

Related

How to deny access to directory for all file extensions except few

The same as in the title, I want to deny access for all file extensions except these 8. I have got something like this, but it does not work properly.
location ~* /uploads/ql/icons/.*.(?!(bmp|gif|tiff|jpeg|jpg|ppm|png|ico))$ {
deny all;
}
Your regex won't work as you expected.
Try this one:
location ~* /uploads/ql/icons/.*\.(?!bmp$|gif$|tiff$|jpeg$|jpg$|ppm$|png$|ico$) {
deny all;
}
However this one won't block access to files without any extension at all. To block that files too you'll need a more complex regex:
location ~* /uploads/ql/icons/(?:[^.]+$|.*\.(?!bmp$|gif$|tiff$|jpeg$|jpg$|ppm$|png$|ico$)) {
deny all;
}
There is also another way adding second location block, see this comment.

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 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 config with spa and subdirectory root

I always seem to have problems with nginx configurations. My SPA is located at /mnt/q/app (pushstate is enabled) and the frontend root is located at client/public. Everything should be mapped to index.html, where the app picks up the route and decides what to do.
Full path to the index is /mnt/q/app/client/public/index.html.
I think I ran out of options by now. No matter what I do, I just get a 404 back from nginx, I think the configuration is simple enought and have no clue what's wrong.
server {
listen 80;
server_name app.dev;
root /mnt/q/app;
location / {
root /client/public;
try_files $uri #rewrites =404;
}
location #rewrites {
rewrite ^(.+)$ /index.html last;
}
}
Any help is appreciated.
If nginx views the file system from the root, then the root should be set to /mnt/q/app/client/public, and not either of the two values you are using.
The last element of the try_files directive can be a default action (e.g. /index.html), a named location or a response code. You have a named location in the penultimate element - which will be ignored.
Your named location should work, but is unnecessary, as try_files is capable of implementing it more simply. See this document for more.
For example:
root /mnt/q/app;
location / {
root /mnt/q/app/client/public;
try_files $uri $uri/ /index.html;
}
location /api {
}
location /auth {
}
The $uri/ element will add a trailing / to directories, so that the index directive can work - you do not have to add it if you do not need it.

Resources