Nginx Variables

Nginx Variables

variables in Nginx's configuration files

Reading Notes / Web Notes

2020.01.20

👣 #nginx

Note took from:

agentzh’s Nginx Tutorials (version 2020.03.19)

Nginx’s configuration files use a micro programming language, variables are thus a natural part of it. Variables are just containers holding various values in imperative languages like Perl, C/C++, and Bash. However, for the Nginx configuration language, variables can hold only one type of values, that is, strings (exception, the 3rd-party module ngx_array_var extends Nginx variables to hold arrays, implemented by encoding a C pointer as a binary string value behind the scene).

Variable syntax and interpolation

For example, in nginx.conf we set:

set $a "hello world";

Which assigns a value (string value of hello world) to the variable $a via the set configuration directive (coming from ngx_rewrite module). This syntax is required by Nginx: whenever we want to reference an Nginx variable, we must add a $ prefix. And variables in Nginx can be embedded directly into a string literal:

set $a "hello";
set $b "$a, $a";

So after above two directives complete execution, the value of $a is hello, and $b is hello, hello. This technique is called variable interpolation in the Perl world, which makes ad-hoc string concatenation operators no longer necessary.

Let’s see another complete example:

server {
  listen 8080;
  
  location /text {
    set $foo "hello";
    echo "foo: $foo";
  }
}

To request this /test interface via curl, we get:

$ curl 'http://localhost:8080/test'
foo: hello

Here in this example, echo directive of 3rd-party module nginx_echo was used, which support variable interpolation. But we cannot take it for granted for other directives, always loop up the documentation to be sure.

Escaping “$”

To output a literal $ character via echo directive, the following naive example does NOT work at all:

location /t {
  echo "$";
}

We will get the following error message while loading this configuration:

[emerg] invalid variable name in ...

Luckily, workarounds do exist:

geo $dollar {
  default "$";
}
...

location /t {
  echo "This is a dollar sign: $dollar";
}

Here we make use of the geo directive of the standard module nginx_geo to initialise the $dollar variable with the string $, thereafter variable $dollar can be used in places that require a dollar sign. This works because the geo directive does not support variable interpolation at all.

Disambiguation variable names

There is a special case for variable interpolation, that is, when the variable name is followed directly by characters allowed in variable name (like letters, digits, and underscores). In such cases, we can use a special notation to disambiguate the variable name from the subsequent literal characters, for instance:

location /test {
  set $first "hello ";
  echo "${first}world";
}

If it was written directly as $firstworld, Nginx variable interpolation engine (also known as the script engine) will try to access the variable $firstworld instead of $first. To address the ambiguity here, curly braces must be used.

Variable declaration and creation

Just like variables in C/C++, which must be declared before they can be used so that the compiler can allocate storage and perform type checking at compile time. Nginx creates all the variables while loading the configuration file, that is, variable creation only occurs when Nginx loads its configuration.

Variable scope

Once an Nginx variable is created, it is visible to the entire configuration, even across different virtual server configuration blocks.

Here is an example:

location /foo {
  echo "foo = [$foo]";
}

location /bar {
  set $foo 32;
  echo "foo = [$foo]";
}

Here, the variable $foo is created by the set directive inside location /bar, and this variable is visible to the entire Nginx configuration. It should be noted that when requesting the /foo interface, we always get an empty value for the $foo variable because that is what we get when accessing an uninitialised variable.

Another important characteristic that we can observe from this example is that even though the scope of Nginx variable is the entire configuration, each request does have its own version of all those variables’ containers. Requests do not interfere with each other even if they are referencing a variable with the same name.

Variable lifetime and internal redirection

There is another common misunderstanding: assume that the lifetime of Nginx variables are bound to the location configuration block. Let’s consider the following example:

location /foo {
  set $a "hello";
  echo_exec /bar;
}

location /bar {
  echo "a = [$a]";
}

The internal redirection is an operation that makes Nginx jump from one location to another while processing a request. this jumping happens completely within the server itself. This is different from those external redirections based on HTTP 301 and 302 responses because the latter is collaborated externally by the HTTP clients. Also, in case of external redirections, the end user could usually observe the change of the URL in the web browser’s address bar while this is not the case for internal ones. Internal redirections are very similar to the exec command in Bash; it is a one way trip and never returns.

Back to the example, the whole process looks like this: Nginx first assigns to the $a variable in location /foo, and then it issues and internal redirection via echo_exec, thus leaving location /foo and entering location /bar, and finally it outputs the value of $a.

$ curl "http://localhost:8080/foo"
a = [hello]

To conclude, the lifetime of Nginx variable containers is indeed bound to the request being processed, and is irrelevant to location.

Special value “invalid” and “not found”

Variables without any meaningful values still take a special value though in Nginx. There are two possible special values: invalid and not found.

For example, when a user variable $foo is created but not assigned yet, $foo takes the special value of “invalid”. And when the current URL query string does not have the xxx argument at all, the built-in variable $arg_xxx takes the special value of “not found”.

Both invalid and not found are special values, completely different from an empty string value (“”).

It is also worth noting that only the invalid special value will trigger the “get handler” invocation in the Nginx core while not found will not.

THE END
Ads by Google

林宏

Frank Lin

Hey, there! This is Frank Lin (@flinhong), one of the 1.41 billion . This 'inDev. Journal' site holds the exploration of my quirky thoughts and random adventures through life. Hope you enjoy reading and perusing my posts.

YOU MAY ALSO LIKE

Using Liquid in Jekyll - Live with Demos

Web Notes

2016.08.20

Using Liquid in Jekyll - Live with Demos

Liquid is a simple template language that Jekyll uses to process pages for your site. With Liquid you can output complex contents without additional plugins.

Practising closures in JavaScript

JavaScript Notes

2018.12.17

Practising closures in JavaScript

JavaScript is a very function-oriented language. As we know, functions are first class objects and can be easily assigned to variables, passed as arguments, returned from another function invocation, or stored into data structures. A function can access variable outside of it. But what happens when an outer variable changes? Does a function get the most recent value or the one that existed when the function was created? Also, what happens when a function invoked in another place - does it get access to the outer variables of the new place?

Understanding Nginx location directive

Tools

2020.09.12

Understanding Nginx location directive

Location directives are essential when working with Nginx. They can be located within server blocks or other location blocks. Understanding how location directives are used to process the URI of client request can help make the request handling less unpredictable.