On this page

Documentation

This reference covers every flag and configuration key Ferrule supports. If it isn't listed here, it doesn't exist.

§1

Overview

Ferrule is one binary that does two things at once: it's a reverse proxy that terminates TLS for hostnames you make up (like api.local), and it's a process supervisor that can start and restart your services directly. Both are driven by a single ferrule.toml file that lives in your project.

You don't have to use both halves. A service can be proxy_to only (something you start yourself), command only (something Ferrule starts, with no HTTP host attached), or both — Ferrule starts the process and routes a hostname to it.

§2

Installation

Pick your platform. Every path ends with a single ferrule binary on your PATH.

shell
brew install ferrule-dev/tap/ferrule
ferrule trust   # installs the local CA into your Keychain
§3

Quick start

  1. Scaffold a config. Run this inside your project — it writes a ferrule.toml with one example service pointing at 127.0.0.1:3000.

    shell
    ferrule init
  2. Edit it. Add every service you run locally, following the configuration reference below.

  3. Trust the local CA, once per machine.

    shell
    ferrule trust
  4. Start everything.

    shell
    ferrule up
    output
    ferrule — 3 services, https on :443
    
      name     host          upstream            status      uptime
      web      app.local     127.0.0.1:5173      up          00:04:12
      api      api.local     127.0.0.1:4000      up (2xx)    00:04:12
      worker   —             node worker.js      up          00:04:09
    
      press q to quit · l to view logs · r to reload config
  5. Open https://app.local in a browser. No certificate warning.

§4

Configuration reference

One [server] table, and one [[service]] block per service.

[server]

KeyTypeDefaultDescription
bindstring"127.0.0.1"Address Ferrule listens on. Use "0.0.0.0" to reach it from another device on your LAN.
http_portinteger80Plain HTTP port; requests are redirected to HTTPS unless a service opts out.
https_portinteger443TLS port serving certificates from the local CA.
local_cabooleantrueGenerate and use a local certificate authority. Set false to serve plain HTTP only.
log_levelstring"info"One of trace, debug, info, warn, error.
log_formatstring"text""text" for the dashboard, or "json" for structured lines suitable for piping elsewhere.

[[service]]

KeyTypeDefaultDescription
namestringrequiredUnique identifier used by ferrule status and ferrule logs.
hoststringnoneHostname to route, e.g. "api.local". Omit for a supervised process with no HTTP endpoint.
proxy_tostringnone"ip:port" upstream. Required if host is set and command is not.
path_prefixstring"/"Route only requests under this prefix to this service — lets several services share one host.
commandstringnoneShell command Ferrule spawns and supervises. Can be combined with host + proxy_to.
workdirstring"."Working directory for command.
restartstring"never"One of never, on-failure, always.
backoffstring"1s..30s"Restart delay range; doubles on each consecutive failure up to the max.
health_checkstringnoneHTTP path polled every 2s once the port is open. Determines the "up (2xx)" status.
envtablenoneExtra environment variables passed to command.
§5

CLI reference

CommandDescription
ferrule initWrites a starter ferrule.toml in the current directory.
ferrule checkValidates the config and flags port conflicts without starting anything.
ferrule upStarts the proxy and every supervised process, with a live status dashboard in the terminal.
ferrule up -dSame, detached to the background. Writes a PID file to .ferrule/ferrule.pid.
ferrule statusPrints a one-shot table of every service's host, upstream, health and uptime.
ferrule logs <name> [-f]Prints, or follows with -f, the captured output of one supervised process.
ferrule reloadRe-reads ferrule.toml and issues certificates for any new hosts, without dropping connections.
ferrule trustInstalls the local CA root into the OS trust store. The only command needing elevated privileges.
ferrule doctorDiagnoses port conflicts, an expired local CA, stale PID files, and unresolvable hosts.
§6

Routing rules

Routing is host-first: Ferrule reads the Host header (or the TLS SNI, for HTTPS) and matches it against every configured host. Matching is exact — api.local does not also match www.api.local. If you need several, list several services.

Two services can share a host if their path_prefix values don't overlap. The longest matching prefix wins, so a more specific rule can sit alongside a catch-all:

ferrule.toml
[[service]]
name = "app-shell"
host = "app.local"
path_prefix = "/"
proxy_to = "127.0.0.1:5173"

[[service]]
name = "app-api"
host = "app.local"
path_prefix = "/api"
proxy_to = "127.0.0.1:4000"

Requests to app.local/api/orders go to app-api; everything else on app.local goes to app-shell.

§7

Local TLS

The first time ferrule up runs with local_ca = true, it generates a root key and certificate under ~/.config/ferrule/ca (Linux/macOS) or %APPDATA%\ferrule\ca (Windows) — never shared, never uploaded. ferrule trust adds that root to your OS trust store: Keychain on macOS, the NSS database and ca-certificates on Linux, the Windows Certificate Store on Windows.

From then on, Ferrule issues a short-lived leaf certificate for every configured host, valid 90 days and renewed automatically on ferrule reload. Because each machine has its own root, trusting your CA never lets you (or anyone) intercept another machine's traffic — teammates each run ferrule trust once, locally.

§8

Process supervision

A service with a command is started by Ferrule as a child process. Its fate is controlled by restart:

  • never — run once; if it exits, it stays stopped and shows as exited in the dashboard.
  • on-failure — restart only on a non-zero exit code or a failing health_check.
  • always — restart on any exit, including a clean one.

Restarts are spaced by backoff, a "min..max" range: the delay starts at min and doubles on each consecutive failure until it hits max, then holds there. A process that stabilizes resets the delay back to min.

If health_check is set, the service isn't marked up until that path returns a 2xx — useful for a Node or Rails process that opens its port before it's actually ready to serve.

§9

Observability

ferrule status prints the same table the dashboard shows, for scripting:

shell
$ ferrule status
name     host          upstream          status      uptime
web      app.local     127.0.0.1:5173    up          01:12:03
api      api.local     127.0.0.1:4000    up (2xx)    01:12:03
worker   —             node worker.js    restarting  00:00:04

The same data is available inside the browser at https://ferrule.local/status — a host Ferrule reserves for itself and answers on every machine it runs on. Set log_format = "json" in [server] to get structured, line-delimited logs instead of the human-readable default, suitable for piping into whatever you already use to read logs.

§10

Troubleshooting