Note: With UTF-8 now accounting for over 98% of all web pages, most modern stacks have no need for the NGINX iconv module. It is primarily useful for legacy system integration — older ERP systems, government platforms, or industrial controllers that still require encodings like GBK, Shift_JIS, or EUC-KR.
The NGINX iconv module converts character encodings directly at the web server level. It uses the well-established libiconv library to transform text between any supported encodings — UTF-8 to GBK, Shift_JIS to UTF-8, ISO-8859-1 to UTF-16, and hundreds more. Instead of adding encoding logic to every backend service, you handle it once in NGINX.
When You Need This Module
The NGINX iconv module solves a specific problem: bridging encoding gaps between systems you cannot modify. Here are the realistic use cases in 2026:
- Legacy system integration: An older ERP, industrial controller, or government platform only accepts GBK, EUC-KR, or Shift_JIS. Your modern backend outputs UTF-8 exclusively.
- Proxy gateways: NGINX sits between a UTF-8 backend and a legacy downstream consumer. You cannot modify either side.
- Regional compliance: Some Chinese government or banking systems still mandate GB18030 or GBK for data exchange.
- Variable manipulation: Converting a query parameter or header value from a legacy encoding to UTF-8 before passing it to a modern upstream.
If your entire stack uses UTF-8, skip this module entirely.
How the NGINX iconv Module Works
The module provides two distinct mechanisms for encoding conversion:
- Variable conversion (
set_iconv): Converts an NGINX variable from one encoding to another during the rewrite phase. This works well for query parameters, header values, or redirect URLs. -
Response body filtering (
iconv_filter): Converts the entire response body as it passes through NGINX. This works with proxied responses, static files, andreturndirectives.
Both mechanisms rely on libiconv internally. The module opens an iconv conversion descriptor for each request and processes data in configurable buffer chunks. It handles incomplete multi-byte characters that span buffer boundaries. Invalid byte sequences are replaced with ? rather than breaking the entire response.
The NGINX iconv module depends on the ngx_devel_kit (NDK) module. NDK provides the infrastructure for custom variable setters like set_iconv. It installs automatically as a dependency from GetPageSpeed repositories. Like the iconv module, NDK is also used by the NGINX Form Input module and the NGINX Encrypted Session module.
Installation
RHEL, CentOS, AlmaLinux, Rocky Linux, Fedora
Install from the GetPageSpeed extras repository:
sudo dnf install https://extras.getpagespeed.com/release-latest.rpm
sudo dnf install nginx-module-iconv
Then load both modules in your nginx.conf. NDK must come first:
load_module modules/ndk_http_module.so;
load_module modules/ngx_http_iconv_module.so;
Place these directives at the top level, before the events block.
Debian and Ubuntu
First, set up the GetPageSpeed APT repository, then install:
sudo apt-get update
sudo apt-get install nginx-module-iconv
On Debian/Ubuntu, the package handles module loading automatically. No
load_moduledirective is needed.
Package details are available on the RPM module page and the APT module page.
After installation, verify the module loads correctly:
nginx -t
If the test passes, the NGINX iconv module is ready to use.
Configuration Directives
The NGINX iconv module provides three directives. All three are valid only in the location context.
set_iconv
Syntax: set_iconv $destination $source from=<encoding> to=<encoding>;
Default: none
Context: location
Phase: rewrite
Converts $source from one encoding to another and stores the result in $destination. The converted variable is then available for return, proxy_set_header, or rewrite.
Example — convert a UTF-8 string to GBK:
location /convert {
set $original "你好世界";
set_iconv $converted $original from=utf-8 to=gbk;
return 200 $converted;
}
You can use any encoding that libiconv recognizes. Common choices include utf-8, gbk, gb2312, big5, shift_jis, euc-jp, euc-kr, iso-8859-1, windows-1251, and utf-16.
iconv_filter
Syntax: iconv_filter from=<encoding> to=<encoding>;
Default: none
Context: location
Phase: output filter
Converts the entire response body. Use this directive when converting proxied content, static files, or any response body in bulk.
Example — convert a proxied backend’s UTF-8 response to GBK:
location /api {
iconv_filter from=utf-8 to=gbk;
proxy_pass http://backend;
}
When iconv_filter is active, NGINX removes the Content-Length header. It switches to chunked transfer encoding instead. This is necessary because converted content may differ in byte length.
The filter also works with static files:
location /legacy {
iconv_filter from=utf-8 to=shift_jis;
root /var/www/html;
}
It even works with return directives:
location /greeting {
iconv_filter from=utf-8 to=gbk;
return 200 "你好世界";
}
iconv_buffer_size
Syntax: iconv_buffer_size <size>;
Default: iconv_buffer_size 4k; (one memory page)
Context: location
Sets the buffer size for encoding conversion. The module processes input in chunks of this size. The minimum allowed value is 2 bytes.
For most use cases, the default of 4 KB works well. Increase it for large response bodies to reduce buffer allocation cycles:
location /large-responses {
iconv_filter from=utf-8 to=gbk;
iconv_buffer_size 8k;
proxy_pass http://backend;
}
A smaller buffer still works correctly. The module handles overflow by allocating additional buffers. However, very small values increase allocation overhead.
Practical Examples
Converting Proxied API Responses
A typical use case: a modern UTF-8 API sits behind NGINX, but a legacy downstream system expects GBK. The NGINX iconv module handles this transparently:
upstream modern_api {
server 10.0.0.5:8080;
}
server {
listen 80;
server_name legacy-gateway.example.com;
location /api/ {
iconv_filter from=utf-8 to=gbk;
iconv_buffer_size 4k;
proxy_pass http://modern_api;
proxy_set_header Host $host;
}
}
Every response from modern_api gets its body converted from UTF-8 to GBK before reaching the client. For related guidance on tuning proxy buffer sizes in NGINX, see our dedicated article.
Converting Query Parameters
When a legacy client sends a query parameter in GBK but your backend expects UTF-8, use set_iconv to convert it at the NGINX level:
location /search {
set $raw_query $arg_q;
set_iconv $utf8_query $raw_query from=gbk to=utf-8;
proxy_pass http://backend/search?q=$utf8_query;
}
Serving Static Files in a Different Encoding
Serve a directory of UTF-8 HTML files in EUC-JP for legacy Japanese clients:
location /legacy-jp/ {
iconv_filter from=utf-8 to=euc-jp;
iconv_buffer_size 4k;
root /var/www/html;
}
Testing Your Configuration
After adding directives to your configuration, verify the syntax:
nginx -t
Then reload NGINX:
systemctl reload nginx
Use curl with xxd to inspect raw bytes and confirm the conversion:
curl -s http://localhost/convert | xxd | head
The Chinese characters “你好世界” in GBK appear as c4e3 bac3 cac0 bde7. In UTF-8 they appear as e4bda0 e5a5bd e4b896 e7958c. If you see the GBK bytes, conversion is working.
Compare filtered and unfiltered responses side by side:
# Direct UTF-8 from backend
curl -s http://backend:8080/api | xxd | head
# Converted GBK through NGINX
curl -s http://localhost/api | xxd | head
Performance Considerations
Encoding conversion adds CPU overhead to every filtered request. Follow these guidelines:
- Apply selectively: Use
iconv_filteronly where needed. Never apply it globally. - Tune buffer size: The default 4 KB is efficient for most payloads. Larger buffers reduce allocations for big responses but use more memory.
- Avoid no-op conversions: Converting UTF-8 to UTF-8 still runs the full conversion cycle. Only convert where there is an actual mismatch.
- Cache converted responses: Place an NGINX proxy cache before the converting location. The conversion then happens only once per cache lifetime.
Monitor CPU usage after enabling the module. Overhead scales with data volume, not request count alone.
Troubleshooting
“unknown directive set_iconv”
The module is not loaded. Add both load_module directives to nginx.conf:
load_module modules/ndk_http_module.so;
load_module modules/ngx_http_iconv_module.so;
NDK must come before iconv. Reversing the order causes a load failure.
“iconv_buffer_size must not less than 2 bytes”
The minimum buffer size is 2 bytes. Values of 0 or 1 are rejected. Use the default of one page size unless you have a specific reason to change it.
Invalid Character Sequences (EILSEQ)
When the module encounters invalid bytes, it logs a notice:
iconv sees invalid character sequence (EILSEQ)
Invalid bytes are replaced with ? and conversion continues. If you see many of these messages, check that from= matches the actual encoding.
Incomplete Multi-byte Characters (EINVAL)
Multi-byte characters split across buffer boundaries are handled automatically. The module stores incomplete bytes and prepends them to the next buffer. Truncated sequences at the very end of a response are silently dropped.
HTTP/1.0 and Keep-Alive
When iconv_filter is active and the client uses HTTP/1.0, keep-alive is disabled. The filter removes Content-Length in favor of chunked encoding, which HTTP/1.0 does not support. HTTP/1.1 and HTTP/2 clients are not affected.
Supported Encodings
The NGINX iconv module supports all encodings recognized by libiconv:
| Encoding | Region / Use Case |
|---|---|
utf-8 |
Universal modern standard |
gbk / gb2312 / gb18030 |
Simplified Chinese |
big5 |
Traditional Chinese |
shift_jis / euc-jp / iso-2022-jp |
Japanese |
euc-kr |
Korean |
iso-8859-1 (Latin-1) |
Western European |
windows-1251 |
Cyrillic |
windows-1252 |
Western European (Windows) |
utf-16 / utf-32 |
Unicode with BOM |
The full list is available in the libiconv documentation.
Conclusion
The NGINX iconv module provides server-level character encoding conversion through two directives: set_iconv for variables and iconv_filter for response bodies. In a world where UTF-8 dominates, this module fills a niche — bridging modern backends with legacy systems that still require older encodings like GBK, Shift_JIS, or EUC-KR.
If your stack is fully UTF-8, you do not need this module. But when legacy integration requirements arise, handling conversion in NGINX is cleaner than scattering it across application code.
The module is part of the OpenResty ecosystem and is maintained on GitHub. Pre-built packages are available from the GetPageSpeed repository for RPM and APT-based distributions.

