Site icon GetPageSpeed

NGINX Var Module: Dynamic Variable Functions for Config

NGINX Var Module: Dynamic Variable Functions for Config

You need to compute a SHA-256 hash inside your NGINX config. Or compare two strings case-insensitively. Or check whether a client IP falls within a CIDR range. Standard NGINX cannot do any of this without a full scripting engine like Lua or njs. The NGINX var module changes that — adding over 70 built-in functions directly to the configuration language.

With the NGINX var module (ngx_http_var_module), you get string manipulation, arithmetic, cryptographic hashing, regex, encoding/decoding, JSON extraction, time functions, and IP operations. Everything evaluates at request time with native C performance. No scripting runtime is required.

How the NGINX Var Module Works

The module introduces a single directive — var — that defines new variables computed by calling a named function. Each time NGINX evaluates a var-defined variable, it runs the function and returns the result. Variables are not cached — they recalculate on every access. This means they always reflect the current request state.

The general syntax is:

var $variable_name function [-i] arguments... [if=condition];

Where:
$variable_name — the new variable to create (must start with $)
function — one of the 70+ built-in function names
-i — optional flag for case-insensitive operations (string comparison and regex functions)
arguments — function-specific arguments (most accept NGINX variables)
if=condition — optional conditional; the variable is set only when the condition is non-empty and not “0”

The var directive works in the http, server, and location contexts. If a location does not define a variable, it inherits from the parent level.

Installation

RHEL, CentOS, AlmaLinux, Rocky Linux

sudo dnf install https://extras.getpagespeed.com/release-latest.rpm
sudo dnf install nginx-module-var

Then load the module by adding this line at the top of /etc/nginx/nginx.conf, before any http block:

load_module modules/ngx_http_var_module.so;

Debian and Ubuntu

First, set up the GetPageSpeed APT repository, then install:

sudo apt-get update
sudo apt-get install nginx-module-var

On Debian/Ubuntu, the package handles module loading automatically. No load_module directive is needed.

Module package pages: RPM | APT

String Functions

The NGINX var module provides a full set of string manipulation functions. These remove the need for regex workarounds or external scripting.

Case Conversion and Formatting

var $upper       upper "hello world";       # HELLO WORLD
var $lower       lower "HELLO WORLD";       # hello world
var $title_case  initcap "hello world test"; # Hello World Test

The initcap function capitalizes the first letter of each word. Word boundaries are non-alphanumeric characters.

Length, Trim, and Reverse

var $length   len "hello";         # 5
var $trimmed  trim "  hello  ";    # hello
var $ltrimmed ltrim "xxhello" "x"; # hello
var $reversed reverse "hello";     # olleh

The trim, ltrim, and rtrim functions accept an optional second argument. It specifies which character to trim (defaults to whitespace).

Substring, Position, and Replace

var $sub     substr "hello world" 6;                 # world
var $pos     position "hello world" "world";          # 7
var $rep     replace "hello world" "world" "nginx";   # hello nginx
var $repeated repeat "ab" 3;                          # ababab

The position function returns a 1-based index, or 0 when not found. The substr function accepts a start position and an optional length.

Set: Direct Assignment with Variable Interpolation

var $full_url set "$scheme://$host$request_uri";

The set function computes its argument (including embedded NGINX variables) and assigns the result. It integrates with the conditional if= feature covered below.

Extract Parameters from Strings

var $bar_value extract_param "bar" "foo=123&bar=456&baz=789";
# Result: 456

The extract_param function parses name-value pair strings. It uses & as the separator and = as the delimiter by default. Both are configurable:

var $value extract_param "key" "key:val;other:data" ";" ":";

This is useful for parsing cookie values or custom header formats without regex.

JSON Operations

The NGINX var module can extract values from JSON strings with the extract_json function. This is useful for JSON-formatted headers, cookies, or upstream response bodies.

Basic Extraction

var $name extract_json '{"name":"alice","age":30}' name;   # alice
var $age  extract_json '{"name":"alice","age":30}' age;    # 30

Nested Objects and Arrays

Navigate nested structures by chaining keys. Access array elements with [index]:

# Nested object traversal
var $deep extract_json '{"a":{"b":{"c":42}}}' a b c;   # 42

