Files
abrown38andClaude Opus 5.5 1bc9f9f63a Let the Reserve button pick another address of the lease's subnet
The Reserve dialog fills in the lease's address but lets it be changed;
POST /leases/{ip}/reserve takes an optional ip, steward lease reserve
takes --ip. The address must be in the lease's subnet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 00:29:07 +01:00

9.5 KiB

The steward CLI

steward talks to stewardd's REST API. steward help COMMAND describes each command and its flags.

Connecting

  • On the server, with nothing configured, the CLI uses stewardd's local socket, /run/steward/steward.sock. Root and the steward user are administrators there without a token: sudo steward status.

  • From elsewhere, give the server's URL and an API token:

    steward config set server https://dhcp.example.com:8067
    steward config set token          # asks for it
    

    The settings are in ~/.config/steward/config.yaml (on macOS ~/Library/Application Support/steward/config.yaml, on Windows %AppData%\steward\config.yaml).

Flag Environment
-s, --server URL STEWARD_SERVER the server; local for the local socket
--token TOKEN or @FILE STEWARD_TOKEN the API token
--config FILE STEWARD_CLI_CONFIG the CLI's configuration file
STEWARD_SOCKET the local socket's path
--insecure, --ca-cert FILE TLS: skip the check, or trust another CA
-n, --dry-run check and show a change without making it
-o, --output FORMAT table (default), json, yaml or id
-q, --quiet print only errors (and the IDs of new objects)

Exit codes: 0 ok, 1 error, 3 not authenticated or not allowed, 4 not found, 5 conflict, 6 invalid or refused by validation, 7 server error.

Changes

Every change is checked as a whole first. A refused change says why and gives the problem's code (validation.md). A saved one says its history entry, and any new warnings:

$ steward subnet add 10.0.20.0/24 --interface eth0.20 --name iot --pool 10.0.20.100-10.0.20.200
created subnet iot (10.0.20.0/24)
saved (history 2; undo with 'steward history undo 2')
warning: subnet iot (10.0.20.0/24): this server has no interface eth0.20 (it has eth0, lo); the subnet is served once it appears [interface_unknown]

-n shows what would change without changing it.

Commands

status

steward status: the version, each interface and whether it is served (and why not), each subnet's pool use, leases by state, DHCP messages since the start, and problems.

subnet

Command
subnet list subnets, with interface, pools, use, reservations, lease time
subnet show SUBNET one subnet; SUBNET is its ID, name or prefix
subnet add PREFIX --interface IFACE [--name N] [--pool A-B[:ORDER]]... [--pool-order listed|random] [--address-order sequential|reverse|random] [--lease-time 12h] [--option NAME=VALUE]... [--comment C] add one
subnet update SUBNET [--name] [--interface] [--prefix] [--pool]... [--add-pool] [--remove-pool] [--pool-order] [--address-order ...|default] [--lease-time 1h|default] [--option NAME=VALUE]... [--unset-option NAME]... [--comment] change what is given; --add-pool of a pool it has changes that pool's order (subnets.md)
subnet enable|disable SUBNET answer its clients, or not
subnet delete SUBNET [-y] delete it and its reservations

--pool replaces the pools; --add-pool and --remove-pool change one. --option sets an option and keeps the others; --unset-option removes one. An option Steward doesn't know: --option 224:string=hello.

reservation

Command
reservation list [--subnet SUBNET] reservations, whether each client is online, and when it last answered a ping
reservation show RES RES is its ID, address or MAC address
reservation add IP MAC [--hostname H] [--client-id HEX] [--lease-time 7d] [--option NAME=VALUE]... [--comment C] - for MAC with --client-id; with both, either matches
reservation update RES [--ip] [--mac] [--client-id] [--hostname] [--lease-time 7d|default] [--option]... [--unset-option]... [--comment]
reservation enable|disable RES use a reservation, or keep it but ignore it
reservation delete RES

access

Command
access show SUBNET the subnet's mode and its allow and deny lists
access mode SUBNET deny-list|allow-list answer every client not denied, or only the allowed (and reserved)
access allow SUBNET ENTRY... [--comment C] add to the allow list (aa:bb:cc:dd:ee:ff, aa:bb:cc:* or id HEX); an entry it has gets the new comment
access deny SUBNET ENTRY... [--comment C] add to the deny list
access remove SUBNET ENTRY... take off both lists

See subnets.md.

lease

