Skip to content

Header Rewrite

Header rewrite rules add, remove or change HTTP headers on requests (before they are sent to the server) or on responses (before they reach the app).

  • Every matching header rule runs, in order: your local rules first, then modules from the top of the list down.
  • Rules match against the original URL the app requested (see How URLs are matched). Response rules are chosen when the request is seen, using the same URL.
  • Request header rewrites run first, before URL rewrite and Map Local. Response header rewrites run before body rewrites and response scripts.
  • Header names are compared case-insensitively.
  • For decrypted hosts, MeowX also removes the Alt-Svc response header so that apps aren’t steered to HTTP/3 (QUIC), which can’t be decrypted.
Operation Effect
header-add Name value Always appends a new Name field, even if one exists.
header-del Name Removes every Name field.
header-replace Name value Replaces the value of every existing Name field. Adds nothing if the header isn’t present.
header-replace-regex Name regex replacement Applies a regex replacement to the value of every existing Name field. $1 … refer to capture groups.
[Header Rewrite]
# [http-request|http-response] regex operation name [value]
http-request ^https:\/\/api\.example\.com\/ header-add X-Debug 1
http-request ^https:\/\/api\.example\.com\/ header-del Cookie
http-response ^https:\/\/api\.example\.com\/ header-replace Cache-Control no-store
http-request ^https:\/\/api\.example\.com\/ header-replace-regex User-Agent iPhone iPad
  • The direction is http-request or http-response. If it is omitted (the older syntax), http-request is assumed.
  • The value is the rest of the line and may contain spaces. A value wrapped in double quotes has the quotes removed.
[Rewrite]
^https:\/\/api\.example\.com\/ header-add X-Debug 1 X-Client meowx
^https:\/\/api\.example\.com\/ response-header-del Set-Cookie
^https:\/\/api\.example\.com\/ header-replace User-Agent My\x20Client
Request Response Arguments
header-add response-header-add name, value
header-del response-header-del name
header-replace response-header-replace name, value
header-replace-regex response-header-replace-regex name, regex, replacement

One line can change several headers: the arguments are taken in groups (header-add A 1 B 2 adds two headers), and each group becomes its own rule. If one group touches Content-Length or Transfer-Encoding, only that group is rejected. Write spaces inside arguments as \x20.

[Rewrite]
request if ${url} ~= /^https:\/\/api\.example\.com\// then request.header.add("X-Debug", "1")
response if ${url} ~= /^https:\/\/api\.example\.com\// then response.header.delete("Set-Cookie")
request if ${url} ~= /^https:\/\/api\.example\.com\//i then request.header.replace("User-Agent", "MyClient")

Supported: request.header.add(name, value), request.header.replace(name, value), request.header.delete(name) (also .del), and the same with response.. Only the ${url} ~= /…/ condition is supported; see URL rewrite.

Over HTTP/2, header names are sent in lowercase. If a rewrite produces a header that isn’t valid in HTTP/2 (an invalid name, a value containing line breaks or NUL, a connection-specific header such as Connection, or TE with a value other than trailers), that field is dropped.