# Array index access
var $first extract_json '{"users":[{"name":"Alice"},{"name":"Bob"}]}' users [0] name;
# Result: Alice

String values are returned without quotes. Numbers, booleans, arrays, and objects are returned as compact JSON strings.

String Comparison Functions

These functions return 1 for true and 0 for false. They pair well with the if= conditional or NGINX’s if directive.

var $equal     str_eq $arg_a $arg_b;             # 1 if equal
var $not_equal str_ne $arg_a $arg_b;             # 1 if not equal
var $starts    starts_with $uri "/api";           # 1 if URI starts with /api
var $ends      ends_with $uri ".json";            # 1 if URI ends with .json
var $has       contains $http_user_agent "Bot";   # 1 if UA contains "Bot"

Add -i for case-insensitive comparison:

var $ci_equal    str_eq -i $arg_format "JSON";
var $ci_contains contains -i $http_user_agent "googlebot";

The str_in function checks membership in a set of values:

var $is_image str_in $arg_ext "jpg" "png" "gif" "webp";

Conditional Logic

Boolean operators enable combining multiple checks:

# True (1) if ALL arguments are non-empty and non-zero
var $both_present and $arg_user $arg_token;

# True (1) if ANY argument is non-empty and non-zero
var $either_present or $arg_user $arg_token;

# Negation: 1 if empty/zero, 0 otherwise
var $missing not $arg_token;

Additional type-checking functions:

var $empty     is_empty $arg_val;      # 1 if empty string
var $has_value is_not_empty $arg_val;  # 1 if non-empty
var $numeric   is_num $arg_val;        # 1 if valid number

Conditional Variable Assignment with if=

One of the most powerful features is conditional assignment. Multiple var definitions for the same variable evaluate in order. The first whose if= condition passes wins:

location / {
    var $backend set "premium-upstream" if=$cookie_premium;
    var $backend set "standard-upstream";

    proxy_pass http://$backend;
}

When the premium cookie is present, $backend gets “premium-upstream”. Otherwise, it falls through to “standard-upstream”. This is cleaner than chaining if blocks or nested map directives.

A more advanced example — routing based on multiple conditions:

location / {
    var $has_api_key is_not_empty $http_x_api_key;
    var $is_internal ip_range $remote_addr 10.0.0.0/8 172.16.0.0/12;

    var $access_level set "internal" if=$is_internal;
    var $access_level set "authenticated" if=$has_api_key;
    var $access_level set "public";

    add_header X-Access-Level $access_level;
    # ... proxy or serve content ...
}

Math Operations

The NGINX var module supports integer arithmetic directly in config. No need for the let module or external scripts.

Basic Arithmetic

var $sum       add $arg_a $arg_b;   # addition
var $diff      sub $arg_a $arg_b;   # subtraction
var $product   mul $arg_a $arg_b;   # multiplication
var $quotient  div $arg_a $arg_b;   # integer division (b cannot be 0)
var $remainder mod $arg_a $arg_b;   # modulus (b cannot be 0)

For a=15 and b=4, these return: 19, 11, 60, 3, 3.

Comparisons and Ranges

Numeric comparisons return 1 or 0:

var $is_equal       eq $arg_a $arg_b;        # equal
var $is_less        lt $arg_a $arg_b;        # less than
var $is_greater_eq  ge $arg_a $arg_b;        # greater or equal
var $in_range       range $arg_val 10 20;    # true if 10 <= val <= 20
var $in_set         in $arg_val 10 20 30 40; # true if val is in set

Additional Math

var $absolute abs $arg_val;         # absolute value
var $bigger   max $arg_a $arg_b;    # larger of two values
var $smaller  min $arg_a $arg_b;    # smaller of two values
var $rounded  round "3.14159" 2;    # 3.14
var $truncated int "3.14159";       # 3
var $floored  floor "3.7";          # 3
var $ceiled   ceil "3.2";           # 4

Random Values

var $random_num rand 1 100;   # random integer between 1 and 100
var $request_id hexrand 16;   # 16-byte random hex string (e.g., "a7f3c902b49c51e0")

The hexrand function generates unique request IDs or session tokens directly in config. It works even on older NGINX versions lacking the native $request_id.

Bitwise Operations

For advanced use cases like flag manipulation or hash-based routing:

