Skill for configuring the Apache APISIX proxy-rewrite plugin via the a6 CLI. Covers rewriting request URI, host, method, headers, and scheme before forwarding to upstream. Includes regex URI rewriting, header manipulation, and common operational patterns.
The proxy-rewrite plugin rewrites request attributes before APISIX forwards
the request to the upstream. You can change the URI path, host header, HTTP
method, scheme, and add/set/remove request headers — all without modifying
your backend service.
/api/v1)| Field | Type | Required | Default | Description |
|---|---|---|---|---|
uri |
| string |
| No |
| — |
New upstream request URI. Supports Nginx variables (e.g., $uri, $arg_name). |
method | string | No | — | Override the HTTP method. Must be uppercase: GET, POST, PUT, DELETE, etc. |
host | string | No | — | New Host header value sent to upstream. |
scheme | string | No | — | New scheme for upstream request: http or https. |
headers | object | No | — | Header manipulation object with set, add, and remove fields. |
headers.set | object | No | — | Set (overwrite) headers. Key-value pairs. Supports Nginx variables. |
headers.add | object | No | — | Append headers. Key-value pairs. Adds even if the header already exists. |
headers.remove | array[string] | No | — | Remove headers. List of header names to strip. |
regex_uri | array[string] | No | — | Array of two strings: [pattern, replacement]. Uses PCRE regex to rewrite the URI. |
use_real_request_uri_unsafe | boolean | No | false | Use the original unescaped URI. Security risk — only enable if you understand the implications. |
Priority: If both uri and regex_uri are set, uri takes precedence.
Strip /api/v1 prefix so /api/v1/users becomes /users:
a6 route create -f - <<'EOF'
{
"id": "strip-prefix",
"uri": "/api/v1/*",
"plugins": {
"proxy-rewrite": {
"regex_uri": ["^/api/v1/(.*)", "/$1"]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"backend:8080": 1
}
}
}
EOF
Route to a different virtual host on the backend:
a6 route create -f - <<'EOF'
{
"id": "rewrite-host",
"uri": "/legacy/*",
"plugins": {
"proxy-rewrite": {
"host": "legacy.internal.svc"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"backend:8080": 1
}
}
}
EOF
a6 route create -f - <<'EOF'
{
"id": "header-manip",
"uri": "/api/*",
"plugins": {
"proxy-rewrite": {
"headers": {
"set": {
"X-Forwarded-Proto": "https",
"X-Real-IP": "$remote_addr"
},
"add": {
"X-Request-Start": "$msec"
},
"remove": ["X-Internal-Debug", "X-Secret-Token"]
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"backend:8080": 1
}
}
}
EOF
Rewrite /products/123/reviews to /api/products?id=123§ion=reviews:
{
"plugins": {
"proxy-rewrite": {
"regex_uri": ["^/products/(\\d+)/(.*)$", "/api/products?id=$1§ion=$2"]
}
}
}
Convert GET to POST for a legacy backend:
{
"plugins": {
"proxy-rewrite": {
"method": "POST"
}
}
}
Replace the entire URI path:
{
"plugins": {
"proxy-rewrite": {
"uri": "/internal/health"
}
}
}
{
"plugins": {
"proxy-rewrite": {
"uri": "/api/$arg_version/resource"
}
}
}
{
"plugins": {
"proxy-rewrite": {
"regex_uri": ["^/v2/(.*)", "/v3/$1"],
"headers": {
"set": {
"X-API-Version": "v3"
}
}
}
}
}
| Symptom | Cause | Fix |
|---|---|---|
| URI not rewritten | Both uri and regex_uri set — uri wins | Remove uri if you need regex |
| Regex not matching | Bad pattern or unescaped characters | Test regex with PCRE syntax; escape backslashes in JSON: \\d+ |
| Nginx variable not resolved | Variable name typo or not available | Check Nginx variable list |
| 404 after rewrite | Rewritten URI doesn't match upstream paths | Verify the rewritten path exists on the backend |
| Host header unchanged | host field not set or overridden by upstream | Explicitly set host in proxy-rewrite config |
| Header appears twice | Used set vs add confusion | Use set to overwrite, add to append |