When working with Apache's reverse proxy configuration, you might need to inject custom headers into requests being forwarded to backend servers. A common use case is adding authentication tokens, tracking information, or other metadata that your backend service requires.
Here's the standard ProxyPass setup mentioned in the question:
<VirtualHost *:80>
ServerName hello.local
ProxyPass / http://localhost:8810/
ProxyPassReverse / http://localhost:8810/
</VirtualHost>
Apache's mod_headers
module combined with environment variables provides the most flexible solution:
<VirtualHost *:80>
ServerName hello.local
# Execute external command and store in environment variable
SetEnvIfExpr "exec('/usr/bin/an_external_program')" MY_HEADER_VALUE
# Pass the header to the backend
RequestHeader set MyHeader "%{MY_HEADER_VALUE}e"
ProxyPass / http://localhost:8810/
ProxyPassReverse / http://localhost:8810/
</VirtualHost>
For more complex scenarios, you can use mod_rewrite
:
<VirtualHost *:80>
ServerName hello.local
RewriteEngine On
RewriteRule .* - [E=MY_HEADER_VALUE:exec('/usr/bin/an_external_program')]
RequestHeader set MyHeader "%{MY_HEADER_VALUE}e"
ProxyPass / http://localhost:8810/
ProxyPassReverse / http://localhost:8810/
</VirtualHost>
- Make sure
mod_headers
andmod_setenvif
(ormod_rewrite
) are loaded - The external program should execute quickly to avoid request delays
- For security, validate the output of external commands
- Consider caching the command output if it doesn't change frequently
To verify headers are being passed correctly:
curl -v http://hello.local
Or check the logs on your backend server to confirm the headers are received.
When working with Apache's reverse proxy configuration, there are cases where you need to inject dynamic headers into proxied requests. The standard ProxyPass
directive doesn't directly support executing external commands to generate header values, which creates an interesting technical challenge.
While Apache's Header
directive is powerful for manipulating response headers, it has limitations when:
- You need to set request headers (not response headers)
- The header value must come from an external program's output
Here's a complete implementation that solves both requirements:
ServerName hello.local
RewriteEngine On
RewriteRule .* - [E=MY_HEADER_VALUE:/usr/bin/an_external_program]
RequestHeader set MyHeader "%{MY_HEADER_VALUE}e"
ProxyPass / http://localhost:8810/
ProxyPassReverse / http://localhost:8810/
The key components are:
mod_rewrite
to execute the external command and store its output in an environment variablemod_headers
withRequestHeader
to set the proxied request header- The
%{VAR}e
syntax to reference environment variables
For more complex scenarios where you need to process the command output:
ServerName api.example.com
# Capture command output and sanitize it
RewriteEngine On
RewriteRule .* - [E=RAW_VALUE:/usr/local/bin/generate-api-key --service=proxy]
RewriteRule .* - [E=SANITIZED_KEY:%{RAW_VALUE}|base64]
# Set multiple dynamic headers
RequestHeader set X-API-Key "%{SANITIZED_KEY}e"
RequestHeader set X-Request-ID "%{TIME_YEAR}%{TIME_MON}%{TIME_DAY}%{TIME_HOUR}%{TIME_MIN}%{TIME_SEC}"
RequestHeader set X-Forwarded-Proto "https" env=HTTPS
ProxyPass / http://backend:8080/
ProxyPassReverse / http://backend:8080/
Be mindful that:
- External command execution happens for every request
- Consider caching mechanisms if the command output doesn't change frequently
- For high-traffic sites, implement this at a load balancer level instead
For Apache 2.4+ with mod_lua enabled, you can achieve this programmatically:
ServerName lua.example.com
LuaHookFixups /path/to/header_script.lua add_headers
ProxyPass / http://localhost:8888/
With header_script.lua
containing:
function add_headers(r)
local handle = io.popen("/usr/bin/dynamic-header-generator")
local result = handle:read("*a")
handle:close()
r.headers_in["X-Dynamic-Header"] = result
return apache2.OK
end