var $band bitwise_and 12 10;   # 8   (1100 & 1010 = 1000)
var $bor  bitwise_or 12 10;    # 14  (1100 | 1010 = 1110)
var $bxor bitwise_xor 12 10;   # 6   (1100 ^ 1010 = 0110)
var $lsh  lshift 1 4;          # 16  (1 << 4)
var $rsh  rshift 16 2;         # 4   (16 >> 2)

Encoding and Decoding

The NGINX var module supports multiple encoding schemes for transforming variable values.

Base64

var $encoded base64_encode "hello world";   # aGVsbG8gd29ybGQ=
var $decoded base64_decode $encoded;        # hello world

URL-safe Base64 variants use - and _ instead of + and /, with no padding:

var $b64url  base64url_encode "hello+world/test"; # aGVsbG8rd29ybGQvdGVzdA
var $decoded base64url_decode $b64url;            # hello+world/test

URI Encoding

Three levels of URI encoding serve different contexts:

var $e1 escape_uri "hello world&foo=bar";
# hello%20world&foo=bar  (preserves & and =)

var $e2 escape_args "hello world&foo=bar";
# hello%20world%26foo=bar  (escapes & but preserves =)

var $e3 escape_uri_component "hello world&foo=bar";
# hello%20world%26foo%3Dbar  (escapes everything)

var $decoded unescape_uri "hello%20world";
# hello world

Use escape_uri for path segments. Use escape_args for query values. Use escape_uri_component when embedding a URI as a parameter value.

Hexadecimal

var $hex     hex_encode "AB";          # 4142
var $decoded hex_decode "48656c6c6f";  # Hello
var $d2h     dec_to_hex "255";         # ff
var $h2d     hex_to_dec "ff";          # 255

The hex_encode and hex_decode functions convert between binary data and hex strings. This is useful for chaining with HMAC functions that produce raw binary output.

Cryptographic Hash Functions

The NGINX var module provides direct access to common hash algorithms. This is useful for cache keys, integrity checks, or token validation.

Hash Algorithms

var $md5_hash    md5 $request_uri;
# e.g., 5d41402abc4b2a76b9719d911017c592

var $sha1_hash   sha1 $request_uri;
var $sha256_hash sha256 $request_uri;
var $crc32_hash  crc32 $request_uri;

SHA-224, SHA-384, and SHA-512 are also available. They require SSL support, included in all standard NGINX builds:

var $sha512_hash sha512 "sensitive data";

HMAC (Keyed Hashing)

HMAC functions produce raw binary output. Chain with hex_encode for a hex string:

var $raw_hmac hmac_sha256 $request_uri "my-secret-key";
var $hmac_hex hex_encode $raw_hmac;
# e.g., 88aab3ede8d3adf94d26ab90d3bafd4a2083070c3bcce9c014ee04a443847c0b

Available HMAC variants: hmac_md5, hmac_sha1, hmac_sha224, hmac_sha256, hmac_sha384, hmac_sha512.

Practical example — validating a signed URL:

location /protected/ {
    var $expected_sig hmac_sha256 "$uri$arg_expires" "url-signing-secret";
    var $expected_hex hex_encode $expected_sig;
    var $sig_valid str_eq $arg_sig $expected_hex;

    if ($sig_valid = "0") {
        return 403;
    }

    # Serve the content
}

Regex Operations

For pattern matching beyond what map can express:

# Check if value matches a pattern (returns 1 or 0)
var $is_numeric regex_match $arg_val "^[0-9]+$";

# Case-insensitive match
var $is_bot regex_match -i $http_user_agent "(bot|crawler|spider)";

Capture and Substitute

# Capture groups: transform "user@example.com" → "user at example dot com"
var $masked regex_capture $arg_email "^(\w+)@(\w+)\.(\w+)$" "$1 at $2 dot $3";

# Regex substitution: replace first match
var $cleaned regex_sub $arg_text "world" "nginx";

Time Operations

Get Current Time

var $timestamp unix_time;                              # Unix timestamp
var $gmt_str   gmt_time "%Y-%m-%d %H:%M:%S";          # 2026-04-02 05:46:03
var $local_str local_time "%Y-%m-%d %H:%M:%S";        # 2026-04-02 13:46:03

You can also convert between formats:

