Site icon GetPageSpeed

NGINX iconv Module: Character Encoding Conversion

NGINX iconv Module: Convert Character Encodings at the Web Server Level

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:

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:

  1. 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.
  2. Response body filtering (iconv_filter): Converts the entire response body as it passes through NGINX. This works with proxied responses, static files, and return directives.

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_module directive 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:

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.

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