Modify HTTP request and response headers
Learn how to modify the request and response headers of your application using NGINX Gateway Fabric.
HTTP Header Modifiers can be used to add, modify or remove headers during the request-response lifecycle. The RequestHeaderModifier is used to alter headers in a request sent by client and ResponseHeaderModifier is used to alter headers in a response to the client.
This guide describes how to configure the headers application to modify the headers in the request. Another version of the headers application is then used to modify response headers when client requests are made. For an introduction to exposing your application, we recommend that you follow the basic guide first.
- Install NGINX Gateway Fabric.
The following examples use a shared Gateway for both RequestHeaderModifier and ResponseHeaderModifier filters. Header values can be plain strings or NGINX variable names such as $remote_addr or $request_method.
The Gateway resource is typically deployed by the Cluster Operator. This Gateway defines a single listener on port 80. Since no hostname is specified, this listener matches on all hostnames. To deploy the Gateway:
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: gateway
spec:
gatewayClassName: nginx
listeners:
- name: http
port: 80
protocol: HTTP
EOFAfter creating the Gateway resource, NGINX Gateway Fabric will provision an NGINX Pod and Service fronting it to route traffic. Verify the gateway is created:
kubectl describe gateways.gateway.networking.k8s.io gatewayVerify the status is Accepted:
Status:
Addresses:
Type: IPAddress
Value: 10.96.36.219
Conditions:
Last Transition Time: 2026-01-09T05:40:37Z
Message: The Gateway is accepted
Observed Generation: 1
Reason: Accepted
Status: True
Type: Accepted
Last Transition Time: 2026-01-09T05:40:37Z
Message: The Gateway is programmed
Observed Generation: 1
Reason: Programmed
Status: True
Type: ProgrammedSave the public IP address and port(s) of the Gateway into shell variables:
GW_IP=XXX.YYY.ZZZ.III
GW_PORT=<port number>In a production environment, you should have a DNS record for the external IP address that is exposed, and it should refer to the hostname that the gateway will forward for.
This examples demonstrates how to configure traffic routing for a simple echo server. A HTTPRoute resource is used to route traffic to the headers application, using the RequestHeaderModifier filter to modify headers in the request. You can then verify that the server responds with the modified request headers.
Begin by deploying the example application headers. It is a simple application that returns the request headers which will be modified later.
kubectl apply -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v2.5.0/examples/http-request-header-filter/headers.yamlThis will create the headers Service and a Deployment with one Pod. Run the following command to verify the resources were created:
kubectl get pods,svcpod/headers-545698447b-z52kj 1/1 Running 0 23s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/headers ClusterIP 10.96.26.161 <none> 80/TCP 23sCreate a HTTPRoute that exposes the header application outside the cluster using the listener created in the previous section. Use the following command:
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: headers
spec:
parentRefs:
- name: gateway
sectionName: http
hostnames:
- "echo.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /headers
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
set:
- name: My-Overwrite-Header
value: this-is-the-only-value
- name: X-Client-IP
value: $remote_addr
add:
- name: Accept-Encoding
value: compress
- name: My-Cool-header
value: this-is-an-appended-value
- name: X-Request-Method
value: $request_method
remove:
- User-Agent
backendRefs:
- name: headers
port: 80
EOFThis HTTPRoute has a few important properties:
-
The
parentRefsreferences the Gateway resource that we created, and specifically defines thehttplistener to attach to, via thesectionNamefield. -
echo.example.comis the hostname that is matched for all requests to the backends defined in this HTTPRoute. -
The
matchrule defines that all requests with the path prefix/headersare sent to theheadersService. -
It has a
RequestHeaderModifierfilter defined for the path prefix/headers. This filter:- Sets
My-Overwrite-Headertothis-is-the-only-valueandX-Client-IPto the value of$remote_addr. - Appends
compresstoAccept-Encoding,this-is-an-appended-valuetoMy-Cool-header, and the value of$request_methodtoX-Request-Method. - Removes
User-Agentheader.
- Sets
To access the application, use curl to send requests to the headers Service, which includes headers within the request.
curl -s --resolve echo.example.com:$GW_PORT:$GW_IP http://echo.example.com:$GW_PORT/headers -H "My-Cool-Header:my-client-value" -H "My-Overwrite-Header:dont-see-this" -H "X-Request-Method:POST"Headers:
header 'Accept-Encoding' is 'compress'
header 'My-cool-header' is 'my-client-value,this-is-an-appended-value'
header 'X-Request-Method' is 'POST,GET'
header 'My-Overwrite-Header' is 'this-is-the-only-value'
header 'X-Client-IP' is '127.0.0.1'
header 'Host' is 'echo.example.com:8080'
header 'X-Forwarded-For' is '127.0.0.1'
header 'X-Real-IP' is '127.0.0.1'
header 'X-Forwarded-Proto' is 'http'
header 'X-Forwarded-Host' is 'echo.example.com'
header 'X-Forwarded-Port' is '80'
header 'Accept' is '*/*'In the output above, you can see that the headers application modifies the following custom headers:
User-Agentheader is absent.- The header
My-Cool-headergets appended with the new valuemy-client-value. - The header
X-Request-Methodis appended with the valueGET, resolved from the$request_methodvariable. - The header
X-Client-IPis set to127.0.0.1, the remote address of the client that sent the request resolved from the$remote_addrvariable. - The header
My-Overwrite-Headergets overwritten fromdont-see-thistothis-is-the-only-value. - The header
Accept-encodingremains unchanged as we did not modify it in the curl request sent.
Delete the headers application and HTTPRoute: another instance will be used for the next examples.
kubectl delete httproutes.gateway.networking.k8s.io headerskubectl delete -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v2.5.0/examples/http-request-header-filter/headers.yamlBegin by configuring an application with custom headers and a simple HTTPRoute. The server response can be observed see its headers. The next step is to modify some of the headers using HTTPRoute filters to modify responses. Finally, verify the server responds with the modified headers.
Begin by deploying the example application headers. It is a simple application that adds response headers that will be modified later.
kubectl apply -f https://raw.githubusercontent.com/nginx/nginx-gateway-fabric/v2.5.0/examples/http-response-header-filter/headers.yamlThis will create the headers Service and a Deployment with one Pod. Run the following command to verify the resources were created:
kubectl get pods,svcNAME READY STATUS RESTARTS AGE
pod/headers-6f854c478-hd2jr 1/1 Running 0 95s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/headers ClusterIP 10.96.15.12 <none> 80/TCP 95sCreate a HTTPRoute that exposes the header application outside the cluster using the listener created in the previous section. You can do this with the following command:
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: headers
spec:
parentRefs:
- name: gateway
sectionName: http
hostnames:
- "cafe.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /headers
backendRefs:
- name: headers
port: 80
EOFThis HTTPRoute has a few important properties:
- The
parentRefsreferences the Gateway resource that we created, and specifically defines thehttplistener to attach to, via thesectionNamefield. cafe.example.comis the hostname that is matched for all requests to the backends defined in this HTTPRoute.- The
matchrule defines that all requests with the path prefix/headersare sent to theheadersService.
Use curl with the -i flag to access the application and include the response headers in the output:
curl -i --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/headersHTTP/1.1 200 OK
Server: nginx
Date: Mon, 30 Mar 2026 21:24:25 GMT
Content-Type: text/plain
Content-Length: 2
Connection: keep-alive
X-Header-Unmodified: unmodified
X-Header-Add: add-to
X-Header-Set: overwrite
X-Header-Remove: remove
X-Real-IP: 10.244.0.53
okIn the output above, you can see that the headers application adds the following custom headers to the response:
- X-Header-Unmodified: unmodified
- X-Header-Add: add-to
- X-Header-Set: overwrite
- X-Header-Remove: remove
- X-Real-IP: set to the value of
$server_addr, the IP address of the server that accepted the request.
The next section will modify these headers by adding a ResponseHeaderModifier filter to the headers HTTPRoute.
Update the HTTPRoute by adding a ResponseHeaderModifier filter:
kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: headers
spec:
parentRefs:
- name: gateway
sectionName: http
hostnames:
- "cafe.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /headers
filters:
- type: ResponseHeaderModifier
responseHeaderModifier:
set:
- name: X-Header-Set
value: overwritten-value
- name: X-Real-IP
value: $remote_addr
add:
- name: X-Header-Add
value: this-is-the-appended-value
- name: X-Request-ID
value: $request_id
backendRefs:
- name: headers
port: 80
EOFNotice that this HTTPRoute has a ResponseHeaderModifier filter defined for the path prefix /headers. This filter:
- Sets the value for the header
X-Header-Settooverwritten-value. - Overwrites the value for the header
X-Real-IPto$remote_addrvariable. - Adds the value
this-is-the-appended-valueto the headerX-Header-Add. - Adds the value
$request_idto the headerX-Request-ID. - Removes
X-Header-Removeheader.
Send a curl request to the modified headers application to verify the response headers are modified.
curl -i --resolve cafe.example.com:$GW_PORT:$GW_IP http://cafe.example.com:$GW_PORT/headersHTTP/1.1 200 OK
Server: nginx
Date: Mon, 30 Mar 2026 21:26:40 GMT
Content-Type: text/plain
Content-Length: 2
Connection: keep-alive
X-Header-Unmodified: unmodified
X-Header-Add: add-to
X-Header-Add: this-is-the-appended-value
X-Request-ID: dad7ece8fd0d1cb83301be8a361a55b1
X-Header-Set: overwritten-value
X-Real-IP: 127.0.0.1
okThe output confirms the filter was applied. X-Header-Unmodified is unchanged because it was not included in the filter. X-Header-Remove is absent. X-Header-Add appears twice with both the original and appended values. X-Header-Set is overwritten to overwritten-value. X-Real-IP is overwritten with the resolved value of $remote_addr, the client’s IP address. X-Request-ID is added with the resolved value of $request_id.
To learn more about the Gateway API and the resources we created in this guide, check out the following Kubernetes documentation resources: