Security headers
Ferron can add, remove, and replace response headers. This is useful for baseline browser hardening, CORS handling, and hiding framework/server fingerprints.
Baseline hardening
example.com {
root /var/www/html
header "X-Content-Type-Options" "nosniff"
header "X-Frame-Options" "DENY"
header "Referrer-Policy" "strict-origin-when-cross-origin"
header "Permissions-Policy" "geolocation=(), microphone=(), camera=()"
header "Content-Security-Policy" "default-src 'self'; object-src 'none'; frame-ancestors 'none'"
header "Strict-Transport-Security" "max-age=31536000; includeSubDomains"
}Remove or replace unwanted headers
app.example.com {
proxy http://127.0.0.1:3000
# Remove or normalize headers from upstream responses.
header -X-Powered-By
header Server "Ferron"
}The header directive supports three forms:
header +Name "value"— add header (appends, allows duplicates)header -Name— remove all instances of the headerheader Name "value"— replace header (removes existing, sets new value)
Per-path policies
example.com {
root /var/www/html
location /admin {
header "Cache-Control" "no-store"
header "X-Frame-Options" "DENY"
}
}CORS configuration
For APIs that need cross-origin access, use the cors directive:
api.example.com {
proxy http://localhost:3000
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"
}
}To allow all origins (use with caution for public APIs):
api.example.com {
proxy http://localhost:3000
cors {
origins "*"
methods GET POST
headers "Content-Type" "Authorization"
max_age 3600
}
}Header interpolation
Header values support interpolation with {{...}} syntax:
example.com {
root /var/www/html
header +X-Client-IP "{{remote.ip}}"
header X-Powered-By "Ferron"
}Available variables include {{remote.ip}}, {{server.ip}}, {{request.host}}, and {{env.NAME}} for environment variables. For the complete reference, see Conditionals and variables.
Notes and troubleshooting
- Keep
Strict-Transport-Securityonly on HTTPS hosts you intend to keep on HTTPS permanently. - Treat
Content-Security-Policyas application-specific; start simple, then tighten based on real asset/script needs. - If a header appears multiple times, use
header -Nameto remove all instances, thenheader Name "value"to set a single value. - If CORS headers are not appearing, verify that
originsis configured — CORS is disabled by default iforiginsis empty. - For directive details, see Configuration: HTTP headers and CORS.