Bindizr is a Rust-based DNS control plane that manages zones and records via an HTTP API or CLI, stores data in a database backend (MySQL, PostgreSQL, or SQLite), and propagates changes to BIND9 secondary servers via AXFR/IXFR using DNS Catalog Zones.
-
Control Plane: Manage DNS zones and records through HTTP API or CLI commands. All changes are stored in the database (MySQL, PostgreSQL, or SQLite).
-
XFR Server: Built-in AXFR (full zone transfer) and IXFR (incremental zone transfer) server that serves zone data to secondary DNS servers. SOA serial numbers are automatically incremented on each change.
-
Catalog Zones: Bindizr uses DNS Catalog Zones (RFC 9432) to automatically propagate zone configuration to BIND9 secondary servers. When you create or delete a zone via the API/CLI, BIND9 automatically discovers and configures it without manual intervention.
-
Secondary DNS Servers: Standard BIND9 (or any RFC-compliant DNS server) instances configured as secondaries. They automatically discover zones through the catalog zone, pull zone updates from Bindizr's XFR server via zone transfer, and respond to DNS queries from clients.
-
nsupdate (Dynamic Update): Supports RFC 2136-style DNS dynamic updates via nsupdate.
Bindizr can be deployed with Helm, Docker Compose for Docker Swarm, or a manual package-based setup.
Use the Helm chart to deploy Bindizr, BIND9 secondary pods, and optional bundled MySQL/PostgreSQL in Kubernetes.
For production, create a Kubernetes Secret that points Bindizr to your external MySQL or PostgreSQL database:
$ helm repo add bindizr https://kweonminsung.github.io/bindizr/charts
$ helm repo update
$ kubectl create secret generic bindizr-db-secret \
--from-literal=database-url='postgresql://user:password@postgresql:5432/bindizr'
$ helm install bindizr bindizr/bindizr-stack \
--set bindizr.database.existingSecret=bindizr-db-secretFor development, the chart can run a single-replica MySQL or PostgreSQL StatefulSet:
$ helm install bindizr bindizr/bindizr-stack \
--set bindizr.database.type=postgresql \
--set bindizr.database.existingSecret= \
--set postgresql.enabled=trueSQLite is not supported by the Helm chart. See charts/bindizr-stack for all Helm values and examples, including TSIG and bindizr-ui.
Use the default docker-compose.yml with Docker Swarm for a containerized Bindizr deployment.
$ docker stack deploy -c docker-compose.yml bindizrThe stack runs Bindizr, MySQL, and BIND9 on an overlay network, using Docker configs for BIND9 configuration.
For package-based installation on a VM or bare-metal host, follow the manual installation guide below. It installs BIND9, installs the Bindizr binary or package, configures BIND9 as a secondary using the catalog zone, and starts Bindizr as a system service.
Bindizr can read configuration from /etc/bindizr/bindizr.conf.toml and can also be configured with environment variables in container deployments. The Docker files in this repository set the same options through environment variables.
For manual installation, create the configuration file:
$ vim /etc/bindizr/bindizr.conf.toml # or use any text editor you preferAdd the following configuration, adjusting values to match your environment:
[api]
listen_addr = "127.0.0.1" # HTTP API listen address
listen_port = 3000 # HTTP API listen port
require_authentication = true # Enable API authentication (true/false)
[database]
type = "mysql" # Database type: mysql, sqlite, postgresql
[database.mysql]
server_url = "mysql://user:password@hostname:port/database" # Mysql server configuration
[database.sqlite]
file_path = "bindizr.db" # SQLite database file path
[database.postgresql]
server_url = "postgresql://user:password@hostname:port/database" # PostgreSQL server configuration
[dns]
listen_addr = "127.0.0.1" # DNS server listen address
listen_port = 53 # DNS server listen port (UDP and TCP)
secondary_addrs = "" # Comma-separated secondary DNS server addresses for NOTIFY (e.g., "192.168.1.2:53,192.168.1.3:53")
notify_after_update = true # Send DNS NOTIFY after zone changes
notify_on_startup = false # Send DNS NOTIFY when bindizr starts
notify_retries = 3 # Retry count after the initial NOTIFY attempt
notify_timeout_secs = 5 # Timeout in seconds for each NOTIFY send/response wait
nsupdate_tsig_key_name = "nsupdate-key" # TSIG key name for nsupdate authentication (name and key must both be set)
nsupdate_tsig_key = "" # Shared TSIG secret for nsupdate authentication (name and key must both be set, base64 recommended)
[logging]
log_level = "debug" # Log level: error, warn, info, debug, trace$ sudo apt-get update
$ sudo apt-get install sudo ufw dnsutils bind9$ sudo yum install bind bind-utilsYou can download the latest bindizr binary from Release.
For building from source, see the packaging documentation.
For Debian-based systems (Ubuntu, Debian, etc.), you can install Bindizr using the .deb package:
# Install using dpkg
$ sudo dpkg -i bindizr_0.1.0_amd64.deb
# Verify installation
$ bindizrFor Red Hat-based systems (Fedora, CentOS, RHEL, etc.), you can install Bindizr using the .rpm file:
# Install the .rpm package
$ sudo rpm -i bindizr_0.1.0_amd64.rpm
# Verify installation
$ bindizrWe provide two methods for configuring BIND: a recommended automated script and a manual setup.
This script automatically detects your BIND configuration directory and configures BIND to use Bindizr's catalog zone for automatic zone discovery.
# Download and run the setup script
$ wget -qO- https://raw.githubusercontent.com/kweonminsung/bindizr/main/packaging/scripts/setup_bind.sh | sudo bash
# Restart bind service
$ sudo systemctl restart bind9 # For Debian-based systems
$ sudo systemctl restart named # For Red Hat-based systemsAlternative: Manual Setup
First, set variables for your BIND configuration. The paths vary depending on your operating system.
- For Debian-based systems (e.g., Ubuntu):
$ BIND_CONF_FILE=/etc/bind/named.conf $ BIND_CACHE_DIR=/var/cache/bind
- For Red Hat-based systems (e.g., Fedora, CentOS):
$ BIND_CONF_FILE=/etc/named.conf $ BIND_CACHE_DIR=/var/named/slaves
Update your main BIND configuration file ($BIND_CONF_FILE) by adding the following:
# Configure catalog zone support
cat <<EOF | sudo tee -a "$BIND_CONF_FILE"
options {
allow-notify { any; };
ixfr-from-differences yes;
catalog-zones {
zone "catalog.bind" default-primaries { 127.0.0.1 port 53; };
};
};
EOF
# Add catalog zone as secondary
cat <<EOF | sudo tee -a "$BIND_CONF_FILE"
zone "catalog.bind" {
type secondary;
primaries { 127.0.0.1 port 53; };
file "$BIND_CACHE_DIR/catalog.bind.zone";
allow-notify { any; };
ixfr-from-differences yes;
};
EOFNote: The catalog.bind zone automatically manages all zones created in Bindizr. When you create a new zone via the API or CLI, BIND will automatically configure it as a secondary zone without requiring manual configuration.
After saving the changes, restart the BIND service:
# Restart bind service
$ sudo systemctl restart bind9 # For Debian-based systems
$ sudo systemctl restart named # For Red Hat-based systemsCreate /etc/bindizr/bindizr.conf.toml using the Bindizr Configuration section above, adjusting values to match your environment.
# Start Bindizr service
$ sudo systemctl enable bindizr
$ sudo systemctl start bindizr
# Create an API token for authentication
$ bindizr token createBindizr provides a command-line interface for managing the DNS synchronization service and API tokens.
# Start bindizr on foreground
$ bindizr start
# Start with a custom configuration file
$ bindizr start -c <FILE>
# Check the current status of bindizr service
$ bindizr status
# Send NOTIFY to secondary DNS servers for a zone
$ bindizr notify zone <ZONE_NAME>
# Show help information
$ bindizr --helpBindizr supports RFC 2136-style dynamic updates through the DNS listener.
$ nsupdate <<EOF
server 127.0.0.1 53
zone example.com
update add sub.example.com. 300 A 1.2.3.4
send
EOFBindizr uses API tokens for authentication. You can manage these tokens using the following commands:
# Create a new API token
$ bindizr token create --description "API access for monitoring"
# Create a token with expiration
$ bindizr token create --description "Temporary access" --expires-in-days 30
# List all API tokens
$ bindizr token list
# Delete an API token by ID
$ bindizr token delete <TOKEN_ID>
# Show token command help
$ bindizr token --helpThe full HTTP API documentation is available at:
👉 https://kweonminsung.github.io/bindizr/api/
When making API requests, include the token in the Authorization header:
$ curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:3000/zonesThis project relies on the following core dependencies:
axum– A web application framework for building fast and modular APIs in Rust.utoipa- Compile-time OpenAPI generation for Rust APIs.sqlx- An async, pure Rust SQL crate featuring compile-time checked queries without a DSL.
This project is licensed under the Apache License 2.0.

