# Is this how variable (set $var) inheritance works?

**URL:** <https://www.ruby-forum.com/t/is-this-how-variable-set-var-inheritance-works/216409>\
**Category:** NGINX\
**Created:** [February 3, 2012, 4:26pm UTC](https://www.ruby-forum.com/t/is-this-how-variable-set-var-inheritance-works/216409 "2012-02-03T16:26:49Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![dubstep](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/cdc98d/32.png) [@dubstep](https://www.ruby-forum.com/u/dubstep)\
**Post date:** [February 3, 2012, 4:26pm UTC](https://www.ruby-forum.com/t/is-this-how-variable-set-var-inheritance-works/216409/1 "2012-02-03T16:26:49Z")

</div>

(doesn’t seem to be specified in documentation)

My test showed:

- anything set in server { } block is inherited:

server {  
set $something /usr/share/something;  
…  
location / {  
location /nested/ {  
# $something is set to /usr/share/something  
root $something;  
}  
}  
}

- anything set in location { } block is not inherited:

server {  
…  
location /~ {  
location ~ ^/~([^/]+)(|/.\*)$ {  
set $userfile /home/$1/public\_html/$2;  
alias $userfile;  
location ~ .php$ {  
include fastcgi\_params;  
# $userfile is empty here  
fastcgi\_param SCRIPT\_FILENAME $userfile;  
fastcgi\_pass 127.0.0.1:9000;  
}  
}  
}

Is it correct?

–  
O\< ascii ribbon campaign - stop html mail - [www.asciiribbon.org](http://www.asciiribbon.org)

---

<div class="post-metadata">

**Author:** ![Edho\_A](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/848f3c/32.png) [@Edho\_A](https://www.ruby-forum.com/u/Edho_A)\
**Post date:** [February 3, 2012, 7:10pm UTC](https://www.ruby-forum.com/t/is-this-how-variable-set-var-inheritance-works/216409/2 "2012-02-03T19:10:56Z")

</div>

Hello!

On Fri, Feb 03, 2012 at 10:26:07PM +0700, Edho A. wrote:

> ```
> # $something is set to /usr/share/something
> location ~ ^/~([^/]+)(|/.*)$ {
> 
> ```
> 
> Is it correct?

Yes, this is expected behavrious. Rewrite module directives are  
never inherited, and directives specified inside location are only  
executed if this exact location matches.

See here for details:

> **[Module ngx\_http\_rewrite\_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html)**

Maxim D.

---

<div class="post-metadata">

**Author:** ![Edho\_A](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/848f3c/32.png) [@Edho\_A](https://www.ruby-forum.com/u/Edho_A)\
**Post date:** [February 3, 2012, 7:49pm UTC](https://www.ruby-forum.com/t/is-this-how-variable-set-var-inheritance-works/216409/3 "2012-02-03T19:49:16Z")

</div>

On Sat, Feb 4, 2012 at 1:10 AM, Maxim D. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Yes, this is expected behavrious. Rewrite module directives are  
> never inherited, and directives specified inside location are only  
> executed if this exact location matches.
> 
> See here for details:  
> [Module ngx\_http\_rewrite\_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html)

I replaced the line:

```
  -fastcgi_param SCRIPT_FILENAME $userfile;
  +fastcgi_param SCRIPT_FILENAME /home/edho/public_html/test.php;

```

But I still see this:

2012/02/03 13:30:16 [warn] 12889#0: \*17 using uninitialized “userfile”  
variable, client: 118.136.36.164, server: localhost, request: “GET  
/~edho/test.php HTTP/1.1”, host: “[yutsuki.myconan.net](http://yutsuki.myconan.net)”

Why did I get warning for using uninitialized variables even though  
it’s not specified at all in the relevant location block?

Additionally:

Is there any variable I can use for my case? $request\_filename  
returned “/opt/nginx/” (bug?). Or do I have use separate block when  
using alias (ie. nothing is inherited when using alias)?

–  
O\< ascii ribbon campaign - stop html mail - [www.asciiribbon.org](http://www.asciiribbon.org)

---

<div class="post-metadata">

**Author:** ![Edho\_A](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/848f3c/32.png) [@Edho\_A](https://www.ruby-forum.com/u/Edho_A)\
**Post date:** [February 3, 2012, 7:51pm UTC](https://www.ruby-forum.com/t/is-this-how-variable-set-var-inheritance-works/216409/4 "2012-02-03T19:51:44Z")

</div>

On Sat, Feb 4, 2012 at 1:48 AM, Edho A. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I replaced the line:
> 
> Why did I get warning for using uninitialized variables even though  
> it’s not specified at all in the relevant location block?

After a bit more thinking, does it mean that the “alias $userfile”  
from parent location block was inherited but the $userfile was passed  
literally?

–  
O\< ascii ribbon campaign - stop html mail - [www.asciiribbon.org](http://www.asciiribbon.org)

---

<div class="post-metadata">

**Author:** ![Edho\_A](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/848f3c/32.png) [@Edho\_A](https://www.ruby-forum.com/u/Edho_A)\
**Post date:** [February 3, 2012, 8:00pm UTC](https://www.ruby-forum.com/t/is-this-how-variable-set-var-inheritance-works/216409/5 "2012-02-03T20:00:22Z")

</div>

On Sat, Feb 4, 2012 at 1:50 AM, Edho A. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > Why did I get warning for using uninitialized variables even though  
> > it’s not specified at all in the relevant location block?
> 
> After a bit more thinking, does it mean that the “alias $userfile”  
> from parent location block was inherited but the $userfile was passed  
> literally?

More self-reply: it certainly looks like the $userfile is passed but  
still in variable, not expanded with the contents as the following  
test showed.

Skipping “set $userfile …” and put the capture in alias directly:

location ~ ^/~([^/]+)(|/.\*)$ {  
alias /home/$1/public\_html/$2;  
location ~ .php$ {  
include fastcgi\_params;  
fastcgi\_param SCRIPT\_FILENAME $request\_filename;  
fastcgi\_pass 127.0.0.1:9000;  
}  
}

resulted in this:

2012/02/03 13:51:28 [debug] 14951#0: \*13 fastcgi param:  
“REDIRECT\_STATUS: 200”  
2012/02/03 13:51:28 [debug] 14951#0: \*13 http script copy: “/home/”  
2012/02/03 13:51:28 [debug] 14951#0: \*13 http script capture: “”  
2012/02/03 13:51:28 [debug] 14951#0: \*13 http script copy:  
“/public\_html/”  
2012/02/03 13:51:28 [debug] 14951#0: \*13 http script capture: “”  
2012/02/03 13:51:28 [debug] 14951#0: \*13 http script copy:  
“SCRIPT\_FILENAME”  
2012/02/03 13:51:28 [debug] 14951#0: \*13 http script var:  
“/home//public\_html/”  
2012/02/03 13:51:28 [debug] 14951#0: \*13 fastcgi param:  
“SCRIPT\_FILENAME: /home//public\_html/”  
2012/02/03 13:51:28 [debug] 14951#0: \*13 fastcgi param: “HTTP\_HOST:  
[yutsuki.myconan.net](http://yutsuki.myconan.net)”

Which explains why I got “/opt/nginx/” for $request\_filename on  
previous config - the .php$ location block was basically using `alias $userfile` but as $userfile was empty, it became empty alias for that  
block.

–  
O\< ascii ribbon campaign - stop html mail - [www.asciiribbon.org](http://www.asciiribbon.org)

---

<div class="post-metadata">

**Author:** ![Edho\_A](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/848f3c/32.png) [@Edho\_A](https://www.ruby-forum.com/u/Edho_A)\
**Post date:** [February 4, 2012, 8:57pm UTC](https://www.ruby-forum.com/t/is-this-how-variable-set-var-inheritance-works/216409/6 "2012-02-04T20:57:14Z")

</div>

On Sat, Feb 4, 2012 at 8:15 AM, Max [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> This feature/bug is especially confusing when you use variables  
> inside root and alias directives, because the nested location blocks  
> will inherit the root and alias contents (unless specifically set),  
> which will have any uninitialized inherited variable names replaced  
> with “”, so “/home/$variable/abc/$dir/” would become “/home//abc//”.

At least this makes nested location useless for cases like this.  
Instead of one regex with captures (and then use nested location), I  
had to do this instead:

location /~ {  
location ~ ^/~([^/]+)/(.+.php)$ {  
alias /home/$1/public\_html/$2;  
if (!-f $request\_filename) { return 404; }  
include fastcgi\_params;  
fastcgi\_param SCRIPT\_FILENAME $request\_filename;  
fastcgi\_pass 127.0.0.1:9000;  
}  
location ~ ^/~([^/]+)(|/.\*)$ {  
alias /home/$1/public\_html/$2;  
index index.html;  
}  
}

Or use map (and since it’s currently impossible to do non-simple regex  
capture, I had to use two maps):

map $uri $user {  
~^/~(?P[^/]+)(|/._)$ $user1;  
}  
map $uri $file {  
~^/~[^/]+(?P|/._)$ $file1;  
}  
server {  
…  
location /~ {  
location ~ ^ {  
alias /home/$user/public\_html/$file;  
location ~ .php$ {  
include fastcgi\_params;  
fastcgi\_param SCRIPT\_FILENAME $request\_filename;  
fastcgi\_pass 127.0.0.1:9000;  
}  
}  
}  
}

–  
O\< ascii ribbon campaign - stop html mail - [www.asciiribbon.org](http://www.asciiribbon.org)

---

<div class="post-metadata">

**Author:** ![Edho\_A](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/848f3c/32.png) [@Edho\_A](https://www.ruby-forum.com/u/Edho_A)\
**Post date:** [February 4, 2012, 7:19pm UTC](https://www.ruby-forum.com/t/is-this-how-variable-set-var-inheritance-works/216409/7 "2012-02-04T19:19:27Z")

</div>

03 февраля 2012, 22:59 от Edho A. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> More self-reply: it certainly looks like the $userfile is passed but  
> fastcgi\_pass 127.0.0.1:9000;  
> 2012/02/03 13:51:28 [debug] 14951#0: \*13 http script copy: “SCRIPT\_FILENAME”  
> 2012/02/03 13:51:28 [debug] 14951#0: \*13 http script var: “/home//public\_html/”  
> 2012/02/03 13:51:28 [debug] 14951#0: \*13 fastcgi param:  
> “SCRIPT\_FILENAME: /home//public\_html/”  
> 2012/02/03 13:51:28 [debug] 14951#0: \*13 fastcgi param: “HTTP\_HOST:  
> [yutsuki.myconan.net](http://yutsuki.myconan.net)”
> 
> Which explains why I got “/opt/nginx/” for $request\_filename on  
> previous config - the .php$ location block was basically using `alias $userfile` but as $userfile was empty, it became empty alias for that  
> block.

Nested location blocks inherit variables only by name, which means  
the inherited variables are only created and marked as uninitialized.  
Note that this is not the same as creating an empty variable that  
contains “”. The distinction should be similar to the one between  
defined vs. empty variables in Perl: if you set $variable to “”,  
then ‘if ($variable)’ would evaluate to false, while  
‘if (defined($variable))’ would evaluate to true.

This distinction exists in nginx as well, where ‘if ($variable)’  
would also evaluate to false, but there’s no direct way to  
test whether a variable is defined. However nginx tests for  
this automatically - if you try to use an undefined variable,  
nginx will report an ‘unknown “\<variable\_name\>” variable’ error  
and fail to start.

That’s why a variable that was set to a certain value inside the  
outermost (parent) location block will be inherited by nested location  
blocks only by name, which means that if you try to use such a  
variable inside a nested location block, nginx won’t report any  
errors, but instead of the original contents of the variable, you will  
only get an empty string when you try to access the contents.

This feature/bug is especially confusing when you use variables  
inside root and alias directives, because the nested location blocks  
will inherit the root and alias contents (unless specifically set),  
which will have any uninitialized inherited variable names replaced  
with “”, so “/home/$variable/abc/$dir/” would become “/home//abc//”.

Another important thing to remember is that if you set root or alias  
to contain nothing but a variable (root $home;), then the root inside  
any nested location block where you do not set root or alias  
specifically,  
will be reset NOT to your default root value from the server  
configuration block, but to the value of the prefix configure argument  
that nginx was compiled with (/usr/local/etc/nginx), which you can see  
under --prefix= when you run nginx -V.

Your nginx was probably compiled with --prefix=/opt/nginx/.

Max

---

<div class="post-metadata">

**Author:** ![Edho\_A](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/e/848f3c/32.png) [@Edho\_A](https://www.ruby-forum.com/u/Edho_A)\
**Post date:** [February 4, 2012, 9:26pm UTC](https://www.ruby-forum.com/t/is-this-how-variable-set-var-inheritance-works/216409/8 "2012-02-04T21:26:16Z")

</div>

On 4 Fev 2012 02h53 WET, [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> At least this makes nested location useless for cases like this.  
> }  
> location ~ ^/~([^/]+)(|/.\*)$ {  
> alias /home/$1/public\_html/$2;  
> index index.html;  
> }  
> }

The thing is that there is a server level rewrite phase and a location  
level rewrite phase. And since you can have only _one and only one_  
location everything at the location rewrite phase that happens before  
a redirect/rewrite gets lost. Why?

Because you enter a configuration find phase again and after that a  
rewrite phase again on the location it was redirected to.

The server level rewrite only happens once in each vhost hence the  
values of user variables set there are preserved.

That’s my understanding of it, at least.

— appa
