Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does if condition work inside location block in nginx conf?

I have read https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/

I want to check if my rails application has already added a header (Access-Control-Allow-Origin) and if it hasn't then add the header.

The examples here have tried to explain the behaviour of if condition in nginx.conf http://agentzh.blogspot.in/2011/03/how-nginx-location-if-works.html

But I have not understood it. One of the question I have is what is meant when they say a directive or phase directive?

I have tried some things myself. Like:

location / {
  add_header My-outer-header '*';
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $http_host;
  proxy_set_header X-NginX-Proxy true; 

  if($sent_http_access_control_allow_origin != /*){
    add_header My-inner-header '**';
  }
}

Here when the if condition is met, only My-inner-header is set and not the My-outer-header.

But when I do:

location / {
  add_header My-outer-header '*';
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $http_host;
  proxy_set_header X-NginX-Proxy true; 
  set $a 1;
  if($a == 1){
    add_header My-inner-header '**';
  }
}

Here $a variable is set to 1 but only the My-inner-header is set again and not the My-outer-header.

I want to check and ensure if the instructions like proxy_set_header are getting executed or not.

like image 558
Abhishek Kumar Avatar asked Feb 07 '16 19:02

Abhishek Kumar


People also ask

How does location work in nginx?

The location directive within NGINX server block allows to route request to correct location within the file system. The directive is used to tell NGINX where to look for a resource by including files and folders while matching a location block against an URL.

Can nginx location blocks match a URL query string?

Can nginx location blocks match a URL query string? Short answer: No.

What is location in nginx config?

Every NGINX configuration file will be found in the /etc/nginx/ directory, with the main configuration file located in /etc/nginx/nginx. conf .

How do I know if nginx config is correct?

Through a simple command you can verify the status of the Nginx configuration file: $ sudo systemctl config nginx The output will show if the configuration file is correct or, if it is not, it will show the file and the line where the problem is.


1 Answers

I haven't tested your code. I only speak from experience!!!

To begin with, allow me to specify that Nginx configuration is NOT at all similar to any OOP behaviour (Object Oriented Programming). It is in a single word unpredictably "Declarative".

Meaning... If you have 2 IF statements in the same block that both meet the criteria, ONLY the second will prevail and be executed.

The same happens with 1 if and all it's previous declarations in the same block. Some variables (Not all) will not be executed due to the presence of IF, and nginx expects them to be re-declared within. This happens in your example. Let's take the second one for clarity. Inside your location block, you declare several header values. BUT, when the IF statement is met, they are NOT executed (IF is evil in nginx indeed). In order to have a full execution you need to re-declare most of your header variables inside and anything else outside the if, again inside the if statement, so they will be executed in case the if statement is met. NOTE, there is no map that lists all the variable affected by IF in nginx and you should test our conf for any errors. Some variables will NOT need to be re-declared and in this case nginx will report an error on restart. Only way to figure out which, is go for all and rule out the reported erroneous ones.

Suggestions

a) Avoid IF in nginx if possible. Use location blocks instead. e.g. If you simply want to add a header variable like Access-Control-Allow-Origin for certain files, do NOT use if, but instead a second location block (See below)

location / {
  // some code here
}
location ~* \.(eot|ttf|woff|woff2)$ {
    add_header Access-Control-Allow-Origin *;
}

b) In cases where IF is mandatory, use with caution and test test test. As above, re-declaring everything in the if statement is a good practice (As above suggested, test and rule out whichever re-declaration breaks configuration).

Good luck.

like image 145
Angelos Hadjiphilippou Avatar answered Oct 21 '22 11:10

Angelos Hadjiphilippou