yum upgrades for production use, this is the repository for you.
Active subscription is required.
The NGINX form input module lets you parse HTTP POST and PUT request bodies encoded as application/x-www-form-urlencoded and extract individual form fields into NGINX variables. This gives system administrators the power to make routing decisions, log specific form values, and set proxy headers based on POST data — all at the NGINX level, before the request ever reaches a backend application.
In this guide, you will learn how to install and configure the module, understand its directives and limitations, and apply it to real-world use cases.
How It Works
When a client submits an HTML form via POST or PUT, the browser typically encodes the data as application/x-www-form-urlencoded. For example, a login form submission produces a request body like:
username=admin&password=secret123&action=login
The module intercepts this request body during the rewrite phase and parses it into key-value pairs. You can then access any form field as an NGINX variable using the set_form_input directive.
This module depends on the NGINX Development Kit (NDK), which provides the underlying variable-setting infrastructure. Both modules must be loaded for form-input to function.
Key Characteristics
- Supported methods: POST and PUT only. GET requests are silently ignored.
- Supported content types: Only
application/x-www-form-urlencoded. JSON and multipart content types are skipped. - Processing phase: Runs in the rewrite phase. Parsed variables are available to
ifblocks,rewriterules, and downstream directives. - No URL decoding: Raw URL-encoded values are returned. Use the set-misc module’s
set_unescape_urito decode them.
Installation
RHEL, CentOS, AlmaLinux, Rocky Linux
sudo dnf install https://extras.getpagespeed.com/release-latest.rpm
sudo dnf install nginx-module-form-input
The package automatically installs the required nginx-module-ndk dependency. After installation, load both modules in your nginx.conf. The NDK module must be loaded first:
load_module modules/ndk_http_module.so;
load_module modules/ngx_http_form_input_module.so;
Debian and Ubuntu
First, set up the GetPageSpeed APT repository, then install:
sudo apt-get update
sudo apt-get install nginx-module-form-input
On Debian/Ubuntu, the package handles module loading automatically. No
load_moduledirective is needed.
You can find additional package details on the RPM module page and APT module page.
Directives
The NGINX form input module provides two directives. Both work in http, server, and location contexts.
set_form_input
set_form_input $variable [field_name];
Parses a single form field from the request body and stores its value in $variable.
- If
field_nameis omitted, the variable name (without$) is used. For example,set_form_input $email;reads theemailfield. - If the field appears multiple times, only the first occurrence is captured.
- If the field is absent, the variable becomes an empty string.
Example:
location /submit {
client_max_body_size 100k;
client_body_buffer_size 100k;
# Variable name matches field name
set_form_input $name;
# Variable name differs from field name
set_form_input $user_email email;
return 200 "name=$name, email=$user_email\n";
}
Sending a POST request:
curl -X POST http://localhost/submit -d "name=John&email=john@example.com"
Returns:
name=John, email=john@example.com
set_form_input_multi
set_form_input_multi $variable [field_name];
Parses all values for a given field name into an array variable. This is useful when a form submits multiple values with the same name, such as checkboxes or multi-select lists.
The resulting array requires the NGINX array-var module to manipulate. Use array_join to convert the array into a delimited string.
Example with the array-var module:
location /preferences {
client_max_body_size 100k;
client_body_buffer_size 100k;
set_form_input_multi $colors color;
array_join ", " $colors;
return 200 "Selected colors: $colors\n";
}
Critical Configuration: Buffer Size Alignment
The module reads the request body from in-memory buffers only. If the body exceeds client_body_buffer_size, NGINX writes the overflow to a temporary disk file. The module cannot read disk-buffered data.
You must set client_max_body_size and client_body_buffer_size to the same value:
location /api {
# Both must match — disk-buffered bodies cannot be parsed
client_max_body_size 100k;
client_body_buffer_size 100k;
set_form_input $action;
# ...
}
If the body exceeds the buffer, NGINX logs an error:
form-input: in-file buffer found. aborted. consider increasing your client_body_buffer_size setting
For more details on body size settings, see our NGINX client_max_body_size guide.
Practical Use Cases
Conditional Routing Based on Form Data
Route POST requests to different handlers based on a field value. This eliminates the need for a backend to handle simple routing:
location /api {
client_max_body_size 100k;
client_body_buffer_size 100k;
set_form_input $action;
if ($action = "login") {
return 200 "Routing to login handler\n";
}
if ($action = "register") {
return 200 "Routing to registration handler\n";
}
return 400 "Unknown action\n";
}
For advanced variable-based routing, combine set_form_input with the map directive to map field values to upstream backends.
Logging Form Field Values
Capture specific fields in NGINX access logs for auditing or analytics:
log_format form_log '$remote_addr - [$time_local] "$request" '
'$status - username=$form_username';
server {
location /login {
client_max_body_size 100k;
client_body_buffer_size 100k;
set_form_input $form_username username;
access_log /var/log/nginx/login.log form_log;
proxy_pass http://backend;
}
}
A POST to /login with username=johndoe produces:
127.0.0.1 - [06/Mar/2026:12:28:19 +0800] "POST /login HTTP/1.1" 200 - username=johndoe
Security note: Never log sensitive fields like passwords. Only log identifiers needed for auditing.
Setting Proxy Headers from Form Data
Extract a form field and pass it as a custom header to the backend:
location /api/submit {
client_max_body_size 100k;
client_body_buffer_size 100k;
set_form_input $token;
proxy_set_header X-Form-Token $token;
proxy_pass http://backend;
}
For a comprehensive reverse proxy guide, see NGINX Reverse Proxy.
URL-Decoding Form Values
Raw URL-encoded values are returned by default. Characters like %20 (space) and %40 (@) stay encoded. The + character (space in form encoding) is also preserved as-is.
To decode these values, use set_unescape_uri from the set-misc module:
location /search {
client_max_body_size 100k;
client_body_buffer_size 100k;
set_form_input $raw_query query;
set_unescape_uri $decoded_query $raw_query;
# $raw_query: "hello%20world%21"
# $decoded_query: "hello world!"
return 200 "Search query: $decoded_query\n";
}
The set-misc module also depends on NDK. Load all three modules together:
load_module modules/ndk_http_module.so;
load_module modules/ngx_http_set_misc_module.so;
load_module modules/ngx_http_form_input_module.so;
Testing Your Configuration
Syntax Check
nginx -t
Runtime Verification
Test with a simple POST request:
curl -X POST http://localhost/submit \
-d "name=TestUser&email=test@example.com"
Verify Content-Type Filtering
JSON payloads are ignored — only URL-encoded forms are parsed:
# Returns empty variables — JSON is not parsed
curl -X POST http://localhost/submit \
-H "Content-Type: application/json" \
-d '{"name":"TestUser"}'
Verify GET Requests Are Ignored
# GET requests produce empty variables
curl http://localhost/submit
Verify PUT Support
# PUT requests work just like POST
curl -X PUT http://localhost/submit \
-d "name=PutUser&email=put@example.com"
Performance Considerations
The module has minimal performance impact. It operates only during the rewrite phase and only on matching requests:
- No overhead for GET requests: Non-POST/PUT methods are skipped immediately.
- No overhead for non-form content types: JSON, multipart, and others are skipped entirely.
- Memory-only parsing: Data is read from in-memory buffers, avoiding disk I/O.
- Buffer size trade-off: High
client_body_buffer_sizevalues allocate memory per request. Use 100k for most HTML forms.
Security Best Practices
- Never log sensitive data: Do not include password fields or credit card numbers in custom log formats.
- Validate at the application layer: The module extracts values but does not sanitize them. Validate in your backend to prevent injection attacks.
- Limit body size: Set
client_max_body_sizeto prevent large POST bodies from consuming memory. - Consider WAF integration: For comprehensive inspection, use a WAF like ModSecurity or NAXSI.
- Be cautious with
ifblocks: Simple conditional returns are safe. However, review the pitfalls of NGINXifblocks when combining with other directives.
Troubleshooting
Variables Are Always Empty
- Check the HTTP method: Only POST and PUT are supported.
- Check the Content-Type: Must be
application/x-www-form-urlencoded. - Verify module loading order: NDK must load before form-input.
- Check buffer sizes: The buffer must hold the entire body.
“in-file buffer found” Error
The request body exceeded client_body_buffer_size. Set both directives to the same value:
client_max_body_size 100k;
client_body_buffer_size 100k;
“unknown directive” Error
The module is not loaded. Verify:
- The
.sofile exists:ls /usr/lib64/nginx/modules/ngx_http_form_input_module.so - Both
load_modulelines are at the top ofnginx.conf, beforeevents - NDK is loaded before form-input
Alternatives
Depending on your needs, other approaches may fit better:
- NGINX JavaScript (njs): Full programmatic access to request bodies, including JSON parsing. Best for complex processing.
- Lua module: Scripting with
ngx.req.get_post_args(). Ideal when you need more than variable extraction. - Upload module: Handles
multipart/form-datafile uploads. Use for file upload forms. - Backend parsing: For complex validation and business logic, parse form data in your application code.
The NGINX form input module is the right choice for simple, declarative extraction of URL-encoded form fields without a scripting engine.
Conclusion
The NGINX form input module bridges NGINX’s request routing with the POST data that applications submit via HTML forms. By extracting form fields into NGINX variables, you can implement conditional routing, targeted logging, and proxy header injection — without modifying backend code.
Combined with set-misc for URL decoding and array-var for multi-value fields, form-input becomes a versatile tool for handling form submissions at the edge.
The module source code is available on GitHub.
