Nginx: cache only specific urls and named location - nginx

I have rails application. There are parts of nginx config of it:
upstream app_server {
server unix:/var/www/app/shared/unicorn.sock fail_timeout=0;
}
server {
listen 80;
server_name app hostname;
keepalive_timeout 5;
root /var/www/app/current/public;
try_files $uri/index.html $uri.html $uri #app;
location #app {
proxy_pass http://app_server;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_cache off;
}
location ~ /assets/*\.(png|gif|jpg|jpeg|css|js|swf|ico|gz)(\?[0-9]+)?$ {
access_log off;
}
}
I want to cache several pages of my apps (for example all *.json urls). How I can do that?
According to nginx docs I can't:
use nested location in named location
use proxy_cache in if block

You can get away with adding Json to the extensions in the static file block if they are not virtual URLs.
If they are, you need to either setup differently by forwarding everything to your app by default and making exceptions, so you avoid having to use named locations. Or you can set variables based on if statements inside the named location:
location #app {
set $proxy_cache_cfg "off";
if($request_uri ~ \.json$) {
set $proxy_cache_cfg "json_zone";
}
}
Untested, not sure if "off" should be quoted and whether it even would work here. If this won't work, you can always use the reverse approach and set proxy_no_cache based on a variable, since that is in effect for anything non-empty and non-zero.

Related

problem using variable in nginx location directive

good evening. i have a question regarding nginx and it is related to the location directive. i currently have this configuration in nginx
server {
server_name ~^(?<account>.+)\.domain\.com$;
root /var/www/html/folder-frontend/;
index index.html;
error_log /var/log/nginx/$account-access.log;
access_log /var/log/nginx/$account-access.log;
location / {
try_files $uri /index.html;
}
location /$account-backend/ {
proxy_pass http://service-backend/;
proxy_set_header HOST $account-backend.domain.co;
proxy_http_version 1.1;
}
}
this means that I have several domains with the ending tenant.domain.com(app1.domain.com, app2.domain.com). with the expression (?.+) I am getting part of the string in the url that interests me and then in the location directive use it to make a proxypass and redirect the requests. but this is not working, I know because when I put in the location what interests me (in this case would be location /app1-backend/) if redirects to the backend service that I have listening in another nginx.
My doubt is, can I use a variable in the location directive of nginx? I tried it that way specified and it does not work.
No, you can't use a variable as location directive argument, even in a regex matching ones. You can try a workaround like
server {
server_name ~^(?<account>.+)\.domain\.com$;
root /var/www/html/folder-frontend/;
index index.html;
error_log /var/log/nginx/$account-access.log;
access_log /var/log/nginx/$account-access.log;
location / {
try_files $uri /index.html;
}
location ~ ^/(?<prefix>[^.]+)-backend(?<suffix>/.*) {
if ($prefix != $account) {
return 404;
}
proxy_pass http://service-backend$suffix$is_args$args;
proxy_set_header HOST $prefix-backend.domain.co;
proxy_http_version 1.1;
}
}

Nginx location / overrides all other locations

I'm trying to write a simple nginx config. What I need is:
if file exists in root serve this file
If url is /default/url then show /some/path2/index.html
Otherwise redirect to /default/url
my config is as follows
server {
listen 127.0.0.1:80;
server_name my.domain.com;
root /some/path/html;
location / {
return 302 /default/url;
}
location = /default/url {
rewrite ^/(.*)$/some/path2/index.html;
}
location /default/e_schema {
proxy_pass http://other.host.com;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
It redirects to /default/url instantly regardless of url.
I was trying to put the location / block on the bottom and on the top. I've tried to use location ~ /.* to lower priority but nothing helps. If I remove location / at all everything is fine my requirements 2 and 3 is ok.
According to this answer https://serverfault.com/questions/656628/nginx-catch-all-other-locations-than-given/656634 it should work.
You have put an "=" in the location block
location = /default/url {
Could you try removing this? I believe it may be setting the url
The problem was here
location = /default/url {
rewrite ^/(.*)$/some/path2/index.html;
}
this makes internal redirect to /some/path2/index.html which is within / path so it triggers the location / block which redirects to /default/url and so on.
My solution was to make empty block to exclude the path from location /
location /some/path2/index.html {}

nginx proxy_pass to all pages

So I am using nginx to reverse proxy to another server. This wasn't serving static files, until I linked them in the location. The location block is super long, but looks similar to the code below. I'm sure that I'm doing this the wrong way, but it works, it's just tedious to write all the paths. I'm wondering if there's a better way.
location / {
proxy_pass www.example.com;
}
location /sytlesheet.css {
proxy_pass www.example.com/stylesheet.css;
}
location /page1 {
proxy_pass www.example.com/page1;
}
#this goes on and on
Is there a way to get everything past the '/' for example 'page1', and pass that to the proxy without manually typing it?
I'm hoping there's something a way to use a variable or something to link all the pages and resources with a single location block:
location / {
proxy_pass www.example.com;
}
location /$variable {
proxy_pass www.example.com/$variable;
}
Thanks!
You should use following code
location / {
# First attempt to serve request as file, then
# as directory, then fall back to proxy
try_files $uri $uri/ #proxy;
}
location #proxy {
proxy_pass www.example.com;
}
Check this out.
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://www.example.com;
}

how can I deal with static files in different server

upstream app_server {
server unix:/tmp/gunicorn.sock fail_timeout=0;
}
upstream another_server {
server 192.168.128.11;
}
server {
server_name test.com;
listen 80;
location / {
proxy_pass http://app_server;
proxy_set_header Host $host;
}
location ~ \.(js|css|jpeg|jpg|png|gif|ico|mp4|json) {
root /www/app;
try_files $uri /$1/$2.$4;
}
location ~ /anotherapp {
proxy_pass http://another_server;
proxy_set_header Host $host;
}
}
I have two server in different machines.I don't know how to deal with the static files in another_server.
When I get the test.com/anotherapp/index.js resoure ,but it return the files in app_server but not in another_app server.
The question is how can I deal with the static files in another_app server
Regular expression location statements are evaluated in order until a matching regular expression is found.
So /anotherapp/index.js matches \.(js|css|jpeg|jpg|png|gif|ico|mp4|json) before it matches /anotherapp.
You have two options:
Either, reverse the order of the regular expression location blocks, so that location ~ /anotherapp is encountered first.
Or, use a prefix location with the ^~ modifier instead (which will always take precedence over any regular expression location), for example:
location ^~ /anotherapp { ... }
See this document for details.

Is is possible to define a single nginx location in two separate blocks?

Is is possible to define a single nginx location in two separate blocks?
For example:
server {
listen *:80;
server_name someserver;
location / {
proxy_cache off;
}
location /assets {
proxy_cache mycache;
}
# What do I need to do to get this second root location
# to append to the 1st? If it's even possible.
location / {
proxy_pass http://foo;
}
}
The idea is that the root location then effectively becomes:
location / {
proxy_cache off;
proxy_pass http://foo;
}
If you'd like to know more about the why, read on.
Background:
I'm running a GitLab Omnibus installation. According to the docs, an admin an inject custom nginx config to the GitLab server block.
However, this injection adds things to the end server block rather than a specific location block.
So if I try to inject include my_config.conf;, I'll get:
server {
listen *:80;
server_name someserver;
location / {
proxy_cache off;
}
location /assets {
proxy_cache mycache;
}
include my_config.conf;
}
and if I try to include location ^~ / {\n include my_config.conf;\n }\n I'll get:
server {
listen *:80;
server_name someserver;
location / {
proxy_cache off;
}
location /assets {
proxy_cache mycache;
}
location ^~ / {
include my_config.conf;
}
}
which then causes the nginx config to fail with a duplicate location "/" in /var/opt/gitlab/nginx/conf/gitlab-http.conf:106 error.
Note: my_config.conf contains add_header stuff for CORS, so it needs to be in a location block.
You probably need to understand how nginx processes a request. But location blocks are not additive and must be individually complete. You can place certain statements in the server block and allow individual location blocks to override as required (e.g. proxy_cache).
Assuming that all of your URIs are proxied, you could use something like this:
proxy_cache off;
location / {
proxy_pass http://foo;
}
location /assets {
proxy_cache mycache;
proxy_pass http://foo;
}
Common statements can be offloaded to an include file.

Resources