ecaddy Docs Commands

Commands

Every ecaddy subcommand and its flags. Commands that touch a project use a site name — a short identifier you supply with --site NAME (or -s NAME). The name determines the fragment filename and is how up, down, edit, and remove target the project.

ecaddy setup

One-time machine bootstrap. Install Caddy, scaffold the global config, trust the local CA, start the brew service.

ecaddy setup

Every step is idempotent — safe to re-run if a prior step failed or you've reinstalled Homebrew. See Getting Started › Step 2 for the per-step breakdown.

ecaddy run

Register a project Caddyfile, block, and unregister on shutdown. The Procfile-friendly variant — pair it with foreman, overmind, or bin/dev.

ecaddy run --config ./Caddyfile --site fishme
ecaddy run -c ./Caddyfile -s fishme

Flags

FlagRequiredDescription
--config, -c PATHyesPath to the project's source Caddyfile
--site, -s NAMEyesSite identifier (fragment filename, registry key)

Lifecycle

  1. Validate that --config exists.
  2. Run conflict detection against the registry — BLOCK on shared domain or port.
  3. Rewrite relative output file log paths to absolute paths (resolved from the directory of --config).
  4. Write the result to ~/.config/caddy/sites/<name>.caddy.
  5. Upsert the registry entry.
  6. Validate the global config with caddy validate and reload Caddy.
  7. Block on a signal trap.
  8. On SIGTERM / SIGINT: delete the fragment, reload Caddy, exit 0.
Why log paths are rewritten Your Caddyfile lives at /projects/fishme/Caddyfile; Caddy runs from brew services and has no relation to that directory. output file log/caddy.log would write somewhere unpredictable. ecaddy rewrites it to /projects/fishme/log/caddy.log before the fragment is installed.

ecaddy ensure

One-shot variant of run. Copy the Caddyfile, reload Caddy, exit immediately. The site stays registered across reboots until you run ecaddy down or ecaddy remove.

ecaddy ensure --config ./Caddyfile --site fishme

Use this in CI, shell scripts, or any setup where you want Caddy configured but don't need a foreground process tied to a dev loop.

ecaddy list

Show all registered sites in a table.

ecaddy list
ecaddy list --format json
┌─────────┬────────┬────────────────────────────────────────────┬────────────┬──────────────────────────┐
│ Name     │ Status │ Domains                                      │ Ports      │ Source                   │
├─────────┼────────┼────────────────────────────────────────────┼────────────┼──────────────────────────┤
│ fishme   │ up     │ fishme.localhost, vite.fishme.localhost      │ 3054, 3104 │ /projects/fishme/Caddyfile │
│ letly    │ down   │ letly.localhost, vite.letly.localhost        │ 3050, 3100 │ /projects/letly/Caddyfile  │
└─────────┴────────┴────────────────────────────────────────────┴────────────┴──────────────────────────┘

--format json emits a machine-readable list suitable for piping to jq.

ecaddy up NAME / ecaddy down NAME

Enable or disable a registered site without removing it. The fragment is moved between sites/ and disabled/ via Pathname#rename (atomic), the registry's enabled flag is flipped, and Caddy is reloaded.

ecaddy down fishme   # sites/fishme.caddy → disabled/fishme.caddy, reload
ecaddy up   fishme   # disabled/fishme.caddy → sites/fishme.caddy, reload

Disabled fragments are preserved — their content stays on disk so re-enabling is instant.

ecaddy status

Show global Caddy state and per-site health (whether the upstream app is actually listening).

ecaddy status
  Caddy service: running
  Config:        /Users/you/.config/caddy/Caddyfile

  fishme               up
    fragment: /Users/you/.config/caddy/sites/fishme.caddy
    source:   /projects/fishme/Caddyfile
  letly                up (app not running)
    fragment: /Users/you/.config/caddy/sites/letly.caddy
    source:   /projects/letly/Caddyfile

ecaddy doctor

Scan all registered sites cross-wise for port and domain conflicts, plus TCP-probe each upstream port.

ecaddy doctor

Exits 0 if all clear or only INFO findings. Exits 1 on any BLOCK.

SeverityMeaning
BLOCKTwo sites share a port or domain — one will fail to bind
WARNA port is bound by an unexpected process (not the registered upstream)
INFOUpstream not listening (the project's app simply isn't running)

ecaddy audit

Full system + TLS audit with optional --fix prompts. Where doctor looks at the registry, audit also probes the live Caddy service, brew-service state, TLS handshakes per domain, and the system-keychain trust state.

ecaddy audit                # report-only
ecaddy audit --fix          # prompt to run each suggested fix
ecaddy audit --site fishme  # limit to one site

The --fix mode walks each collected finding, prints the proposed command, asks for confirmation, runs it, and re-verifies. If the primary fix doesn't resolve the finding, audit chains to a next_fix (e.g. caddy trustsudo caddy trust).

ecaddy edit NAME

Open a site's installed fragment in $EDITOR. Caddy is validated and reloaded after you save and exit the editor.

ecaddy edit fishme
This edits the copy, not your source ecaddy edit opens ~/.config/caddy/sites/fishme.caddy — the installed fragment, not your project's Caddyfile. Re-running ecaddy run (or ecaddy ensure) will overwrite your edits with the project source. Use this for quick experiments; for lasting changes edit the project Caddyfile and re-register.

ecaddy logs --site NAME

Tail the project's Caddy log files. ecaddy reads the fragment, extracts every output file PATH directive, and shells out to tail on them.

ecaddy logs --site fishme           # tail -F (follow)
ecaddy logs --site fishme --lines 100   # tail -n 100, no follow

If the Caddyfile has no output file directives, ecaddy prints guidance and exits. Works for both enabled and disabled sites.

ecaddy remove NAME

Delete a site's fragment and registry entry entirely.

ecaddy remove fishme
ecaddy remove fishme --force   # skip the confirmation prompt

ecaddy reload

Validate the global config with caddy validate and reload Caddy without restarting it. Equivalent to what run / ensure / up / down do internally after each change.

ecaddy reload

ecaddy version

ecaddy version
# ecaddy 0.1.0

A note on the run command

run is a Thor reserved method name. Internally the method is caddy_run, exposed as run via map 'run' => :caddy_run in cli.rb. This is irrelevant from the CLI side — ecaddy run works as expected — but worth knowing if you crack open the source.

ecaddy v0.1.0 · MIT License · GitHub