Troubleshooting
When something goes wrong with Ferron or your website, start here. The goal is to quickly isolate whether the issue is service state, networking, TLS, routing, permissions, or configuration logic.
Quick diagnostic checklist
- Check the logs.
- Confirm Ferron is running.
- Test upstream directly (if you are reverse proxying).
- Confirm port and firewall.
- Restart Ferron after config changes.
First checks
Is Ferron running?
Check service status first (commands are given for common installation methods).
- Linux (systemd) -
sudo systemctl status ferron - Windows Server -
sc query ferron - Docker -
docker ps(anddocker logs <container>)
If Ferron is not running, restart it and re-check logs right away.
- Linux -
sudo systemctl restart ferron - Windows Server -
net stop ferron && net start ferron
Is the port correct?
- Standard Ferron config typically serves on ports
80and443. ferron servedefaults to port3000.
If you are testing the wrong port, the server can be healthy but still appear down.
Relevant directives: default_http_port, default_https_port, listen_ip. See Configuration: core directives.
Is the firewall open?
Ensure inbound traffic is allowed for the ports you use (usually 80 and 443).
- Local host firewall
- Cloud/VPS security groups
- Any external reverse proxy/load balancer policy
Are logs enabled?
Use at least one access log output and one error log output.
- File logs -
log,error_log - Container-friendly streams -
log_stdout,error_log_stderr - Common package paths -
/var/log/ferron/access.log,/var/log/ferron/error.log(Linux packages) and%SystemDrive%\ferron\log\access.log,%SystemDrive%\ferron\log\error.log(Windows installer)
See Logging & observability and Configuration: observability & logging.
What does the log say?
Read the newest error lines first, then reproduce the request once and read again.
Common meanings:
connection refused- target process is not listening on that host/port/socket.- timeout errors - target is unreachable, blocked, overloaded, or too slow.
- TLS verification/certificate errors - upstream cert or trust chain problem.
permission denied/ file open errors - filesystem ownership/mode issue.
Reverse proxy issues
Can you reach the upstream directly?
From the same host where Ferron runs, test the upstream URL/socket directly.
If direct access fails, fix the upstream first; Ferron cannot proxy to an unreachable backend.
Is the upstream bound to 127.0.0.1 instead of 0.0.0.0?
If Ferron and upstream are in different hosts/containers/namespaces, upstream binding to 127.0.0.1 can make it unreachable externally. Bind to 0.0.0.0 (or the correct interface) when needed.
Is TLS verification failing?
For HTTPS upstreams with private/self-signed certs:
- Prefer fixing trust (install proper CA chain) rather than disabling verification.
proxy_no_verificationcan help confirm diagnosis, but keep it disabled in production unless you fully understand the risk.
Timeout vs connection refused?
connection refused- wrong port/host, or service down.- timeout - route/firewall/DNS issue, or upstream accepted but did not respond in time.
See Reverse proxying and Configuration: reverse proxying.
TLS issues
Certificate not matching hostname
Ensure the requested hostname matches the certificate SAN/CN and the correct Ferron host block.
Missing DNS records
For automatic TLS, DNS must point the hostname to the Ferron server.
Port 80/443 blocked
ACME validation can fail when these ports are blocked by firewall, cloud policy, or proxy path.
ACME challenge failing
- Use Let’s Encrypt staging first -
auto_tls_letsencrypt_production #false - If behind an HTTPS-terminating proxy, use
auto_tls_challenge "http-01"(or"dns-01") - Use
"dns-01"for wildcard certificates - Keep
auto_tls_cacheon persistent storage
Could this be bot or scanner traffic?
On public servers, some TLS and HTTP errors are just background Internet scanning noise.
- Requests like
/wp-login.php,/.env, or/phpmyadminare common bot probes against non-WordPress/non-PHP sites. - Some TLS handshake failures happen before HTTP request parsing, so they may appear in error logs without a matching access-log line.
- If legitimate traffic works and failures come from random IPs/paths, this is often not a Ferron misconfiguration.
If noise is high, reduce impact with targeted controls:
- Add route-specific
limitrules for sensitive endpoints. - Use
allow/blockrules where appropriate. - Keep authentication and admin paths narrow and explicit.
See Automatic TLS and Configuration: security & TLS.
Static file issues
Incorrect root path
Verify root points to the directory containing deployed files for that host/location.
Permissions
Ferron must be able to read files and traverse directories (x on directories for Unix and Unix-like systems).
Path rewriting confusion
For SPAs, route fallback rewrites are commonly required. If rewrites are involved, enable rewrite_log while diagnosing.
See Static file serving, URL rewriting, and Configuration: routing & URL processing.
Rate limiting and access control
Is a condition blocking traffic?
Check status rules (allowed, not_allowed), allow/block, and conditional logic (condition, if, if_not).
Is client IP detection correct?
If Ferron is behind a proxy/load balancer and IP handling is wrong, access-control and rate-limit behavior can be wrong too.
Is trust_x_forwarded_for configured?
Set trust_x_forwarded_for only when behind a trusted proxy path that sets X-Forwarded-For. For PROXY protocol frontends, use protocol_proxy.
See Client IP, Rate limiting, Access control, and Configuration: conditionals.
Configuration mistakes
Wrong nesting
KDL block placement matters. A directive in the wrong block can look valid but not apply where expected.
Missing directive
Common examples:
- Using
rootwhen you intendedproxy - Missing
fcgi_php(orcgi+cgi_extension) for PHP - Missing
locationsplit between static files and API
Unexpected conditional behavior
All subconditions in one condition block must pass. If one fails, the condition fails.
Quick isolation method
Start with a minimal known-good config, confirm it works, then add one change at a time.
See Getting started, Configuration: fundamentals, and Configuration: examples.
Observability & logs
How to enable debug logging
Ferron does not use a single global “debug mode” directive. For troubleshooting visibility:
- Ensure
error_log(orerror_log_stderr) is enabled - Ensure access logs are enabled (
log,log_stdout, orlog_stderr) - Enable
rewrite_logtemporarily when debugging rewrite behavior - Optionally export logs/metrics/traces via OTLP
How to read logs effectively
- Reproduce one request at a time.
- Match request path/status in access logs with timestamps in error logs.
- Check whether failure happened before upstream, during upstream connection, or in local file/routing logic.
How to read Combined Log Format access lines (default)
Ferron’s default access-log format is:
{client_ip} - {auth_user} [{timestamp}] "{method} {path_and_query} {version}" {status_code} {content_length} "{header:Referer}" "{header:User-Agent}"
This matches the default log_format directive in Configuration: observability & logging.
Example line:
::ffff:203.0.113.42 - - [19/Feb/2026:14:26:11 +0000] "GET /api/health HTTP/1.1" 200 27 "-" "curl/8.5.0"
Field breakdown:
::ffff:203.0.113.42- client IP (client_ip)- first
-- RFC 1413 identity placeholder (unused) - second
-- authenticated user (auth_user),-when not authenticated [19/Feb/2026:14:26:11 +0000]- request timestamp (timestamp)"GET /api/health HTTP/1.1"- method, path+query, and protocol version200- response status code27- response content length in bytes"-"-Refererheader (missing in this example)"curl/8.5.0"-User-Agentheader
Quick reading heuristics:
- Focus on status code first (
2xxsuccess,3xxredirects,4xxclient-side/request-side,5xxserver/upstream-side). - Repeated
4xxon unrelated paths from many IPs usually indicates bot scanning. - Bursts of
502/504for valid routes usually indicate upstream/backhaul problems. - Correlate the same timestamp window in error logs for root cause details.
How to interpret common errors
404 Not Found- often wrongroot, wrong path rewrite, or backend route mismatch.403 Forbidden- often access-control rule or filesystem permissions.502 Bad Gateway- upstream connection/handshake failure.504 Gateway Timeout- upstream reachable but too slow/unresponsive.
Still stuck?
- Use support options for troubleshooting help.
- If you suspect a Ferron bug, open an issue on GitHub.
When asking for help, include Ferron version (ferron --version), your deployment type, a minimal config snippet, and the relevant error-log lines.