v0.7.1 · updated · GitHub

All commands

This page explains what every command does, what it reads or changes, and which mode to choose. Use caddy-analyze <command> --help for the exact flags installed in your binary. The complete flag section separates persistent flags, root-only modes and command-specific options.

Choose a command

GoalCommandEffect
Summarize one or more logscaddy-analyze SOURCE...Read-only report
Find suspicious requestscaddy-analyze --detect SOURCE...Read-only threat report
Watch new entriestail or --followRead-only stream/report
See rankingstopRead-only aggregation
Compare two periodsdiffRead-only comparison
Store a reference periodbaseline saveWrites JSON
Automatically block attackersguardMay change firewall rules
Block or unblock manuallyblock / unbanChanges firewall rules
Manage threat-intel feedsblocklistWrites cache/config, not firewall
Manage defaultsconfigWrites configuration
Maintain protected IPswhitelistWrites allowlist
Export detection rulesexport-sigmaWrites YAML or stdout
Install a releaseupdateReplaces the binary

Analyze: the root command

caddy-analyze [flags] [source...]
caddy-analyze --detect --format json access.log
caddy-analyze --from 1h --5xx /var/log/caddy/*.log

With no subcommand, the tool parses Caddy JSON access logs and operational events, applies filters, aggregates metrics, and prints a table report. Sources can be local files or globs, - for stdin, docker://container, k8s://pod, or journalctl://unit. If no source is supplied, the configured default source is used.

--detect enables the dual-pass security engine and adds suspicious IPs, categories, confidence and evidence to the report. It does not block anything. Use --format json for automation, --format csv for spreadsheets, and --format html -o report.html for sharing. Filtering flags such as --ip, --path, --slow and --5xx are combined as AND conditions; --status, country and ASN lists match any value in their list.

Use --follow for periodic reports, --interval 5m for windowed aggregation, or --watch for the interactive dashboard. These root-only modes cannot be combined with each other where the CLI reports them as mutually exclusive.

# Pipe logs and produce machine-readable output
cat access.log | caddy-analyze --detect --format json -

# Inspect only slow server errors from a time window
caddy-analyze --from 2h --5xx --slow 500ms access.log

# Send analyzed documents to Loki or Elasticsearch-compatible storage
caddy-analyze --format loki --remote-url https://logs.example/api/prom/push access.log

tail

caddy-analyze tail [source...] [--detect]

Streams entries as they arrive and colorizes status, method, path, latency and client IP. It is the interactive choice for troubleshooting a live service. --detect highlights matching requests inline; it does not modify the firewall. Filters still apply, so a filtered-out entry is not printed.

caddy-analyze tail docker://caddy --detect --5xx
caddy-analyze tail --grep '/admin|wp-login' /var/log/caddy/access.log

top

caddy-analyze top [dimension] [source...] [flags]

Computes only a ranked view instead of a full report. Dimensions are path, ip, ua, status, method, host, bandwidth, country, city and asn. The dimension may be positional or supplied with --by; path is the default. Use -t 0 to disable the top list, and use normal filters to limit the population before ranking.

caddy-analyze top ip access.log -t 20
caddy-analyze top bandwidth access.log --from 24h
caddy-analyze top --by status --5xx access.log
caddy-analyze top country --geoip-db GeoLite2-Country.mmdb access.log

diff

caddy-analyze diff <baseline_log> <target_log> [flags]

Compares two local log files and reports changes in request rate, status errors and latency. The first file is the reference period and the second is the period under investigation. It does not require or create a saved baseline. Use --format json or --output for CI and scheduled checks.

caddy-analyze diff yesterday.log today.log
caddy-analyze diff before.log after.log --format json -o regression.json

baseline save

caddy-analyze baseline save <source...> -o baseline.json [--detect]

Parses a source and stores a versioned JSON snapshot of aggregate metrics. This is useful for keeping a known-good deployment reference. It writes the file specified by --output; use filters to ensure the baseline and later comparisons cover the same population. --detect includes detection statistics. Saving a baseline does not block IPs.

caddy-analyze baseline save access.log --from 7d -o baseline.json --detect
caddy-analyze --against baseline.json access.log --threshold 15

guard

sudo caddy-analyze guard [source] [flags]

Continuously monitors a source and automatically blocks IPs that cross request, authentication, not-found or detection thresholds. Depending on --firewall-backend, it can modify iptables, nftables, Docker's DOCKER-USER chain, or a hybrid of them. Blocks can be persisted in the state file and every action can be audited.

Firewall safety
Protect the administrator IP with --never-block or --never-block-file before running on a remote host. Use --dry-run first. Normal mode needs root; dry-run does not change firewall or state.
sudo caddy-analyze guard /var/log/caddy/access.log --dry-run
sudo caddy-analyze guard docker://caddy --never-block 203.0.113.10 \
  --firewall-backend hybrid --state-file /var/lib/caddy-analyzer/blocked.json

--country-block blocks matching countries immediately when GeoIP is available. Blocklist feeds are enabled by default and can be disabled with --no-blocklist. Audit notifications support JSONL, syslog and generic, Slack, Discord or PagerDuty webhooks. See the dedicated guard reference for all thresholds and sinks.

block and unban

sudo caddy-analyze block <ip> [ip...]
sudo caddy-analyze unban <ip> [ip...] | --all | --list

block adds one or more addresses to the firewall and, unless disabled, synchronizes the guard state file. unban removes selected addresses; --list only displays current state and --all removes every tracked block. Configure the same state file and audit sinks used by guard when these commands are part of an incident workflow.

sudo caddy-analyze block 198.51.100.7 --webhook-url https://hooks.example/...
sudo caddy-analyze unban --list
sudo caddy-analyze unban 198.51.100.7

blocklist

caddy-analyze blocklist refresh|list|config|init [flags]

Downloads and parses threat-intelligence feeds used by guard. refresh updates the cache, list shows active feeds and counts, config prints effective configuration, and init persists CLI settings. These operations do not install firewall rules.

caddy-analyze blocklist refresh
caddy-analyze blocklist list -f json
caddy-analyze blocklist --blocklist-config custom.json \
  --no-default-blocklists init

Use --cache-dir for a service-owned cache. Custom JSON sources use name, url and format; validate access and format before enabling them in guard.

config

caddy-analyze config [show|set|reset|source] [--global]

Sets the default source used when the root command has no positional source. Without --global, configuration is stored in ./caddy-analyzer.json; with it, the file is stored under ~/.config/caddy-analyzer/config.json. Local configuration is project-specific and takes precedence over the global location. show displays the active choice and reset removes the selected file.

caddy-analyze config /var/log/caddy/access.log
caddy-analyze config docker://caddy --global
caddy-analyze config show
caddy-analyze config reset

whitelist

sudo caddy-analyze whitelist [--add IP/CIDR] [--remove IP/CIDR]
caddy-analyze whitelist --list [--file PATH]

Maintains a file of IPs and CIDRs that guard must never block. The default is /etc/caddy-analyzer/whitelist.txt. --init creates it with a header, --add and --remove accept comma-separated values, and --list prints entries. Point guard at the same file with --never-block-file.

export-sigma

caddy-analyze export-sigma [output-file]

Exports the built-in detection categories as multi-document Sigma YAML. With no file it writes to stdout, which makes it suitable for piping to a validator; with a file it writes the complete rule set. The export is vendor-neutral and includes MITRE ATT&CK tags. Custom runtime patterns are not silently converted unless supported by the exporter.

caddy-analyze export-sigma rules.yml
caddy-analyze export-sigma - | sigma check

update

caddy-analyze update [--check|--version TAG|--force]

Checks for and installs a verified release from GitHub. Installation is fail-closed: cosign must validate the signed release manifest and the archive checksum must match it. --check performs no installation, --version pins a tag, --force permits reinstall or downgrade, and --install-dir selects a directory. If verification fails, the current binary is left untouched.

caddy-analyze update --check
sudo caddy-analyze update
caddy-analyze update --version v0.7.0 --install-dir ~/.local/bin

completion and version

caddy-analyze --version
caddy-analyze completion bash > ~/.local/share/bash-completion/completions/caddy-analyze
caddy-analyze completion zsh
caddy-analyze completion fish

--version prints the installed version. The hidden completion command generates shell completions for bash, zsh or fish; it requires exactly one supported shell name.

Useful combinations

# Investigate a suspected scan without taking action
caddy-analyze --detect --grep 'wp-login|\.env|/admin' access.log

# Create a comparable baseline and check for a regression
caddy-analyze baseline save baseline.log -o baseline.json
caddy-analyze --against baseline.json current.log --threshold 20

# Preview guard decisions, then enable enforcement
sudo caddy-analyze guard access.log --dry-run --never-block-file whitelist.txt
sudo caddy-analyze guard access.log --never-block-file whitelist.txt
Read next
See CLI Reference for the complete flag matrix, Log Sources for source syntax, and Security Detection for categories, confidence and evidence.

Global flags: complete reference

Most options below are persistent and inherited by subcommands. The root-only modes are --follow, --interval, --watch, root --detect and --version; tail has its own local --detect. An omitted value keeps the default. Durations use Go syntax such as 500ms, 5m or 1h.

FlagDefaultWhat it does
--fromnoneKeeps entries after an RFC3339 time or relative period such as 5m, 1h or 2d.
--tononeKeeps entries before the supplied RFC3339 time.
--status, -sallSelects one or more HTTP status codes, for example -s 200,404; repeatable.
--2xx, --3xx, --4xx, --5xxfalseShortcuts for selecting a status class.
--errors-only, -efalseKeeps only 5xx server errors.
--method, -mnoneFilters by HTTP method, case-insensitively.
--path, -pnoneFilters paths with a glob such as /api/*.
--hostnoneFilters by a substring of the request host.
--ip / --exclude-ipnoneInclude or exclude an IP address or CIDR network.
--country / --exclude-countrynoneInclude or exclude ISO country codes or names; requires GeoIP.
--asn / --exclude-asnnoneInclude or exclude ASN numbers; requires GeoIP.
--slownoneSelects requests slower than the supplied duration.
--max-latencynoneSelects requests no slower than the supplied duration.
--min-size / --max-sizenoneBounds response size in bytes; accepts kb, mb and gb suffixes.
--grepnoneSearches URI, User-Agent and IP using a regex, with substring fallback for invalid patterns.
--no-bots / --bots-onlyfalseExclude or include only traffic classified as bots and crawlers.
--levelallFilters operational events by error, warn, info or debug; repeatable.
--ops-onlyfalseShows only non-HTTP operational events.
--top, -t10Number of ranked items; 0 disables top lists.
--format, -ftableSelects table, json, csv, html, elasticsearch, opensearch or loki where supported.
--output, -ostdoutWrites output to a file instead of stdout.
--compact, -cfalseUses the compact table layout.
--defangfalseReplaces dots in IPs with [.] for safe IOC sharing.
--workersavailable CPUsSets parser worker count; 0 selects automatically and keeps reduction ordered.
--max-cardinality100000Caps distinct keys per counter to bound memory; 0 is unlimited.
--trust-forwardedfalseUses the last public X-Forwarded-For/X-Real-IP hop; enable only behind a trusted proxy.
--geoip-dbautoSets a DB-IP or MaxMind mmdb path; empty enables auto-discovery.
--no-auto-downloadfalsePrevents the first-use DB-IP database download.
--geo-cache-ttl24hSets GeoIP cache lifetime; 0 disables caching.
--geo-cache-size50000Sets maximum cached GeoIP lookups; 0 disables caching.
--ua-rotation10Distinct User-Agent count from one IP before the rotation/scanner heuristic fires.
--custom-patternsnoneLoads one or more validated custom detection JSON files.
--againstnoneCompares current analysis with a baseline JSON and applies the threshold.
--threshold20%Regression percentage used by baseline comparison.
--namespace, -nnoneKubernetes namespace for k8s:// sources.
--follow, -FfalseFollows new logs and emits periodic reports; root mode.
--interval, -inoneSets aggregation window length in follow mode.
--watch, -wfalseOpens the live TUI dashboard and requires a terminal.
--detect, -dfalseEnables threat detection in the root report.
--remote-urlnoneHTTP endpoint for Elasticsearch/OpenSearch bulk or Loki output; required for those formats.
--remote-indexcaddy-analyzerElasticsearch/OpenSearch index name.
--remote-user, --remote-passwordnoneHTTP Basic credentials for remote delivery.
--remote-tokennoneHTTP Bearer token for remote delivery.
--remote-batch-size100Documents per remote request.
--remote-retries3Retries after the first remote delivery attempt.
--remote-backoff250msInitial delay between remote retries.
--remote-timeout10sTimeout for each remote request.

Subcommand-specific flags

tail

tail --detect highlights suspicious requests inline. All global filters remain available, but tail does not aggregate a report and never blocks IPs.

top

top --by DIMENSION is the flag form of the positional dimension. Valid dimensions are path, ip, ua, status, method, host, bandwidth, country, city and asn. The last three require a compatible GeoIP database.

baseline save

baseline save --detect adds security statistics to the JSON. --output is the global flag used to retain the file; generate the baseline with the same filters used for comparison.

blocklist

FlagWhat it does
--cache-dirDirectory for downloaded feed files.
--no-default-blocklistsDisables the eight built-in feeds for a custom-only setup.
--blocklist-config FILEAdds JSON sources with name, url and optional format; repeatable.
--blocklist-remove NAMERemoves named sources; accepts comma-separated names.
--format table|jsonOutput format for list and config.

refresh downloads feeds; list shows status, age, errors and counts; config prints effective configuration; init saves current settings. None changes firewall rules.

guard

FlagDefaultWhat it does
--limit, -l100HTTP requests per IP in the window before blocking; 0 disables.
--window, -w1mSliding monitoring window with per-second buckets.
--duration, -d10mBlock duration; 0 is permanent.
--auth-limit10401/403 responses before blocking; 0 disables.
--notfound-limit50404 responses before blocking; 0 disables.
--detect-confidence8Minimum pattern confidence from 1-10; 0 disables only this block path.
--firewall-backendautoSelects auto, iptables, docker, nftables or hybrid.
--dry-runfalseReports and audits would-be blocks without changing firewall or state.
--country-blocknoneImmediately blocks listed ISO countries through GeoIP.
--no-blocklistfalseDisables checking the eight feeds.
--blocklist-refresh6hFeed refresh interval; minimum 1h, 0 disables.
--cache-diruser cacheBlocklist cache directory.
--never-blocknoneProtected IPs/CIDRs; repeatable.
--never-block-filenoneOne IP/CIDR per line, with # comments.
--state-file/var/lib/caddy-analyzer/blocked.jsonPersists and recovers blocks; empty disables.
--iptables-timeout10sTimeout for each firewall invocation.
--subnet-limit0Blocks a /24 or /64 when distributed requests exceed the threshold.
--rps-anomaly0Audits an RPS spike over the EWMA baseline; it is not a block.
--cred-stuffing-limit0Audits distinct IPs failing the same path; it is not a block.
--audit-logJSONL in /var/logLocal event log; empty disables.
--audit-syslogdisabledUDP syslog destination such as 127.0.0.1:514.
--webhook-url / --audit-webhookdisabledGeneric, Slack, Discord or PagerDuty notifications.
--webhook-providergenericWebhook provider name.
--pagerduty-routing-keynonePagerDuty routing key; excluded from logs.
--audit-timeout / --audit-retries5s / 2Sink timeout and retries after the first attempt; max 5 retries.
--audit-rate-limit0Minimum interval between notifications for one IP; 0 disables.

block and unban

Both commands share audit flags: --audit-log, --audit-syslog, --webhook-url/--audit-webhook, --webhook-provider, --pagerduty-routing-key, --audit-timeout, --audit-retries and --audit-rate-limit. --state-file synchronizes manual changes with guard. Additionally, unban --list lists active IPs and unban --all removes all tracked blocks; do not combine them.

config

--global, -g selects the global configuration file instead of the local one. config SOURCE and config set SOURCE set a source; config show displays it and config reset removes the selected file.

whitelist

--file selects the file, --init creates it, --add inserts IPs/CIDRs, --remove deletes them and --list, -l prints entries. Pass the same file to guard with --never-block-file.

update

--check only checks, --version TAG installs an exact release, --force allows reinstall or downgrade and --install-dir DIR selects the destination directory. cosign and SHA256 verification is mandatory.

export-sigma

Accepts at most one output file. No argument or - writes multi-document Sigma YAML to stdout; a path writes the complete rule set. Global analysis filters do not change the exported rules.

help and --help

caddy-analyze help COMMAND displays command help without executing it; --help is available on every command and subcommand. The help generated by the installed binary is the final authority for flags and defaults in that version.