When setting up a reverse proxy in Nginx, the sub_filter
directive is commonly used for replacing strings in proxied content. However, a significant limitation exists: you can only specify one sub_filter
per location block. This becomes problematic when you need multiple replacements.
location / {
proxy_pass http://upstream;
sub_filter 'Original' 'Replacement';
sub_filter_once off;
}
Here are three practical approaches to overcome this limitation:
1. Using Multiple Location Blocks
Create separate location blocks for different paths, each with its own sub_filter:
location /path1/ {
proxy_pass http://upstream/path1/;
sub_filter 'String1' 'New1';
sub_filter_once off;
}
location /path2/ {
proxy_pass http://upstream/path2/;
sub_filter 'String2' 'New2';
sub_filter_once off;
}
2. Lua Module for Advanced Replacement
For more complex scenarios, consider using Nginx's Lua module:
location / {
proxy_pass http://upstream;
header_filter_by_lua_block {
ngx.arg[1] = ngx.arg[1]:gsub("Old1", "New1")
ngx.arg[1] = ngx.arg[1]:gsub("Old2", "New2")
}
body_filter_by_lua_block {
ngx.arg[1] = ngx.arg[1]:gsub("Old1", "New1")
ngx.arg[1] = ngx.arg[1]:gsub("Old2", "New2")
}
}
3. Combining Sub_filter with Regular Expressions
For simple cases, you might combine multiple replacements into one pattern:
location / {
proxy_pass http://upstream;
sub_filter 'Old1|Old2' '${1}New';
sub_filter_once off;
}
Each additional replacement impacts performance. For high-traffic sites:
- Cache processed responses when possible
- Minimize the number of replacements
- Consider doing replacements at the application level instead
Always verify your replacements work as expected:
curl -v http://yourproxy | grep -i "ReplacementString"
When setting up Nginx as a reverse proxy, the sub_filter
directive allows content modification during proxying, but comes with a significant constraint: only one replacement rule can be defined per location block. This becomes problematic when multiple string substitutions are needed.
location / {
proxy_pass http://upstream;
sub_filter 'Original' 'Replaced';
sub_filter_once off;
# Cannot add another sub_filter here
}
1. Using Multiple Location Blocks
Create separate location blocks for different path patterns, each with its own substitution rule:
location /section1/ {
proxy_pass http://upstream;
sub_filter 'foo' 'bar';
sub_filter_once off;
}
location /section2/ {
proxy_pass http://upstream;
sub_filter 'baz' 'qux';
sub_filter_once off;
}
2. Lua Module for Advanced Processing
For complex scenarios, Nginx's Lua module provides more flexibility:
location / {
proxy_pass http://upstream;
header_filter_by_lua_block {
ngx.header.content_length = nil
}
body_filter_by_lua_block {
local body = ngx.arg[1]
if body then
body = body:gsub("pattern1", "replacement1")
body = body:gsub("pattern2", "replacement2")
ngx.arg[1] = body
end
}
}
3. Using the Perl Module
For environments where Perl is available, you can leverage Nginx's perl module:
location / {
proxy_pass http://upstream;
perl_modules perl/lib;
perl_require replace.pm;
perl_set $processed_content 'MyReplace::filter';
}
With replace.pm containing:
package MyReplace;
sub filter {
my $r = shift;
my $content = $r->request_body;
$content =~ s/old1/new1/g;
$content =~ s/old2/new2/g;
return $content;
}
1;
When implementing multiple replacements:
- The Lua solution offers best performance for most cases
- Multiple location blocks work well when content is naturally segmented
- Perl module provides maximum flexibility but with higher overhead
For extremely complex scenarios, consider processing the content externally:
location / {
proxy_pass http://upstream;
proxy_set_header Accept-Encoding "";
sub_filter '' ''; # Dummy filter to enable processing
sub_filter_once off;
# Additional processing through fastcgi or proxy to processing service
}