OpenWrt CLI
English | 简体中文
Remote OpenWrt admin over SSH or LuCI/ubus HTTP. The same services power CLI tables (typer + rich), the setup/wizard flows (questionary), and the full-screen TUI (textual).
The command is openwrt. openwrt-cli is still installed as a compatibility alias; docs and --help always say openwrt.
|
Network |
Neighbors |
PassWall2* |
|
Services |
Process |
Logs |
* PassWall2 requires openwrt-cli >= 1.1.0 and luci-app-passwall2 on the router.
Features
- Three surfaces — CLI tables,
setup+wizard, andopenwrt tui - doctor — capability-aware SSH/HTTP health checks, structured,
-f jsonready - Network — interfaces, routes, rules, neighbors, DHCP leases with MAC vendors, optional Bandix history
- PassWall2 — optional
luci-app-passwall2; requires openwrt-cli >= 1.1.0. Read status / nodes / ACL / logs; add, edit, delete nodes and ACL; TUI tab7when the package is present - One device model — SSH and HTTP share ubus / uci / shell semantics; missing capability fails loudly (no fake data)
- Agent-ready —
-f json/-f compact, no TTY or color required - English / 简体中文 UI — command names stay English
Quick Start
curl -fsSL https://raw.githubusercontent.com/Necho-dev/openwrt-cli/main/install.sh | bash
openwrt setup
openwrt doctor
openwrt tui
Non-interactive equivalent:
openwrt -H 192.168.1.1 -u root --password your_password --save-config
Installation
Requires Python >= 3.12.
Linux / macOS
curl -fsSL https://raw.githubusercontent.com/Necho-dev/openwrt-cli/main/install.sh | bash
Windows — clone, then run install.bat, or:
pip install git+https://github.com/Necho-dev/openwrt-cli.git
pip / pipx
pipx install git+https://github.com/Necho-dev/openwrt-cli.git
Development (Poetry)
git clone https://github.com/Necho-dev/openwrt-cli.git
cd openwrt-cli
poetry install
poetry run openwrt --help
poetry install --with dev
poetry run pytest -m "not live" # no device, CI-safe
OPENWRT_LIVE=1 poetry run pytest -m live # read-only against ~/.openwrt-cli.yaml
Destructive commands (reboot, reload, service restart, …) are not in the live set.
Release — bump [project].version in pyproject.toml, add a matching ## [x.y.z] section to both CHANGELOG.md and CHANGELOG.zh.md, then tag vx.y.z and push the tag. The publish workflow runs unit tests, checks the tag against pyproject.toml and PyPI (refuses a version that already exists), requires the two changelogs to list the same versions, builds the wheel, uploads it, and opens a GitHub Release from the English notes (with a link to the Chinese changelog).
Command Overview
Flags may sit before or after a subcommand (openwrt network leases -f json). Full help: openwrt --help and openwrt <group> --help.
| Option | Description |
|---|---|
-H, --host |
Device IP |
-u, --user |
Username |
-p, --port |
Port (SSH 22 / HTTP 80 / HTTPS 443) |
-i, --identity-file |
SSH private key path (same as ssh -i) |
--password |
Login password |
--ssh |
Connect over SSH |
--http |
LuCI/ubus HTTP |
--https |
LuCI/ubus HTTPS |
--config |
Config file path |
-L, --language |
UI language: en / zh |
-f, --format |
Output format: text / json / compact |
--json |
Same as -f json; Agent-friendly |
--yes, -y |
Skip confirmation |
-v, --version |
Show version and exit |
Success and failure are one object with ok. Interactive commands (setup, tui, wizard) refuse JSON (error: interactive). Destructive actions prompt on a TTY; in a pipe or JSON mode they need --yes or they exit 2.
doctor / system / logs
openwrt doctor
openwrt doctor --quick
openwrt -f json doctor
openwrt system status
openwrt system memory
openwrt system processes
openwrt logs system --tail 80
openwrt logs system -f
openwrt logs kernel --tail 80
openwrt logs system --since 10m
network
openwrt network interfaces
openwrt network interfaces --rates
openwrt network routes
openwrt network rules
openwrt network neighbors # IPv4 neighbors; Bandix overlays device rates when present
openwrt network set-hostname --mac aa:bb:cc:dd:ee:ff --name phone --yes
openwrt network leases
openwrt network metrics # Bandix history (needs luci-app-bandix)
openwrt network metrics --ip 192.168.1.50 --since 30m
openwrt network wifi list
openwrt network lan show
openwrt network reload --yes
qos is OpenWrt SQM / tc (luci-app-sqm), not Bandix per-device limits.
passwall2
Requires openwrt-cli >= 1.1.0 and luci-app-passwall2 on the router. Older CLI builds do not have this command group or TUI tab.
When the package is present, TUI adds tab 7 with Nodes / Subscribe / Settings / Rules / ACL / Logs. The node list shows type, protocol, address, port, Ping, and TCPing; the right pane is the selected node. Keys: a add, e edit, Del delete, p Ping, c TCPing, [ ] switch sub-pages.
Read: status, nodes (Ping + TCPing on list enter/refresh), subscribe, settings, components, ACL, and logs. Write nodes and ACL through UCI (node add/set/delete, acl add/set/delete, acl source add/remove); --apply restarts PassWall2. No subscribe refresh, clear_log, or component update.
openwrt passwall2 status
openwrt passwall2 nodes
openwrt passwall2 node show <id>
openwrt passwall2 node add --from-url 'vless://...' --apply --yes
openwrt passwall2 node set <id> --remarks HK --yes
openwrt passwall2 acl
openwrt passwall2 acl add --remarks iot --sources 192.168.9.10 --yes
openwrt passwall2 logs --tail 80
firewall / qos
UCI views work over HTTP. Commands that need iptables or tc fail on HTTP instead of inventing data — use --ssh.
openwrt --https firewall zones # UCI, OK
openwrt --https firewall rules # needs iptables → fail (use --ssh)
openwrt qos status
service / user / backup
openwrt service list --running
openwrt service show firewall
openwrt service restart firewall --yes
openwrt user key add --yes
openwrt backup create -o /tmp/bak.tar.gz
openwrt backup restore /tmp/bak.tar.gz --yes
setup / wizard / tui
openwrt setup
openwrt wizard # menu
openwrt wizard wifi # user | hostname | wifi | lan | service
openwrt tui
TUI keys: 1–6 tabs (7 PassWall2 when luci-app-passwall2 is present; openwrt-cli >= 1.1.0), r refresh, e edit (Neighbors hostname / PassWall2 node or ACL), f filter, q quit, ? help.
Configuration
openwrt setup or --save-config writes ~/.openwrt-cli.yaml:
host: 192.168.1.1
user: root
port: 22
transport: ssh
# password: prefer an SSH key
identity_file: ~/.ssh/id_ed25519_openwrt
openwrt config show
openwrt config path
openwrt config set -H 192.168.1.1 --ssh
openwrt config set --language en
UI language (tables, TUI, setup, help) resolves as:
-L/--languageorOPENWRT_LANG(en/zh)languagein the config file- System locale (
LANG/LC_ALL) — Chinese locales get 简体中文, everything else English
openwrt setup detects the system language, asks you to confirm, and writes it to the config file.
Project Layout
src/openwrt_cli/
app.py # entry (openwrt / openwrt-cli)
commands/ # Typer
services/ # presentation-free business logic
tui/ # textual dashboard
ui/ # Rich / questionary
core/ # DeviceClient, SSH / HTTP channels
i18n/
flowchart LR
CLI[CLI / wizard / TUI] --> Services
Services --> DeviceClient
DeviceClient --> SSH
DeviceClient --> HTTP
SSH --> Channels[ubus / uci / shell]
HTTP --> Channels
FAQ
SSH will not connect
openwrt setup
ssh -v -p 22 root@192.168.1.1
Use a key instead of a password
openwrt user key add --yes
openwrt -H 192.168.1.1 -i ~/.ssh/id_ed25519_openwrt --save-config
Web admin only, no SSH
openwrt setup # pick HTTP API
openwrt --https system status
firewall rules fails over HTTP — that path needs iptables. Use --ssh, or stick to UCI commands such as firewall zones.
JSON / pipe errors on reboot, reload, restart — add --yes.
passwall2 is unknown / no TUI tab 7 — that feature shipped in openwrt-cli >= 1.1.0. Upgrade the CLI, and install luci-app-passwall2 on the router. openwrt -v prints the package version.
openwrt is not on PATH — a pip install --user may have dropped the script in python -m site --user-base + /bin. Add that directory, or install with pipx.
Switch the UI language
openwrt -L zh doctor
openwrt config set --language zh
Acknowledgments
This project talks to OpenWrt through the official stack:
- openwrt/openwrt — the OpenWrt operating system
- openwrt/luci — LuCI web interface and ubus/HTTP API
- openwrt/uci — Unified Configuration Interface
Thanks to a6726170/openwrt-cli for the original inspiration.
License
MIT — see LICENSE.
Release files for openwrt-cli 1.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| openwrt_cli-1.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Release files / openwrt_cli-1.1.1-py3-none-any.whl
| Download URL | openwrt_cli-1.1.1-py3-none-any.whl |
|---|---|
| Size | 189.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
94795823255dc557aec042c8de94616274cf9b5d3130ed39d7f90f248c1cce2f
|
|
BLAKE2b-256 checksum How to use checksums |
cfe2c241c411fb64e38397cd5263103f29de1915227b740bb79912c0a80620d3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency log