• Steward v0.2.0-rc.3
    release / release (push) Successful in 3m24s
    Pre-Release

    adam released this 2026-10-24 23:33:41 +00:00 | -16 commits to main since this release

    Added

    • Reserve another address from a lease. The Reserve dialog on the
      Leases page fills in the lease's address but lets you change it, to
      any address of the same subnet (steward lease reserve IP --ip ADDR,
      "ip" in the API). The client moves there when it next renews.

    • Failed logins in the journal. A failed login and a refused API
      token are logged as well as audited, with the address first
      (msg="login failed" ip=… user=…, msg="token refused" ip=…), for
      Guard's steward preset or a fail2ban filter to ban such addresses
      (docs/operations.md).

    • Allow and deny lists per subnet (docs/subnets.md): a deny-list
      subnet (the default) answers everyone not denied; an allow-list subnet
      only clients allowed or with a reservation. Entries are MAC addresses,
      prefixes (aa:bb:cc:*) or client IDs. A refused client gets no answer
      (DENIED in the activity log, with an Allow button), or a NAK when it
      next renews. steward access, the subnet's Access tab, access,
      allow and deny in the API.

    • Every option of a DHCP message, in words: ▸ on an Activity row,
      steward activity show N or --details, and GET /events/{id}. What
      the client asked for (its parameter request list, by name), its client
      ID and host name, and what Steward sent back.

    Upgrading from 0.1

    • The database gets a new version (7), applied when stewardd starts; a
      0.1 stewardd can't open it afterwards, so take a backup first (sudo stewardd backup). Every subnet stays a deny-list subnet with empty
      lists, so nothing changes until you add entries.
    Downloads
  • Steward v0.2.0-rc.2
    release / release (push) Successful in 3m22s
    Pre-Release

    adam released this 2026-10-22 18:08:58 +00:00 | -14 commits to main since this release

    Added

    • Failed logins in the journal. A failed login and a refused API
      token are logged as well as audited, with the address first
      (msg="login failed" ip=… user=…, msg="token refused" ip=…), for
      Guard's steward preset or a fail2ban filter to ban such addresses
      (docs/operations.md).

    • Allow and deny lists per subnet (docs/subnets.md): a deny-list
      subnet (the default) answers everyone not denied; an allow-list subnet
      only clients allowed or with a reservation. Entries are MAC addresses,
      prefixes (aa:bb:cc:*) or client IDs. A refused client gets no answer
      (DENIED in the activity log, with an Allow button), or a NAK when it
      next renews. steward access, the subnet's Access tab, access,
      allow and deny in the API.

    • Every option of a DHCP message, in words: ▸ on an Activity row,
      steward activity show N or --details, and GET /events/{id}. What
      the client asked for (its parameter request list, by name), its client
      ID and host name, and what Steward sent back.

    Upgrading from 0.1

    • The database gets a new version (7), applied when stewardd starts; a
      0.1 stewardd can't open it afterwards, so take a backup first (sudo stewardd backup). Every subnet stays a deny-list subnet with empty
      lists, so nothing changes until you add entries.
    Downloads
  • Steward v0.2.0-rc.1
    release / release (push) Successful in 58s
    Pre-Release

    adam released this 2026-10-18 19:40:11 +00:00 | -12 commits to main since this release

    Added

    • Allow and deny lists per subnet (docs/subnets.md): a deny-list
      subnet (the default) answers everyone not denied; an allow-list subnet
      only clients allowed or with a reservation. Entries are MAC addresses,
      prefixes (aa:bb:cc:*) or client IDs. A refused client gets no answer
      (DENIED in the activity log, with an Allow button), or a NAK when it
      next renews. steward access, the subnet's Access tab, access,
      allow and deny in the API.
    • Every option of a DHCP message, in words: ▸ on an Activity row,
      steward activity show N or --details, and GET /events/{id}. What
      the client asked for (its parameter request list, by name), its client
      ID and host name, and what Steward sent back.

    Upgrading from 0.1

    • The database gets a new version (7), applied when stewardd starts; a
      0.1 stewardd can't open it afterwards, so take a backup first (sudo stewardd backup). Every subnet stays a deny-list subnet with empty
      lists, so nothing changes until you add entries.
    Downloads
  • v0.1.0 b3c8329ae8

    Steward v0.1.0
    release / release (push) Successful in 57s
    Stable

    adam released this 2026-10-18 19:39:13 +00:00 | -10 commits to main since this release

    The first version of Steward, a DHCPv4 server with a web UI, a REST API
    and a CLI, built the way Jarl is.

    Added

    • DHCPv4 server (stewardd serve):
      • Answers DISCOVER, REQUEST (selecting, init-reboot, renewing,
        rebinding), DECLINE, RELEASE and INFORM, as RFC 2131 describes.
      • Serves each subnet on its own network interface, with a socket per
        interface bound to it, so a VLAN's clients only get that VLAN's
        addresses.
      • Several subnets on one interface are served together, as a shared
        network.
      • Opens an interface's socket when the interface appears, such as a
        VLAN that comes up later, and closes it when its last subnet goes.
    • Address choice, in this order:
      1. the client's reservation;
      2. the address it had before;
      3. the address it asks for;
      4. a pool address never handed out, else the one free the longest.
    • Reserved addresses are never handed out to anyone else, even inside
      a pool.
    • Leases are kept in SQLite and saved before the ACK is sent. Ended
      ones stay 30 days, so returning clients get their address again.
    • Conflict checks:
      • An address is pinged before it is offered, and one that answers is
        held back.
      • An address a client declines is held back for a day.
      • Both use the decline_hold setting.
    • Authority: a request for an address that doesn't belong on the
      interface gets a NAK, so the client starts over at once. This can be
      turned off when another server shares a network.
    • Options:
      • 27 by name (routers, domain-name-servers, domain-search,
        ntp-servers, classless-static-route, …), and any other by number
        with a type.
      • Set globally, per subnet and per reservation, the most specific
        winning.
      • When a client sends a parameter request list, it gets what it asked
        for, in that order.
    • Configuration changes:
      • Validated as a whole, with stable problem codes (docs/validation.md).
      • Saved with a history entry, and can be undone after a check that
        nothing changed since.
      • ?dry_run=1 (or steward -n) previews a change.
    • REST API (docs/api.md):
      • users, sessions with CSRF protection, and API tokens limited by role
        or grant (config, leases, audit);
      • an audit log;
      • a local unix socket where root needs no token.
    • CLI steward (docs/cli.md):
      • commands: status, subnet, reservation, lease, activity, settings,
        option, interface, history (with undo), import kea, user, token,
        password, audit, config;
      • output as tables, JSON, YAML or IDs.
    • Web UI:
      • a dashboard of interfaces, pool use, problems and recent messages;
      • subnets with their leases, reservations and settings;
      • leases, with reserve and delete;
      • reservations;
      • live DHCP activity;
      • settings and global options;
      • history with undo, the audit log, users and tokens.
      • A new subnet suggests its network and a pool from the interface's
        address.
    • Kea import: steward import kea (POST /import/kea) reads a
      kea-dhcp4.conf and its lease files (docs/kea.md):
      • global, shared-network and subnet options, pools, lease times and
        reservations;
      • each subnet's interface: Kea's, else the host's interface with an
        address in the subnet, else --interface PREFIX=IFACE.
      • It lists what it doesn't support instead of dropping it silently.
      • Importing again keeps subnets' and reservations' IDs and Steward's
        subnet names.
    • stewardd commands: init (asks for the administrator's name),
      user add|password|token, check, backup (with pruning), restore,
      config --example.
    • The web UI's certificate from Let's Encrypt, through Jarl
      (docs/certificates.md, docs/jarl.md):
      • tls.acme in steward.yaml names the certificate, and jarl: the
        Jarl server and a token that may only write the challenge record.
      • Steward gets the certificate with the DNS-01 challenge, writing the
        record through Jarl's API into every view that has the zone.
      • It renews with a third of the lifetime left, and swaps the new
        certificate in without a restart.
      • A check runs before every order, and on demand: Jarl, the zone, the
        token's permission, a test record, the zone's public name servers and
        public resolvers, clean-up. Each step says what to fix.
      • It starts with Let's Encrypt's staging service by default.
      • steward cert, cert check, cert renew; Server → Certificate in the
        web UI; GET /certificate, POST /certificate/check|renew.
      • Dashboard problems: certificate_failed, certificate_expiring,
        certificate_staging.
    • HTTPS and plain HTTP on one port: with a certificate, plain HTTP is
      redirected to HTTPS, except from the server itself (also for
      tls.cert_file).
    • Disabled reservations (steward reservation disable|enable, Disable
      in the web UI): kept but ignored, so the client gets a pool address like
      any other. Subnets get Disable/Enable buttons in the web UI too.
    • Hidden interfaces: interfaces.exclude in steward.yaml (names or
      shell patterns such as docker*) leaves interfaces out of the web UI's
      interface picker, steward interface list and GET /interfaces.
    • Last seen: with the ping check on, active leases' addresses are
      pinged every minute, and a client that answers gets a last-seen time
      (Leases page, reservations' online badge, steward lease list|show,
      steward reservation list|show, last_seen in the API). A client that
      blocks pings stays online for as long as its lease lasts, without one.
    • The Reservations page refreshes itself every 15 seconds, so online
      and last seen stay current.
    • Activity by subnet: steward activity --subnet, a subnet filter on
      the Activity page, GET /events?subnet= (ID, name or prefix).
    • Address order (docs/subnets.md): which never-used pool address a
      new client gets, sequential (the lowest, as before), reverse or
      random, in the settings, a subnet (--address-order) or a single
      pool (--pool 10.0.10.200-10.0.10.250:random). A subnet's pools are
      used in the order listed, or one at random (--pool-order random),
      weighted by its never-used addresses. Pools now keep the order they are
      given in. Kea's allocator: random is imported.
    • A reservation's own lease time (--lease-time 7d, the reservation
      dialog), over the subnet's.
    • Reservations by MAC address and client ID together: either one gets
      the client its address (a dual-boot machine sends two client IDs from
      one MAC). The Leases page shows the client ID a client sent, and
      reserving a lease uses both (steward lease reserve --by for one).
    • Token rotation (steward token rotate, POST /tokens/{id}/rotate,
      Rotate in the web UI): a new secret for a token, with an optional grace
      period for the old one, as in Jarl.
    • Packaging:
      • a sandboxed systemd unit (steward.service, also stewardd.service)
        whose only privilege is CAP_NET_BIND_SERVICE;
      • a daily backup timer, and sysusers and tmpfiles files;
      • Debian packages steward and steward-cli, and a Gitea release
        workflow.
    • The Steward logo: a key whose bow is a crown with Jarl's network
      nodes, in Jarl's blue and white, with a STEWARD wordmark in Jarl's
      letters.
    Downloads
  • Steward v0.1.0-rc.1
    release / release (push) Successful in 57s
    Pre-Release

    adam released this 2026-10-18 17:16:50 +00:00 | -8 commits to main since this release

    The first version of Steward, a DHCPv4 server with a web UI, a REST API
    and a CLI, built the way Jarl is.

    Added

    • DHCPv4 server (stewardd serve):
      • Answers DISCOVER, REQUEST (selecting, init-reboot, renewing,
        rebinding), DECLINE, RELEASE and INFORM, as RFC 2131 describes.
      • Serves each subnet on its own network interface, with a socket per
        interface bound to it, so a VLAN's clients only get that VLAN's
        addresses.
      • Several subnets on one interface are served together, as a shared
        network.
      • Opens an interface's socket when the interface appears, such as a
        VLAN that comes up later, and closes it when its last subnet goes.
    • Address choice, in this order:
      1. the client's reservation;
      2. the address it had before;
      3. the address it asks for;
      4. a pool address never handed out, else the one free the longest.
    • Reserved addresses are never handed out to anyone else, even inside
      a pool.
    • Leases are kept in SQLite and saved before the ACK is sent. Ended
      ones stay 30 days, so returning clients get their address again.
    • Conflict checks:
      • An address is pinged before it is offered, and one that answers is
        held back.
      • An address a client declines is held back for a day.
      • Both use the decline_hold setting.
    • Authority: a request for an address that doesn't belong on the
      interface gets a NAK, so the client starts over at once. This can be
      turned off when another server shares a network.
    • Options:
      • 27 by name (routers, domain-name-servers, domain-search,
        ntp-servers, classless-static-route, …), and any other by number
        with a type.
      • Set globally, per subnet and per reservation, the most specific
        winning.
      • When a client sends a parameter request list, it gets what it asked
        for, in that order.
    • Configuration changes:
      • Validated as a whole, with stable problem codes (docs/validation.md).
      • Saved with a history entry, and can be undone after a check that
        nothing changed since.
      • ?dry_run=1 (or steward -n) previews a change.
    • REST API (docs/api.md):
      • users, sessions with CSRF protection, and API tokens limited by role
        or grant (config, leases, audit);
      • an audit log;
      • a local unix socket where root needs no token.
    • CLI steward (docs/cli.md):
      • commands: status, subnet, reservation, lease, activity, settings,
        option, interface, history (with undo), import kea, user, token,
        password, audit, config;
      • output as tables, JSON, YAML or IDs.
    • Web UI:
      • a dashboard of interfaces, pool use, problems and recent messages;
      • subnets with their leases, reservations and settings;
      • leases, with reserve and delete;
      • reservations;
      • live DHCP activity;
      • settings and global options;
      • history with undo, the audit log, users and tokens.
      • A new subnet suggests its network and a pool from the interface's
        address.
    • Kea import: steward import kea (POST /import/kea) reads a
      kea-dhcp4.conf and its lease files (docs/kea.md):
      • global, shared-network and subnet options, pools, lease times and
        reservations;
      • each subnet's interface: Kea's, else the host's interface with an
        address in the subnet, else --interface PREFIX=IFACE.
      • It lists what it doesn't support instead of dropping it silently.
      • Importing again keeps subnets' and reservations' IDs and Steward's
        subnet names.
    • stewardd commands: init (asks for the administrator's name),
      user add|password|token, check, backup (with pruning), restore,
      config --example.
    • The web UI's certificate from Let's Encrypt, through Jarl
      (docs/certificates.md, docs/jarl.md):
      • tls.acme in steward.yaml names the certificate, and jarl: the
        Jarl server and a token that may only write the challenge record.
      • Steward gets the certificate with the DNS-01 challenge, writing the
        record through Jarl's API into every view that has the zone.
      • It renews with a third of the lifetime left, and swaps the new
        certificate in without a restart.
      • A check runs before every order, and on demand: Jarl, the zone, the
        token's permission, a test record, the zone's public name servers and
        public resolvers, clean-up. Each step says what to fix.
      • It starts with Let's Encrypt's staging service by default.
      • steward cert, cert check, cert renew; Server → Certificate in the
        web UI; GET /certificate, POST /certificate/check|renew.
      • Dashboard problems: certificate_failed, certificate_expiring,
        certificate_staging.
    • HTTPS and plain HTTP on one port: with a certificate, plain HTTP is
      redirected to HTTPS, except from the server itself (also for
      tls.cert_file).
    • Disabled reservations (steward reservation disable|enable, Disable
      in the web UI): kept but ignored, so the client gets a pool address like
      any other. Subnets get Disable/Enable buttons in the web UI too.
    • Hidden interfaces: interfaces.exclude in steward.yaml (names or
      shell patterns such as docker*) leaves interfaces out of the web UI's
      interface picker, steward interface list and GET /interfaces.
    • Last seen: with the ping check on, active leases' addresses are
      pinged every minute, and a client that answers gets a last-seen time
      (Leases page, reservations' online badge, steward lease list|show,
      steward reservation list|show, last_seen in the API). A client that
      blocks pings stays online for as long as its lease lasts, without one.
    • The Reservations page refreshes itself every 15 seconds, so online
      and last seen stay current.
    • Activity by subnet: steward activity --subnet, a subnet filter on
      the Activity page, GET /events?subnet= (ID, name or prefix).
    • Address order (docs/subnets.md): which never-used pool address a
      new client gets, sequential (the lowest, as before), reverse or
      random, in the settings, a subnet (--address-order) or a single
      pool (--pool 10.0.10.200-10.0.10.250:random). A subnet's pools are
      used in the order listed, or one at random (--pool-order random),
      weighted by its never-used addresses. Pools now keep the order they are
      given in. Kea's allocator: random is imported.
    • Token rotation (steward token rotate, POST /tokens/{id}/rotate,
      Rotate in the web UI): a new secret for a token, with an optional grace
      period for the old one, as in Jarl.
    • Packaging:
      • a sandboxed systemd unit (steward.service, also stewardd.service)
        whose only privilege is CAP_NET_BIND_SERVICE;
      • a daily backup timer, and sysusers and tmpfiles files;
      • Debian packages steward and steward-cli, and a Gitea release
        workflow.
    • The Steward logo: a key whose bow is a crown with Jarl's network
      nodes, in Jarl's blue and white, with a STEWARD wordmark in Jarl's
      letters.
    Downloads
  • Steward v0.1.0-dev
    release / release (push) Successful in 5m53s
    Pre-Release

    adam released this 2026-10-14 17:15:39 +00:00 | -4 commits to main since this release

    The first version of Steward, a DHCPv4 server with a web UI, a REST API
    and a CLI, built the way Jarl is.

    Added

    • DHCPv4 server (stewardd serve):
      • Answers DISCOVER, REQUEST (selecting, init-reboot, renewing,
        rebinding), DECLINE, RELEASE and INFORM, as RFC 2131 describes.
      • Serves each subnet on its own network interface, with a socket per
        interface bound to it, so a VLAN's clients only get that VLAN's
        addresses.
      • Several subnets on one interface are served together, as a shared
        network.
      • Opens an interface's socket when the interface appears, such as a
        VLAN that comes up later, and closes it when its last subnet goes.
    • Address choice, in this order:
      1. the client's reservation;
      2. the address it had before;
      3. the address it asks for;
      4. a pool address never handed out, else the one free the longest.
    • Reserved addresses are never handed out to anyone else, even inside
      a pool.
    • Leases are kept in SQLite and saved before the ACK is sent. Ended
      ones stay 30 days, so returning clients get their address again.
    • Conflict checks:
      • An address is pinged before it is offered, and one that answers is
        held back.
      • An address a client declines is held back for a day.
      • Both use the decline_hold setting.
    • Authority: a request for an address that doesn't belong on the
      interface gets a NAK, so the client starts over at once. This can be
      turned off when another server shares a network.
    • Options:
      • 27 by name (routers, domain-name-servers, domain-search,
        ntp-servers, classless-static-route, …), and any other by number
        with a type.
      • Set globally, per subnet and per reservation, the most specific
        winning.
      • When a client sends a parameter request list, it gets what it asked
        for, in that order.
    • Configuration changes:
      • Validated as a whole, with stable problem codes (docs/validation.md).
      • Saved with a history entry, and can be undone after a check that
        nothing changed since.
      • ?dry_run=1 (or steward -n) previews a change.
    • REST API (docs/api.md):
      • users, sessions with CSRF protection, and API tokens limited by role
        or grant (config, leases, audit);
      • an audit log;
      • a local unix socket where root needs no token.
    • CLI steward (docs/cli.md):
      • commands: status, subnet, reservation, lease, activity, settings,
        option, interface, history (with undo), import kea, user, token,
        password, audit, config;
      • output as tables, JSON, YAML or IDs.
    • Web UI:
      • a dashboard of interfaces, pool use, problems and recent messages;
      • subnets with their leases, reservations and settings;
      • leases, with reserve and delete;
      • reservations;
      • live DHCP activity;
      • settings and global options;
      • history with undo, the audit log, users and tokens.
      • A new subnet suggests its network and a pool from the interface's
        address.
    • Kea import: steward import kea (POST /import/kea) reads a
      kea-dhcp4.conf and its lease files (docs/kea.md):
      • global, shared-network and subnet options, pools, lease times and
        reservations;
      • each subnet's interface: Kea's, else the host's interface with an
        address in the subnet, else --interface PREFIX=IFACE.
      • It lists what it doesn't support instead of dropping it silently.
      • Importing again keeps subnets' and reservations' IDs and Steward's
        subnet names.
    • stewardd commands: init (asks for the administrator's name),
      user add|password|token, check, backup (with pruning), restore,
      config --example.
    • The web UI's certificate from Let's Encrypt, through Jarl
      (docs/certificates.md, docs/jarl.md):
      • tls.acme in steward.yaml names the certificate, and jarl: the
        Jarl server and a token that may only write the challenge record.
      • Steward gets the certificate with the DNS-01 challenge, writing the
        record through Jarl's API into every view that has the zone.
      • It renews with a third of the lifetime left, and swaps the new
        certificate in without a restart.
      • A check runs before every order, and on demand: Jarl, the zone, the
        token's permission, a test record, the zone's public name servers and
        public resolvers, clean-up. Each step says what to fix.
      • It starts with Let's Encrypt's staging service by default.
      • steward cert, cert check, cert renew; Server → Certificate in the
        web UI; GET /certificate, POST /certificate/check|renew.
      • Dashboard problems: certificate_failed, certificate_expiring,
        certificate_staging.
    • HTTPS and plain HTTP on one port: with a certificate, plain HTTP is
      redirected to HTTPS, except from the server itself (also for
      tls.cert_file).
    • Disabled reservations (steward reservation disable|enable, Disable
      in the web UI): kept but ignored, so the client gets a pool address like
      any other. Subnets get Disable/Enable buttons in the web UI too.
    • Token rotation (steward token rotate, POST /tokens/{id}/rotate,
      Rotate in the web UI): a new secret for a token, with an optional grace
      period for the old one, as in Jarl.
    • Packaging:
      • a sandboxed systemd unit (steward.service, also stewardd.service)
        whose only privilege is CAP_NET_BIND_SERVICE;
      • a daily backup timer, and sysusers and tmpfiles files;
      • Debian packages steward and steward-cli, and a Gitea release
        workflow.
    • The Steward logo: a key whose bow is a crown with Jarl's network
      nodes, in Jarl's blue and white, with a STEWARD wordmark in Jarl's
      letters.
    Downloads