The NGINX set-misc module extends the standard rewrite module with powerful utility functions for encoding, hashing, escaping, and manipulating variables. Instead of proxying requests to a backend application just to compute an MD5 hash or encode a string to Base64, you can perform these operations directly in your NGINX configuration.
This module is essential for building signed URLs, generating secure tokens, escaping user input for SQL or JSON, and handling data transformations at the edge. Combined with modules like echo and headers-more, the set-misc module transforms NGINX into a versatile request processing engine.
What Is the NGINX Set-Misc Module?
The NGINX set-misc module (ngx_http_set_misc_module) is developed by the OpenResty project and provides 27 directives for variable manipulation. These directives work seamlessly with the standard set directive and can be mixed with other rewrite module directives like if and rewrite.
The module depends on the NGINX Development Kit (NDK) and covers these categories:
- Encoding/Decoding: Base64, Base64URL, Base32, Hexadecimal
- Hashing: MD5, SHA1, HMAC-SHA1, HMAC-SHA256
- Escaping: URI encoding, SQL quoting, PostgreSQL quoting, JSON quoting
- Random Generation: Pseudo-random numbers, cryptographically secure tokens
- Utilities: Conditional assignment, time formatting, round-robin rotation
Every directive operates during the rewrite phase and can use NGINX variables as input. The results are stored in variables that can be used anywhere in your configuration.
Installing the NGINX Set-Misc Module
RHEL, CentOS, AlmaLinux, Rocky Linux
Install the module from the GetPageSpeed extras repository:
sudo dnf install https://extras.getpagespeed.com/release-latest.rpm
sudo dnf install nginx-module-set-misc
The package automatically installs the required NGINX Development Kit (NDK) as a dependency.
Add module loading to /etc/nginx/nginx.conf at the very top, before any other blocks:
include /usr/share/nginx/modules/*.conf;
Or manually load the modules:
load_module modules/ndk_http_module.so;
load_module modules/ngx_http_set_misc_module.so;
Important: The NDK module must be loaded before the set-misc module because set-misc depends on NDK.
Debian and Ubuntu
First, set up the GetPageSpeed APT repository, then install:
sudo apt-get update
sudo apt-get install nginx-module-set-misc
On Debian/Ubuntu, the package handles module loading automatically. No
load_moduledirective is needed.
For the full list of available platforms and versions, see the RPM module page or APT module page.
Verify the Installation
After installation, verify that NGINX accepts the configuration:
sudo nginx -t
If you see “syntax is ok” and “test is successful,” the module is loaded and ready to use.
NGINX Set-Misc Module Directives Reference
The module provides 27 directives organized into logical categories. All directives work in location, server, and if blocks during the rewrite phase.
Base64 Encoding and Decoding
set_encode_base64
Encodes a value to standard Base64 format.
Syntax: set_encode_base64 $dst <src> or set_encode_base64 $dst
location /base64 {
set $raw "hello world";
set_encode_base64 $encoded $raw;
return 200 "Encoded: $encoded\n";
}
Output: Encoded: aGVsbG8gd29ybGQ=
The single-argument form modifies the variable in place:
location /base64-inplace {
set $data "secret message";
set_encode_base64 $data;
return 200 "Result: $data\n";
}
set_decode_base64
Decodes a Base64-encoded string back to its original form.
Syntax: set_decode_base64 $dst <src> or set_decode_base64 $dst
location /decode {
set $encoded "aGVsbG8gd29ybGQ=";
set_decode_base64 $decoded $encoded;
return 200 "Decoded: $decoded\n";
}
Output: Decoded: hello world
set_encode_base64url
Encodes to URL-safe Base64 format. This variant replaces + with - and / with _, making it safe for URLs and filenames.
Syntax: set_encode_base64url $dst <src> or set_encode_base64url $dst
location /base64url {
set $raw "hello+world/test";
set_encode_base64url $encoded $raw;
return 200 "URL-safe: $encoded\n";
}
Output: URL-safe: aGVsbG8rd29ybGQvdGVzdA
The URL-safe variant is ideal for query parameters and cookie values where standard Base64 characters could cause parsing issues.
set_decode_base64url
Decodes a URL-safe Base64 string.
Syntax: set_decode_base64url $dst <src> or set_decode_base64url $dst
location /decode-url {
set $encoded "aGVsbG8rd29ybGQvdGVzdA";
set_decode_base64url $decoded $encoded;
return 200 "Original: $decoded\n";
}
Base32 Encoding and Decoding
Base32 uses a smaller alphabet than Base64, making it more suitable for case-insensitive systems like DNS and file systems.
set_encode_base32
Encodes a value to Base32 format. The module uses the “base32hex” alphabet (0-9a-v) by default.
Syntax: set_encode_base32 $dst <src> or set_encode_base32 $dst
location /base32 {
set $raw "hello";
set_encode_base32 $encoded $raw;
return 200 "Base32: $encoded\n";
}
Output: Base32: d1imor3f
set_decode_base32
Decodes a Base32-encoded string.
Syntax: set_decode_base32 $dst <src> or set_decode_base32 $dst
set_base32_padding
Controls whether to add = padding characters to Base32 output.
Syntax: set_base32_padding on|off
Default: on
Context: http, server, location
location /base32-nopad {
set_base32_padding off;
set $raw "hello";
set_encode_base32 $encoded $raw;
return 200 "No padding: $encoded\n";
}
set_base32_alphabet
Customizes the alphabet used for Base32 encoding and decoding. The default alphabet is 0123456789abcdefghijklmnopqrstuv (base32hex). For RFC 3548 compliant encoding, use the standard alphabet.
Syntax: set_base32_alphabet <alphabet>
Default: 0123456789abcdefghijklmnopqrstuv
Context: http, server, location
location /base32-rfc {
set_base32_alphabet "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
set $raw "hello";
set_encode_base32 $encoded $raw;
return 200 "RFC 3548: $encoded\n";
}
Hexadecimal Encoding and Decoding
set_encode_hex
Converts a string to its hexadecimal representation.
Syntax: set_encode_hex $dst <src> or set_encode_hex $dst
location /hex {
set $raw "hello";
set_encode_hex $hex $raw;
return 200 "Hex: $hex\n";
}
Output: Hex: 68656c6c6f
Hexadecimal encoding is useful for debugging binary data, generating cache keys, and creating URL-safe representations of arbitrary bytes.
set_decode_hex
Converts a hexadecimal string back to its original binary form.
Syntax: set_decode_hex $dst <src> or set_decode_hex $dst
location /unhex {
set $hex "68656c6c6f";
set_decode_hex $raw $hex;
return 200 "Decoded: $raw\n";
}
Output: Decoded: hello
Cryptographic Hashing
set_md5
Computes the MD5 hash of a value and returns it in hexadecimal format.
Syntax: set_md5 $dst <src> or set_md5 $dst
location /md5 {
set $data "hello";
set_md5 $hash $data;
return 200 "MD5: $hash\n";
}
Output: MD5: 5d41402abc4b2a76b9719d911017c592
MD5 is useful for generating cache keys, content fingerprints, and non-security-critical checksums. For security-sensitive applications, use SHA1 or HMAC functions instead.
set_sha1
Computes the SHA1 hash of a value and returns it in hexadecimal format.
Syntax: set_sha1 $dst <src> or set_sha1 $dst
location /sha1 {
set $data "hello";
set_sha1 $hash $data;
return 200 "SHA1: $hash\n";
}
Output: SHA1: aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
SHA1 provides stronger collision resistance than MD5 and is suitable for content integrity verification.
set_hmac_sha1
Computes an HMAC-SHA1 message authentication code using a secret key. The result is returned in raw binary format, so you typically combine it with set_encode_base64 or set_encode_hex.
Syntax: set_hmac_sha1 $dst <secret_key> <message>
location /hmac-sha1 {
set $secret "my-secret-key";
set $message "data to sign";
set_hmac_sha1 $signature $secret $message;
set_encode_base64 $sig_b64 $signature;
return 200 "HMAC-SHA1: $sig_b64\n";
}
HMAC-SHA1 is widely used for API authentication, webhook verification, and signed URL generation.
set_hmac_sha256
Computes an HMAC-SHA256 message authentication code. This provides stronger security than HMAC-SHA1 and is recommended for new applications.
Syntax: set_hmac_sha256 $dst <secret_key> <message>
location /hmac-sha256 {
set $secret "my-secret-key";
set $message "data to sign";
set_hmac_sha256 $signature $secret $message;
set_encode_base64 $sig_b64 $signature;
return 200 "HMAC-SHA256: $sig_b64\n";
}
Output: The Base64-encoded HMAC-SHA256 signature.
This directive requires OpenSSL support in your NGINX build, which is standard in GetPageSpeed packages.
URI Encoding and Decoding
set_escape_uri
Encodes a string for safe inclusion in URLs. Special characters are converted to percent-encoded form (e.g., space becomes %20).
Syntax: set_escape_uri $dst <src> or set_escape_uri $dst
location /escape {
set $data "hello world!";
set_escape_uri $escaped $data;
return 200 "Escaped: $escaped\n";
}
Output: Escaped: hello%20world!
set_unescape_uri
Decodes a percent-encoded URI string. This is the inverse of set_escape_uri.
Syntax: set_unescape_uri $dst <src> or set_unescape_uri $dst
location /unescape {
set_unescape_uri $key $arg_key;
return 200 "Key: $key\n";
}
The built-in $arg_* variables contain raw (escaped) query parameter values. Use set_unescape_uri to decode them before processing.
String Quoting for Database and JSON
set_quote_sql_str
Escapes a string for safe inclusion in MySQL SQL queries. The result is wrapped in single quotes with special characters properly escaped.
Syntax: set_quote_sql_str $dst <src> or set_quote_sql_str $dst
location /sql {
set $input "hello'world";
set_quote_sql_str $safe $input;
return 200 "SQL: $safe\n";
}
Output: SQL: 'hello\'world'
This directive prevents SQL injection when constructing queries dynamically. However, parameterized queries in your application are still the preferred approach.
set_quote_pgsql_str
Escapes a string for safe inclusion in PostgreSQL SQL queries. PostgreSQL uses a different escaping syntax with the E prefix for strings containing escape sequences.
Syntax: set_quote_pgsql_str $dst <src> or set_quote_pgsql_str $dst
location /pgsql {
set $input "hello'world\n";
set_quote_pgsql_str $safe $input;
return 200 "PostgreSQL: $safe\n";
}
Output: PostgreSQL: E'hello\'world\n'
set_quote_json_str
Escapes a string for safe inclusion in JSON. The result is wrapped in double quotes with special characters properly escaped.
Syntax: set_quote_json_str $dst <src> or set_quote_json_str $dst
location /json {
set $data "hello world";
set_quote_json_str $json $data;
return 200 "{\"message\": $json}\n";
}
Output: {"message": "hello world"}
This is particularly useful when constructing JSON responses directly in NGINX configuration.
Random Number Generation
set_random
Generates a pseudo-random integer within a specified range (inclusive).
Syntax: set_random $dst <from> <to>
location /random {
set_random $rand 1 100;
return 200 "Random: $rand\n";
}
The random number generator uses the standard C rand() function, seeded automatically by NGINX. For cryptographic applications, use set_secure_random_alphanum instead.
set_secure_random_alphanum
Generates a cryptographically secure random string using characters from [a-zA-Z0-9].
Syntax: set_secure_random_alphanum $dst <length>
Length: 1 to 64 characters
location /token {
set_secure_random_alphanum $token 32;
return 200 "Token: $token\n";
}
Output: Token: zuSh9MKf6kVGk3CVlW649JpQGPsVe5GW (example, varies each request)
This directive reads from /dev/urandom and is suitable for generating session tokens, CSRF tokens, and one-time passwords.
set_secure_random_lcalpha
Generates a cryptographically secure random string using only lowercase letters [a-z].
Syntax: set_secure_random_lcalpha $dst <length>
Length: 1 to 64 characters
location /slug {
set_secure_random_lcalpha $slug 16;
return 200 "Slug: $slug\n";
}
Output: Slug: qwertyuiopasdfgh (example, varies each request)
Lowercase-only strings are useful for URL slugs, filenames, and systems that normalize case.
Conditional Assignment
set_if_empty
Assigns a value to a variable only if it is empty (not set or contains an empty string).
Syntax: set_if_empty $dst <value>
location /default {
set $format $arg_format;
set_if_empty $format "json";
return 200 "Format: $format\n";
}
When accessing /default, the response is Format: json. When accessing /default?format=xml, the response is Format: xml.
This directive is essential for providing default values for optional query parameters, headers, or cookies.
Time Formatting
set_local_today
Sets the current date in YYYY-MM-DD format using local time.
Syntax: set_local_today $dst
location /today {
set_local_today $today;
return 200 "Today: $today\n";
}
Output: Today: 2026-02-22
set_formatted_gmt_time
Formats the current GMT time using strftime format specifiers.
Syntax: set_formatted_gmt_time $dst <format>
location /gmt {
set_formatted_gmt_time $timestamp "%Y-%m-%d %H:%M:%S GMT";
return 200 "GMT: $timestamp\n";
}
Output: GMT: 2026-02-22 14:30:00 GMT
Common format specifiers:
– %Y – 4-digit year
– %m – Month (01-12)
– %d – Day of month (01-31)
– %H – Hour (00-23)
– %M – Minute (00-59)
– %S – Second (00-59)
– %Z – Timezone abbreviation
set_formatted_local_time
Formats the current local time using strftime format specifiers.
Syntax: set_formatted_local_time $dst <format>
location /local {
set_formatted_local_time $timestamp "%Y-%m-%d %H:%M:%S %Z";
return 200 "Local: $timestamp\n";
}
Output: Local: 2026-02-22 21:30:00 WITA
Round-Robin Rotation
set_rotate
Increments a counter and keeps it within a specified range. When the counter exceeds the maximum, it wraps back to the minimum.
Syntax: set_rotate $dst <from> <to>
location /rotate {
set_rotate $counter 1 5;
return 200 "Counter: $counter\n";
}
Successive requests produce: 1, 2, 3, 4, 5, 1, 2, …
The counter state is maintained per-location across requests, making it useful for banner rotation, A/B testing, and simple round-robin load distribution.
Hashed Upstream Selection
set_hashed_upstream
Selects an upstream server from a predefined list by hashing a key value. This provides consistent routing where the same key always maps to the same upstream.
Syntax: set_hashed_upstream $dst <upstream_list> <key>
This directive requires defining an upstream list first:
upstream_list backends backend1 backend2 backend3;
upstream backend1 { server 10.0.0.1:8080; }
upstream backend2 { server 10.0.0.2:8080; }
upstream backend3 { server 10.0.0.3:8080; }
location /api {
set_hashed_upstream $backend backends $arg_user_id;
proxy_pass http://$backend;
}
Users with the same user_id are consistently routed to the same backend, which is valuable for maintaining session affinity without cookies.
Practical Use Cases
Generating Signed Download URLs
Create time-limited download URLs with HMAC verification:
location /download {
# Verify signature
set $expected_data "$uri$arg_expires";
set_hmac_sha256 $expected_sig "your-secret-key" $expected_data;
set_encode_base64url $expected_b64 $expected_sig;
if ($expected_b64 != $arg_sig) {
return 403 "Invalid signature";
}
# Check expiration
if ($arg_expires < $time_iso8601) {
return 410 "Link expired";
}
# Serve the file
alias /var/files;
try_files $uri =404;
}
Building Cache Keys with Content Hashing
Create deterministic cache keys based on request content:
location /api/query {
set $cache_input "$request_method|$uri|$args";
set_md5 $cache_key $cache_input;
proxy_cache_key $cache_key;
proxy_pass http://backend;
}
Secure Token Generation for APIs
Generate secure tokens for API authentication:
location /auth/token {
set_secure_random_alphanum $token 64;
set_formatted_gmt_time $expires "%Y-%m-%dT%H:%M:%SZ";
default_type application/json;
return 200 '{"token": "$token", "expires": "$expires"}';
}
URL-Safe Encoding for Cookies
Encode arbitrary data for storage in cookies:
location /set-cookie {
set $data "user_id=123&role=admin";
set_encode_base64url $encoded $data;
add_header Set-Cookie "session=$encoded; HttpOnly; Secure";
return 200 "Cookie set\n";
}
Dynamic JSON Response Construction
Build JSON responses with properly escaped values:
location /user {
set $name "John O'Brien";
set_quote_json_str $safe_name $name;
default_type application/json;
return 200 '{"user": $safe_name, "ip": "$remote_addr"}';
}
Performance Considerations
The NGINX set-misc module is designed for high performance:
CPU efficiency: All encoding and hashing operations use optimized C implementations. MD5 and SHA1 compute in microseconds for typical input sizes.
Memory usage: Operations work on NGINX’s internal string pools with minimal allocations. Large Base64-encoded values do require proportional memory.
Cryptographic operations: HMAC-SHA1 and HMAC-SHA256 use OpenSSL, benefiting from hardware acceleration on modern CPUs (AES-NI, SHA extensions).
Secure random: Reading from /dev/urandom is non-blocking on Linux and typically takes microseconds.
For high-traffic endpoints generating cryptographic hashes or signatures, the overhead is negligible compared to network I/O and upstream processing.
Security Best Practices
Use HMAC-SHA256 for New Applications
While HMAC-SHA1 is still secure for message authentication, HMAC-SHA256 provides a larger security margin and is recommended for new applications.
Protect Secret Keys
Store secret keys in NGINX variables defined in included files with restricted permissions:
include /etc/nginx/secrets.conf; # Contains: set $hmac_secret "...";
Ensure the secrets file is readable only by the NGINX master process:
chmod 600 /etc/nginx/secrets.conf
chown root:root /etc/nginx/secrets.conf
Use Secure Random for Security-Critical Applications
The set_random directive uses a pseudo-random number generator that is predictable. For session tokens, CSRF tokens, or any security-critical purpose, always use set_secure_random_alphanum or set_secure_random_lcalpha.
Validate Input Length
When processing user input with encoding functions, validate the input length to prevent denial-of-service through excessive memory allocation:
if ($request_body_length > 1048576) {
return 413 "Request too large";
}
Troubleshooting
“unknown directive set_encode_base64”
This error means either the module is not loaded or the NDK module is missing. Ensure both modules are loaded in the correct order:
load_module modules/ndk_http_module.so;
load_module modules/ngx_http_set_misc_module.so;
HMAC Functions Not Available
If set_hmac_sha1 or set_hmac_sha256 fail, verify that your NGINX build includes OpenSSL support. GetPageSpeed packages include OpenSSL by default.
set_if_empty Not Working with Special Variables
Do not use $arg_*, $cookie_*, or $http_* variables as the destination for set_if_empty. These special NGINX variables are read-only and attempting to modify them will cause a segmentation fault. Always copy to a regular variable first:
# WRONG - will crash
set_if_empty $arg_user "guest";
# CORRECT
set $user $arg_user;
set_if_empty $user "guest";
Empty Output from Hashing Functions
If hash functions return empty values, verify that the input variable contains data:
location /debug {
set $input $arg_data;
set_md5 $hash $input;
return 200 "Input: [$input] Hash: [$hash]\n";
}
Conclusion
The NGINX set-misc module brings essential encoding, hashing, and variable manipulation capabilities directly into your NGINX configuration. With 27 directives covering Base64, hexadecimal, cryptographic hashing, secure random generation, and string escaping, this module eliminates the need for backend processing of common data transformation tasks.
Whether you are building signed URLs, generating secure tokens for JWT authentication, constructing JSON responses, or implementing cache key strategies, the set-misc module provides the tools you need at the edge.
Install the module from the GetPageSpeed repository and start building more powerful NGINX configurations today. For the full source code and additional documentation, visit the set-misc-nginx-module GitHub repository.

