No description
  • Go 96.2%
  • Just 3.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Kyle Mendell 2a7fca91d8
All checks were successful
Release / release (push) Successful in 11s
fix: audiance claim in workflow
2026-08-23 11:44:01 -05:00
.forgejo fix: audiance claim in workflow 2026-08-23 11:44:01 -05:00
cmd fix: migrate to urfave cli 2026-08-23 11:16:59 -05:00
internal fix: migrate to urfave cli 2026-08-23 11:16:59 -05:00
.gitignore initial commit 2026-07-19 16:43:12 -05:00
.golangci.yml initial commit 2026-07-19 16:43:12 -05:00
.goreleaser.yaml fix: audiance claim in workflow 2026-08-23 11:44:01 -05:00
go.mod fix: migrate to urfave cli 2026-08-23 11:16:59 -05:00
go.sum fix: migrate to urfave cli 2026-08-23 11:16:59 -05:00
Justfile initial commit 2026-07-19 16:43:12 -05:00
README.md fix: migrate to urfave cli 2026-08-23 11:16:59 -05:00

nsup

Manage DNS records on authoritative servers with TSIG-signed RFC 2136 dynamic updates — nsupdate with the UX of a modern CLI. Works against BIND, Knot, PowerDNS, and anything else that speaks dynamic updates.

  • View — TSIG-signed AXFR zone listing and single-rrset queries
  • Add / Set / Delete — rrset-granular dynamic updates (the same model as the Terraform dns provider); set replaces an rrset atomically
  • Named servers and TSIG keys in a config file, overridable by flags
  • Table or JSON output

Install

Download a binary from the releases, or:

go install forgejo.ofkm.us/ofkm/nsup/cmd/nsup@latest

With Homebrew, install it from OFKM's Forgejo-hosted tap:

brew tap ofkm/tap https://forgejo.ofkm.us/brew/tap.git
brew install --cask ofkm/tap/nsup

Configure

The quickest way is to let nsup write the config and mint a TSIG secret for you:

nsup config generate --address 10.0.0.53

This creates ~/.config/nsup/config.yaml (0600) with one server and a fresh random key, and prints the matching BIND key { } block to install on the server. --server-name, --key-name, --key-algo customize the entries; --key-secret (or $NSUP_TSIG_SECRET) reuses an existing secret instead of generating one. Tweak it later with nsup config edit (opens $EDITOR and validates the result) and check it any time with nsup config validate.

The file looks like this:

defaults:
  server: homelab   # used when --server is omitted
  ttl: 300

servers:
  homelab:
    address: 10.0.0.53        # port defaults to 53
    key: update-key           # default TSIG key for this server

keys:
  update-key:                 # the map name is the TSIG key name on the wire
    algorithm: hmac-sha256    # default; also hmac-sha1/224/384/512
    secret: bWVnYXNlY3JldA==  # base64, or secret_env: VAR, or secret_file: path

Generate a key on the server side with tsig-keygen update-key (BIND) and grant it update rights, e.g. update-policy { grant update-key zonesub ANY; };.

No config file? Everything works from flags:

NSUP_TSIG_SECRET=bWVnYXNlY3JldA== \
  nsup -s 10.0.0.53 --key-name update-key list example.internal

Use

nsup list example.internal                 # whole zone (AXFR)
nsup list example.internal --type A
nsup get www.example.internal          # every record at a name
nsup get www.example.internal A        # just one type

nsup add www.example.internal A 10.0.0.5 10.0.0.6 --ttl 300
nsup set www.example.internal A 10.0.0.7   # replace the rrset atomically
nsup add example.internal MX "10 mail.example.internal."   # apex record
nsup add _sip._tcp.example.internal SRV "10 60 5060 sip.example.internal."
nsup set 5.0.0.10.in-addr.arpa PTR www.example.internal.

nsup delete www.example.internal              # shows what's there, pick what to delete
nsup delete www.example.internal A            # the whole rrset
nsup delete www.example.internal A 10.0.0.5   # one specific record
nsup delete www.example.internal --yes        # everything at the name, no prompt

nsup config validate
nsup list example.internal -o json

Conventions:

  • Commands take full names (www.example.internal) — nsup discovers the enclosing zone automatically, so there is no separate zone argument. For apex records, use the zone name itself.
  • Multi-field values (MX, SRV) are one quoted argument in zone-file order.
  • Target names in record data (CNAME/MX/NS/PTR/SRV) must be fully qualified (end with .) — nsup refuses to guess an origin for them.
  • Supported types for mutations: A, AAAA, CNAME, MX, NS, PTR, SRV, TXT.

Exit codes

Code Meaning
0 success
1 user error or nothing found
2 server or transport failure (REFUSED, BADSIG, timeout, ...)

Develop

just build    # bin/nsup
just check    # format + lint + test
just release  # conventional-commit version bump, tag, push