Configuration: syntax and file structure
This page covers the Ferron configuration file format, how blocks and directives are structured, and how configuration is resolved at runtime.
Ferron configuration files
Ferron uses .conf files parsed by the config-ferronconf adapter. A configuration file is made of top-level statements that define global blocks, host blocks, matchers, and snippets.
# Uncomment to include additional configuration files
#include "/etc/ferron/conf.d/**/*.conf"
{
runtime {
io_uring
}
tcp {
listen "::"
}
}
match api_request {
request.uri.path ~ "/api"
request.method in "GET,POST"
}
snippet common_http {
http {
protocols h1 h2
}
}
example.com {
use common_http
tls {
provider manual
cert "{{env.TLS_CERT}}"
key "{{env.TLS_KEY}}"
}
}Top-level statements
A configuration file can contain the following at the top level:
- Global blocks —
{ ... }for server-wide settings - Host blocks —
<host-pattern> { ... }for virtual host configuration - Match blocks —
match <name> { ... }for reusable conditional matchers - Snippet blocks —
snippet <name> { ... }for reusable directive groups - Include directives —
include "path.conf"to load additional configuration files (globs are supported)
Value types
Ferron configuration supports these value types:
- Strings — bare (
example.com) or quoted ("example.com") - Integers —
80,443,1000 - Floats —
3.14 - Booleans —
true,false - Interpolated strings —
{{env.TLS_CERT}}reads from environment variables - Duration strings —
30m,1h,90s,1d
Flags (boolean directives)
Several directives accept boolean values. For convenience, these can be written as flags with no arguments, which is equivalent to true:
# This is a bare flag, equivalent to setting the value to true:
directory_listing
# To explicitly disable, use false:
directory_listing falseThis shorthand can useful for simple on/off toggles where the intent is clear.
Duration strings
Several directives accept duration values. The following formats are supported:
| Suffix | Unit | Example | Result |
|---|---|---|---|
h or H | Hours | 12h, 1H | 12 hours |
m or M | Minutes | 30m, 30M | 30 minutes |
s or S | Seconds | 90s, 90S | 90 seconds |
d or D | Days | 1d, 1D | 1 day |
| (none) | Seconds (default) | 12 | 12 seconds |
Plain numbers without a suffix are treated as seconds.
Raw string literals
For values that contain regex patterns or other content where escape processing is undesirable, use raw string literals (r"..." or r'...'). Raw strings process no escape sequences — backslashes are treated literally:
match api_request {
request.uri.path ~ r"^/api/v1(?:/|$)"
}Without raw strings, the same regex would require escaping backslashes:
match api_request {
request.uri.path ~ "^/api/v1(?:/|$)"
}Invalid escape sequences in quoted strings (e.g., \z, \$) are now parse errors. Use raw strings (r"...") if you need literal backslashes in values like regex patterns.
Raw strings do not support interpolation ({{...}}). Use regular strings if variable substitution is needed.
Line continuations
Long directives can be split across multiple lines using \ at the end of the line. The continuation must be indented:
example.com {
# This is just an example directive
example_proxy http://localhost:3000 \
http://localhost:3001
}Line continuations can include trailing comments:
example.com {
# This is just an example directive
example_proxy http://localhost:3000 \ # first backend
http://localhost:3001
}Comments
Comments start with #.
Host block syntax
Host blocks are top-level only. Supported selectors include:
example.com— hostname-based virtual host*.example.com— wildcard hostname127.0.0.1— IP-based virtual host[2001:db8::1]— IPv6 addresshttp example.com— explicit protocolhttp example.com:8080— explicit protocol and porttcp *:5432— TCP listener
Current defaults:
- If the protocol is omitted, it defaults to
http. - For HTTP host blocks, if the port is omitted, Ferron treats it as port
80.
When a hostname is specified (e.g. example.com) and no explicit port is given, Ferron starts two listeners — one on the default HTTP port (80) and one on the default HTTPS port (443) with automatic ACME TLS. See ACME automatic TLS for details.
Includes and snippets
include "path.conf"at the top level loads another config file relative to the current file.snippet <name> { ... }defines a reusable block of directives.use <snippet-name>inside a block expands that snippet in place.
- Top-level file includes and snippet expansion are different features.
- Include cycles and snippet cycles are rejected.
- Snippets can be reused across multiple host blocks.
Resolution model
Configuration is resolved in layers:
- Global configuration from
{ ... }is used for startup and runtime settings. - An HTTP host block is selected by local IP and hostname.
- Matching
locationblocks are layered in. - Matching
ifandif_notblocks are layered in.
locationis prefix-based./apimatches/apiand/api/users.- More specific locations win over less specific ones.
- All expressions inside a
matchblock are combined with AND semantics. - Duplicate
location,if,if_not, andhandle_errorblocks with the same selector are merged during preparation.
Inheritance and override behavior
Ferron applies inheritance by block context:
- Location blocks inherit parent directives unless the child block defines directives with the same name.
- When a child block defines a directive with the same name as one in the parent, the child’s directives take precedence in that block.
- For conditional branches, it is often clearer to explicitly
useshared snippets inside eachif/if_notbranch.
Where validation and runtime behavior differ, the directive pages call that out explicitly.
Duration strings accept suffixes like 30m, 1h, 90s, 1d — plain numbers without a suffix are treated as seconds. Boolean directives are written as bare flags (equivalent to true), or explicitly as false when disabling.
Hot-reload support
Ferron .conf configuration files support hot-reload. When the file changes, Ferron detects the update and reloads the configuration gracefully. The ConfigurationWatcher monitors the file for modifications.
To enable hot reloading, specify a watch configuration adapter parameter:
ferron run --config-params 'watch=1;file=ferron.conf' --config-adapter ferronconfSee also
- Conditionals and variables
- Configuration formatting —
ferron-fmtfor formatting.conffiles - Routing and URL processing (
location,if,if_not) - Core directives