dezhban [-v] <command> [flags]
Commands:
run Run the monitor→decision→enforcement loop (root)
block Manually block network egress (root)
unblock Remove dezhban's firewall rules (root)
status Show version, config, service, and block state (--json for tooling)
validate Load + validate a config file (no root, no effects)
print-rules Print the ruleset a block/guard would apply, without applying it
doctor Diagnose VPN guard config (tunnels, endpoints, lockout risks)
monitor Live read-only view: IP, country, tunnel state, endpoints, verdict
panic Force-remove dezhban's rules even with no daemon (root)
install Register dezhban as a boot-persistent OS service (root)
uninstall Remove the OS service (root)
start Start the installed service (root)
stop Stop the installed service (removes firewall rules) (root)
detect-vpn Print detected VPN tunnel interfaces for config
setup Interactive wizard to create or update the config
config Inspect or change the config without hand-editing JSON
completion Print a shell completion script (bash|zsh|fish)
version Print the version
Global: -v / --verbose override the configured log level to debug
--config is optional: when omitted, dezhban resolves the config from
$DEZHBAN_CONFIG, then the canonical system path (dezhban config path prints
it), then built-in defaults. So dezhban run / monitor / validate normally
need no path at all.
Privileged commands (run, block, unblock, panic, install, uninstall,
start, stop) require root/admin. When run without it from an interactive
terminal on unix, dezhban auto-re-runs itself under sudo (prompting for your
password once) — so you rarely need to type sudo yourself. Pass --no-sudo (or
set DEZHBAN_NO_SUDO=1) to opt out and get the plain "must run as root" error;
on Windows, and when there's no terminal (CI/pipes), it never auto-elevates.
setup and config set/edit elevate just their config write the same way. The
inspect commands (validate, print-rules, doctor, monitor) are read-only —
no root, no firewall effects.
dezhban status # config + service + block state
dezhban status --json # machine-readable (merges the state file)
dezhban run --dry-run # poll & print country, no firewall
sudo dezhban run --config /etc/dezhban/dezhban.json
# manual block / override
sudo dezhban block --config configs/dezhban.example.json
sudo dezhban block --force # cut ALL egress, ignore detection
sudo dezhban unblock
sudo dezhban panic # standalone teardown, no daemon neededrun --dry-run— poll and print the country without touching the firewall.block --guard— install the VPN interface guard (see modes.md).block --force— unconditional hard block of all egress (loopback + allowlist only), bypassing the VPN guard. The override when detection is wrong.unblock --force— accepted for symmetry (unblockis already unconditional).--simulate-country IR(onmonitorandrun) — force the verdict from anywhere, without a sanctioned IP.
Inspect and validate before you risk a block — none of these touch the firewall:
dezhban validate --config <config> # parse + validate, summarize
dezhban print-rules --mode guard --config <config> # exact ruleset, not applied
dezhban doctor --config <config> # tunnels, subnets, endpoint sanity
dezhban doctor --discover --config <config> # macOS: find the VPN's real server IP
dezhban monitor --config <config> # live: IP, country, tunnels, endpoints, verdictmonitor streams the live state the decision rests on; add --once for a single
snapshot. print-rules --mode takes guard, fullblock, or legacy. See
config.md for the full field reference and troubleshooting.md
for the lockout-recovery runbook.
You rarely need to touch JSON by hand. See config.md for where the file lives and the resolution order.
sudo dezhban setup # interactive wizard — builds/updates the config,
# detects tunnels, previews the ruleset, then writes it
dezhban config path # print the resolved config path
dezhban config show # print the effective config as JSON
dezhban config get blockedCountries
sudo dezhban config set blockedCountries IR,RU # set, validate, save
sudo dezhban config edit # open the config in $EDITOR, re-validated on savesetup needs an interactive terminal and reuses the same tunnel detection,
validation, and ruleset preview as detect-vpn/validate/print-rules. Writes to
the system path need root (hence sudo); a permission error prints a sudo hint.
source <(dezhban completion zsh) # or bash; add to your ~/.zshrc / ~/.bashrc
dezhban completion fish | source # fishCompletes subcommands, --mode values (guard|fullblock|legacy), the config
subcommands, and file paths for --config.
dezhban can install itself as a boot-persistent background service using one
cross-platform API (launchd on macOS, systemd/upstart/sysv on Linux, the Windows
Service manager). The service wraps the run loop, restarts on crash, and routes
logs to the platform logger (syslog/journald/Event Log).
sudo dezhban install --config /etc/dezhban/dezhban.json # register (default path if omitted)
sudo dezhban start # start now; also auto-starts on boot
dezhban status # → service: installed, running
sudo dezhban stop # stops AND removes firewall rules
sudo dezhban uninstallstop cancels the run loop so its deferred Cleanup() removes every rule —
stopping the service never leaves a block-all rule behind. If the service crashes
while blocked, the rules persist by design (a kill switch must not fail open); use
sudo dezhban panic to flush them even with no daemon running.
On macOS an optional native menubar app (Dezhban.app) shows the daemon's
live posture at a glance and offers click-to-control. It's a separate Swift/AppKit
target, so the Go binary keeps its zero-dependency, CGO_ENABLED=0 promise. Build
it with make gui-macos (see development.md).
- Status icon — 🟢 allow/guard, 🔴 block/full-block, ⚪ stopped or stale; repainted about once a second.
- Menu — Start/Stop, Block/Unblock, VPN-mode indicator + Open config, View
logs, Launch at login (
SMAppService), Quit. Items enable/disable from the current state; privileged actions raise a native admin prompt viaosascript.
The app runs no IP/country poller of its own — it reads the daemon's state file (see state.md), the single source of truth for what the daemon decided. It is unsigned for local use (right-click → Open past Gatekeeper); an in-app VPN-mode toggle is deferred (the menu routes to Open config…). Design notes: plans/phase-8-macos-gui.md.