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

The header directive manipulates response headers before sending to the client. Three forms are supported:

SyntaxEffect
header +Name "value"Add header (appends, allows duplicates)
header -NameRemove 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

VariableDescription
{{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 directiveArgumentsDescriptionDefault
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

  1. Preflight handling: When an OPTIONS request includes Origin and Access-Control-Request-Method headers, the module returns 204 No Content with the appropriate CORS response headers.

  2. 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, and Vary: Origin.

Origin matching

  • If origins contains "*", any origin is allowed and Access-Control-Allow-Origin is set to *.
  • Otherwise, the incoming Origin header 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 origins is configured (CORS is disabled by default if origins is empty).
  • For header interpolation, remote.ip and server.ip automatically canonicalize IPv4-mapped IPv6 addresses to IPv4. See Conditionals and variables for details.
  • For HTTP host directives, see HTTP host directives.