Command
lease list [--subnet S] [--state STATE] [--interface I] [--search TEXT] [-a] active and held-back leases; -a all
lease show IP one lease
lease reserve IP [--ip ADDR] [--hostname H] [--by mac|client-id|both] make the address its client's reservation, by its MAC address and client ID (either matches) unless --by says one; --ip reserves another address of the same subnet instead
lease delete IP [-y] free the address at once

activity

steward activity [--mac MAC] [--subnet SUBNET] [--interface I] [--limit N] [-d] [-f]: the latest DHCP messages, received and sent, oldest first. --subnet takes an ID, name or prefix; a message without an address (a DISCOVER, "no address") shows for every subnet on its interface. -f keeps watching, which is useful while a device tries to get an address:

#1042  11:02:13.120  eth0     DHCPDISCOVER  3c:22:fb:11:22:33 -               adams-macbook
#1043  11:02:13.622  eth0     DHCPOFFER     3c:22:fb:11:22:33 10.0.10.150     adams-macbook
#1044  11:02:13.630  eth0     DHCPREQUEST   3c:22:fb:11:22:33 10.0.10.150     adams-macbook
#1045  11:02:13.631  eth0     DHCPACK       3c:22:fb:11:22:33 10.0.10.150     adams-macbook

Each line starts with the message's number. -d (--details) adds every field and option of each message in words, and steward activity show N shows one: what the client asked for (its parameter request list, by name), its client identifier and host name, and what Steward sent back (lease time, routers, DNS servers...):

$ steward activity show 1042
#1042 DHCPDISCOVER on eth0 at 2026-10-18 11:02:13.120, received from the client
  transaction ID: 0x3a1c99f0
  client hardware address: 3c:22:fb:11:22:33
  flags: broadcast (the client wants replies broadcast)
  option 53 message-type: DHCPDISCOVER
  option 61 client-identifier: 01:3c:22:fb:11:22:33 (type 1: the MAC address 3c:22:fb:11:22:33)
  option 55 parameter-request-list: subnet-mask (1), routers (3), domain-name-servers (6), domain-name (15), v4-captive-portal (114)
  option 12 host-name: adams-macbook

In the web UI, ▸ on an Activity row opens the same.

NO ADDRESS means the pools on that interface are full, and CONFLICT an address that answered the ping check. A DHCPNAK says why it was sent.

settings and options

Command
settings show
settings set [--lease-time 1d] [--ping-check on|off] [--ping-timeout 500ms] [--decline-hold 24h] [--authoritative on|off] [--address-order sequential|reverse|random] [--option NAME=VALUE]... [--unset-option NAME]...
option list the options Steward knows (options.md)
interface list the server's interfaces, their addresses and subnets (not those in interfaces.exclude)

history

Command
history list [--limit N] changes, newest first
history show ID each object's fields before and after
history undo ID apply the change backwards (refused if something it touched has changed since)

import

steward import kea CONFIG [--leases FILE]... [--interface PREFIX=IFACE]... [--replace]: see kea.md.

cert

Administrators only (certificates.md).

Command
cert the certificate: name, CA, validity, renewal, the last check
cert check check that the challenge can be published through Jarl and seen, without the CA (fails with exit code 1 if it can't)
cert renew [-w] get a new certificate now; -w waits and shows the result

users, tokens, audit

Command
whoami who you are to the server, and what you may do
user list|add|update|delete users (administrators); user add NAME --role operator
token list [--all], token create NAME [--role R] [--grant G]... [--expires 90d] [--user U] [--save], token revoke ID API tokens
token rotate ID|--current [--grace 1h] [--expires 90d|never] [--save] a new secret for a token, the old one working for the grace period
password change your password
audit [--user U] [--action PREFIX] [--search TEXT] the audit log
config show, config set server|token|insecure|ca_cert [VALUE] this CLI's settings

permissions.md explains roles and grants.

stewardd

The daemon's own commands work on the database directly, as root or the steward user (sudo -u steward stewardd ...):

Command
stewardd serve run (the systemd unit does)
stewardd init [-u NAME] [--token] create the database and the first administrator (asks for the name on a terminal)
stewardd user add NAME [--admin], user password NAME, user token NAME TOKEN-NAME when the API can't be used
stewardd check check the configuration against this machine's interfaces
stewardd backup [FILE], stewardd restore FILE operations.md
stewardd config [--example] the settings in use, or a commented example
stewardd version

All take -c FILE for another configuration file.