Configuration validation
This page covers the ferron validate command, the types of diagnostics it produces, and how to interpret validation output.
The validate command
The validate command checks your configuration file for errors and unknown directives without starting the server.
ferron validate -c ferron.confIf the configuration is valid, the command exits with code 0. If there are errors, it exits with code 1.
Validation is module-aware: a directive recognized by a loaded module is valid; an unrecognized one is flagged as unknown. Validation does not guarantee runtime correctness — some issues can only be detected at runtime.
Log output
By default, validation prints diagnostics as log messages:
*:443 {
tlss
}$ ferron validate -c ferron.conf
[2026-05-30 07:18:34.372 WARN] Unknown directive (block 'http port 443' in file '/home/.../ferron.conf' at line 1, column 7): `tlss` is unused in the blockThe configuration above is still structurally valid — tlss is an unrecognized directive, but it does not prevent the server from starting. Validation exits with code 0 in this case.
JSON output
Use the --json (or -j) flag to get machine-readable output:
ferron validate -c ferron.conf --json{
"valid": true,
"diagnostics": [
{
"kind": "Unknown directive",
"message": "`tlss` is unused in the block",
"span": {
"line": 1,
"column": 7,
"file": "/home/.../ferron.conf"
},
"scope": "http port 443"
}
]
}Response structure
The JSON response contains two top-level fields:
| Field | Type | Description |
|---|---|---|
valid | bool | Whether the configuration is valid. false only when invalid directives are found. |
diagnostics | Vec<Diagnostic> | List of diagnostic messages, warnings, and errors. |
Diagnostic fields
Each diagnostic entry contains:
| Field | Type | Description |
|---|---|---|
kind | string | The diagnostic category — "Unknown directive", "Invalid configuration", or "Best practice violation". |
message | string | A human-readable description of the issue. |
span | Span | null | Source location (line, column, file) where the issue occurred. |
scope | string | null | The configuration block scope (e.g., "http port 443", "global"). |
Diagnostic kinds
Unknown directive
A directive in the configuration is not recognized by any loaded module. This is reported as a warning — the server can still start.
example.com {
non_existent_directive true
}{
"valid": true,
"diagnostics": [
{
"kind": "Unknown directive",
"message": "`non_existent_directive` is unused in the block",
"span": { "line": 2, "column": 3, "file": "ferron.conf" },
"scope": "http example.com"
}
]
}Invalid configuration
A recognized directive has invalid arguments or a misconfigured value. This is an error — validation fails and the server cannot start with this configuration.
# INVALID: bogus TLS provider
example.com {
tls {
provider bogus
}
}{
"valid": false,
"diagnostics": [
{
"kind": "Invalid configuration",
"message": "unknown tls provider: `bogus`",
"span": { "line": 3, "column": 5, "file": "ferron.conf" },
"scope": "http example.com"
}
]
}When valid is false, the command exits with code 1.
Best practice violation
A configuration pattern is technically valid but deviates from recommended practices. This is an advisory diagnostic — ferron validate suppresses it, and ferron doctor reports it. The server can start with these patterns.
example.com {
directory_listing
}{
"valid": true,
"diagnostics": [
{
"kind": "Best practice violation",
"message": "`directory_listing` exposes generated indexes for directories without index files; enable it only for intentionally public file listings",
"span": { "line": 2, "column": 5, "file": "ferron.conf" },
"scope": "http example.com"
}
]
}Span metadata
The span field pinpoints the exact location of the diagnostic in the configuration file:
| Field | Type | Description |
|---|---|---|
line | usize | Line number, 1-indexed. |
column | usize | Column number, 1-indexed. |
file | string | null | Absolute path to the configuration file, or null if constructed programmatically. |
Validation scope
Validation runs against two levels:
- Global configuration — directives inside the top-level
{ ... }block - Per-protocol blocks — host blocks such as
example.com,*:443,http *:8080
Each protocol registers its own validators via the module system. If a module is not loaded (e.g., a custom build with a reduced feature set), its directives will not be recognized and will show as unknown.
Configuration adapters and validation
The validate command works with any configuration adapter. The adapter is auto-detected from the file extension:
ferron validate -c ferron.conf # uses config-ferronconf adapter
ferron validate -c config.json # uses config-json adapterYou can also specify an adapter explicitly:
ferron validate -c config.json --config-adapter jsonValidation runs after the adapter has loaded and parsed the configuration. If the configuration file cannot be parsed, validation reports the parse error directly.
Related commands
ferron doctor
The doctor command extends validation with best-practice checks for security, reliability, and operational hygiene. It reports advisory diagnostics for patterns that are technically valid but deviate from recommended practices:
ferron doctor -c ferron.confSee Configuration doctor for the full list of checks.
ferron adapt
The adapt command outputs the parsed configuration as JSON without running validators. This is useful for inspecting how Ferron interprets your configuration:
ferron adapt -c ferron.confThe JSON output format is stable and suitable for programmatic consumption by tools and CI pipelines.
See JSON configuration and adapt command for details.
ferron run
The run command performs the same validation during startup. If validation fails, the server exits with an error.
Unknown directives produce warnings, not errors — the server can start, but the directive is silently ignored. Invalid configurations produce errors — the server will not start.