- Go 96.2%
- Just 3.8%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| .forgejo | ||
| cmd | ||
| internal | ||
| .gitignore | ||
| .golangci.yml | ||
| .goreleaser.yaml | ||
| go.mod | ||
| go.sum | ||
| Justfile | ||
| README.md | ||
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
dnsprovider);setreplaces 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