# Convert timestamp to HTTP date
var $http_date gmt_time $arg_ts http_time;

# Convert timestamp to cookie date
var $cookie_date gmt_time $arg_ts cookie_time;

# Convert date string back to timestamp
var $ts unix_time "2026-01-15 12:00:00" "%Y-%m-%d %H:%M:%S";

Time Range Checks

The time_range function checks whether the current time falls within constraints. This is useful for maintenance windows or time-based routing:

# Business hours only (Mon-Fri, 9am-5pm, UTC+8)
var $is_business_hours time_range wday=1-5 hour=9-17 timezone=gmt+0800;

location /api/ {
    if ($is_business_hours = "0") {
        return 503 "Service available during business hours only";
    }
    proxy_pass http://backend;
}

Parameters: year, month, day, wday (0=Sunday, 6=Saturday), hour, min, sec. Timezone defaults to local. Use timezone=gmt for UTC or timezone=gmt+HHMM for a specific offset.

IP Operations

CIDR Range Checking

Check whether a client IP falls within one or more networks:

var $is_private ip_range $remote_addr 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16;

if ($is_private = "0") {
    return 403 "Internal access only";
}

The ip_range function supports IPv4, IPv6, CIDR notation, and IPv4 ranges. Unlike NGINX’s native geo module, ip_range evaluates against dynamic variables at runtime.

Network Address Calculation

Compute the network address for an IP:

var $network cidr $remote_addr 24;
# 10.0.1.5 → 10.0.1.0
# 8.8.8.8 → 8.8.8.0

For IPv6, specify separate prefix lengths:

var $net cidr $remote_addr 24 64;  # 24 for IPv4, 64 for IPv6

Native NGINX Alternatives Compared

Before reaching for the NGINX var module, check whether native features cover your use case:

Need Native NGINX var Module
Static variable mapping map directive set with if=
IP-based variable geo block ip_range (dynamic)
Simple assignment set directive var ... set
String/math/crypto Not available 70+ functions
JSON extraction Not available extract_json
Regex capture map with ~ regex_capture

Use the var module when you need runtime computation — hashing, arithmetic, string manipulation, JSON parsing, or conditional chains. For static lookup tables, NGINX’s native map is the right tool.

The module is also a lightweight alternative to Lua or njs. Lua loads an interpreter and allocates separate memory. The var module runs compiled C functions with zero overhead.

Performance Considerations

The module runs C functions directly in the request processing pipeline. There is no interpreter startup, no garbage collection, and no extra memory allocations.

Keep these points in mind:

Security Best Practices

When using cryptographic functions for authentication or URL signing:

  1. Keep secrets out of config files. Store HMAC keys in separate include files with restricted permissions.
  2. Use SHA-256 or stronger for security-sensitive hashing. MD5 and SHA-1 are for compatibility only.

  3. Validate user-supplied inputs. The module returns empty values when parameters are invalid. Check for empty results before using computed values in security decisions.

  4. Be cautious with regex patterns. Poorly written expressions can cause catastrophic backtracking. Keep patterns simple.

Troubleshooting

Variable Returns Empty Value

The module silently returns an empty string when:

Check the NGINX error log at warn level for diagnostics:

tail -f /var/log/nginx/error.log

Conflicts with map or geo

The var directive cannot define the same variable as map or geo. The native set directive can override a var-defined variable. Use set for the override and var for the computed default.

Testing Your Configuration

After adding var directives, always test the configuration:

nginx -t

Then verify runtime behavior with curl:

# Reload and test
systemctl reload nginx
curl -s http://localhost/your-test-endpoint

Conclusion

The NGINX var module fills a significant gap in the configuration language. Instead of reaching for Lua or njs for a string comparison, a hash, or conditional logic, express it directly in config with native performance.

With 70+ functions spanning strings, math, cryptography, encoding, JSON, regex, time, and IP handling, the NGINX var module covers the vast majority of cases that previously required external scripting. Your configuration stays readable and your NGINX stays lean.

The module source code is available on GitHub.

D

Danila Vershinin

Founder & Lead Engineer

NGINX configuration and optimizationLinux system administrationWeb performance engineering

10+ years NGINX experience • Maintainer of GetPageSpeed RPM repository • Contributor to open-source NGINX modules

Exit mobile version