Configuration: HTTP headers and CORS
This page documents the header and cors directives for configuring response header manipulation and Cross-Origin Resource Sharing (CORS) handling.
Directives
header
The header directive manipulates response headers before sending to the client. Three forms are supported:
| Syntax | Effect |
|---|---|
header +Name "value" | Add header (appends, allows duplicates) |
header -Name | Remove all instances of the header |
header Name "value" | Replace header (removes existing, sets new value) |
Header values support interpolation with {{...}} syntax.
Configuration example:
example.com {
header +X-Client-IP "{{remote.ip}}"
header X-Powered-By "Ferron"
header -Server
}Interpolation variables
| Variable | Description |
|---|---|
{{remote.ip}} | The client’s IP address |
{{remote.port}} | The client’s port |
{{server.ip}} | The server’s listening IP address |
{{server.port}} | The server’s listening port |
{{request.host}} | The matched hostname |
{{request.scheme}} | http or https |
{{env.NAME}} | Environment variable NAME |
For the complete variable reference, see Conditionals and variables.
Unresolved variables are left as {{name}} in the output.
cors
The cors directive configures Cross-Origin Resource Sharing behavior.
example.com {
cors {
origins "https://example.com" "https://app.example.com"
methods GET POST PUT DELETE
headers "Content-Type" "Authorization"
credentials true
max_age 86400
expose_headers "X-Custom-Header"
}
}| Nested directive | Arguments | Description | Default |
|---|---|---|---|
origins | <string>... | Allowed origins. Use "*" to allow all. | none (CORS disabled) |
methods | <string>... | Allowed HTTP methods for preflight. | none |
headers | <string>... | Allowed request headers for preflight. | none |
credentials | <bool> | Allow credentials (cookies, auth headers). | false |
max_age | <number> | Preflight cache duration in seconds. | none |
expose_headers | <string>... | Headers exposed to the browser in responses. | none |
Behavior
-
Preflight handling: When an
OPTIONSrequest includesOriginandAccess-Control-Request-Methodheaders, the module returns204 No Contentwith the appropriate CORS response headers. -
Response headers: For all responses (including error responses), CORS headers are added when enabled, including
Access-Control-Allow-Origin,Access-Control-Allow-Credentials,Access-Control-Allow-Methods,Access-Control-Allow-Headers,Access-Control-Max-Age,Access-Control-Expose-Headers, andVary: Origin.
Origin matching
- If
originscontains"*", any origin is allowed andAccess-Control-Allow-Originis set to*. - Otherwise, the incoming
Originheader is compared against the list. If it matches, the header is echoed back. If it doesn’t match, no CORS headers are added.
Configuration example — allow all origins:
api.example.com {
cors {
origins "*"
methods GET POST
headers "Content-Type" "Authorization"
credentials false
max_age 3600
}
}Configuration example — specific origins with credentials:
api.example.com {
cors {
origins "https://app.example.com" "https://admin.example.com"
methods GET POST PUT DELETE OPTIONS
headers "Content-Type" "Authorization" "X-Request-ID"
credentials true
max_age 86400
expose_headers "X-Total-Count" "X-Page"
}
}Notes and troubleshooting
- If CORS headers are not appearing in responses, verify that
originsis configured (CORS is disabled by default iforiginsis empty). - For header interpolation,
remote.ipandserver.ipautomatically canonicalize IPv4-mapped IPv6 addresses to IPv4. See Conditionals and variables for details. - For HTTP host directives, see HTTP host directives.