Skip to main content

proxy-rewrite

Rewrites the request URI, method, host and headers before proxying.

Category TransformationAdd it to Route, Service, Consumer, Consumer group, Global rule, Plugin configEngine plugin proxy-rewritePriority 1008

What it does​

proxy-rewrite changes the request the backend receives: the path, by a fixed URI or a pattern, the Host header, the method and the headers. The client is not redirected, and the request still goes to the route's upstream.

The route matches the path the client sends, before anything is rewritten, so its Path stays the one clients call. A query string the client sent stays attached to the new path.

When to use it​

  • A prefix that exists for routing only, /api/v1 for example, and must not reach the backend, while the rest of the path does.
  • A backend that reads the Host header and needs a name of its own, not the one the client used.
  • A backend that expects another path than the one clients call.
  • A header the backend must always see with your value, whatever the client sent, or one the client sends, a cookie for example, that must never reach it.

Not for sending the client to another address with a redirect — see redirect (Redirects requests to another URI or to HTTPS), changing the answer the client gets, its status, headers or body — see response-rewrite (Rewrites the response status, headers and body) or sending the request to another upstream — see traffic-split (Splits traffic between upstreams by weight and match rules).

Guides​

Pages that walk through a job with proxy-rewrite, step by step.

Set it up​

Remove the /api/v1 prefix and send the Host name the backend expects​

The route keeps the path clients call, /api/v1/orders/*; only the request the backend receives changes.

Fill Regex URI as in the JSON below and set Host to orders.internal.

The console's Add plugin panel, filled with this example.
proxy-rewrite · as the console saves it
{
"regex_uri": [
"^/api/v1/(.*)",
"/$1"
],
"host": "orders.internal"
}

What you will see​

  • A request for /api/v1/orders/42 reaches the backend as GET /orders/42 with Host: orders.internal: the prefix is gone and the rest of the path stays.
  • A query string the client sends stays attached: /api/v1/orders/42?page=2 arrives as GET /orders/42?page=2.

More scenarios​

Rewrite the path and the Host header sent to the backend

The request still goes to the route's own upstream; only the path and the Host header it carries change.

Set URI to /v2/orders and set Host to orders.internal.

proxy-rewrite · as the console saves it
{
"uri": "/v2/orders",
"host": "orders.internal"
}

What you will see​

  • A request for the route's path with ?page=2 reaches the backend as GET /v2/orders?page=2 with Host: orders.internal: the query string stays, the method stays.
  • X-Tenant: acme and the body go on as the client sent them, and a POST arrives as POST /v2/orders.
Remove the /api/v2 prefix before the request reaches the backend

Clients keep calling the route's own path; the pattern is read against the path alone, and the query string stays as it is.

Fill Regex URI as in the JSON below.

proxy-rewrite · as the console saves it
{
"regex_uri": [
"^/api/v2/(.*)",
"/$1"
]
}

What you will see​

  • A request for /api/v2/orders/42?page=2 reaches the backend as GET /orders/42?page=2: the prefix is gone and the query string stays.
Stamp one value on a header, whatever the client sent

The plain shape, a header name with one value, writes the header over the value the client sent, the way Set does in the other shape.

Choose One value per header and fill Headers as in the JSON below.

proxy-rewrite · as the console saves it
{
"headers": {
"X-Tenant": "acme"
}
}

What you will see​

  • The backend sees X-Tenant: acme and nothing of the value the client sent under that name.
Set, add and remove request headers before the backend sees them

Set writes the header over whatever the client sent, Add appends your value beside the one the client sent, and Remove drops the header.

Choose Add, set and remove and fill Headers as in the JSON below.

proxy-rewrite · as the console saves it
{
"headers": {
"add": {
"X-Request-Source": "gateway"
},
"remove": [
"Cookie"
],
"set": {
"X-Forwarded-Proto": "https"
}
}
}

What you will see​

  • The backend sees X-Forwarded-Proto as https whatever the client sent.
  • A client that sends its own X-Request-Source keeps it: the backend sees both values, client first and gateway after it.
  • No Cookie reaches the backend.

Things to know​

  • URI — A fixed URI replaces the whole path: on a route whose Path ends in /*, every request the route takes reaches the backend with that one path, whatever followed the prefix. To keep the rest of the path, use Regex URI.
  • URI — The query string the client sent stays attached to the new path.
  • Regex URI — $1 in the replacement is what the first bracket of the pattern matched. The pattern is read against the path without its query string, which stays attached afterwards.
  • Headers — Two shapes, never mixed in one configuration: one value per header writes each header over what the client sent, and Add, set and remove is the three lists.
  • Add — Add keeps the value the client sent and appends yours, so the backend sees both; to replace it, use Set.

Settings​

The fields as the console shows them, section by section.

URIuristring

The path the request is forwarded with, in place of the one the client sent.

1 to 4096 characters ·
pattern^\/.*
· example /api/v2/orders
Regex URIregex_uriarray of strings

Rewrites the client's path by a pattern: the first part matches, the second builds the new path. A plain URI, when set, wins over it.

at least 2 items
Hosthoststring

The Host header sent to the upstream, such as orders.internal, while the request still goes to the upstream's own nodes. An upstream whose Host passing is node or rewrite overrides it: the node address or the upstream's own host is sent instead.

pattern^[0-9a-zA-Z-.]+(:\d{1,5})?$
· example backend.internal
Methodmethodstring

The HTTP method the request is forwarded with.

one of COPY, DELETE, GET, HEAD, LOCK, MKCOL, MOVE, OPTIONS, PATCH, POST, PROPFIND, PUT, TRACE, UNLOCK

Choose one:

  • One value per headerEvery header is written with the value given here, replacing what the request carries.
  • Add, set and removeThree lists: headers to append, headers to write over and headers to drop.
  • No header changes

One value per header​

Headersheadersobject

Headers added to, set on or removed from the request before it is forwarded. An object whose keys are a name without a colon, each with a string or number as its value.

object at least 1 key

Add, set and remove​

Headersheadersobject

Headers added to, set on or removed from the request before it is forwarded.

object at least 1 key
Addheaders.addobject

An object whose keys are a name without a colon, each with a string or number or array as its value.

at least 1 key · example {"X-Request-Source":"gateway"}
Removeheaders.removearray of strings
at least 1 item
Setheaders.setobject

An object whose keys are a name without a colon, each with a string or number or array as its value.

at least 1 key · example {"X-Forwarded-Proto":"https"}
Use real request URI unsafeuse_real_request_uri_unsafebooleandefault false

Forwards the path exactly as the client sent it, without the normalisation this plugin otherwise applies (x/../y becomes y). A URI set above still wins over it. Leave it off unless the upstream needs the raw path: dot segments and encoded slashes then reach it untouched.

Every plugin also has Enabled, Priority, Filter, Error response and Pre-function: see Plugin execution settings.

G8 dev · Apache APISIX® 3.19.0
Apache, Apache APISIX and APISIX are trademarks of The Apache Software Foundation.
Facts
Category
Transformation
Add it to
Route, Service, Consumer, Consumer group, Global rule, Plugin config
Engine plugin
proxy-rewrite
Priority
1008