Skip to main content

bindantic

PyPI version Python versions License CI Coverage Docs PyPI Downloads

bindantic is a library for managing BIND9 DNS server configuration via Pydantic models.

Instead of manually editing named.conf, you describe the configuration in Python, and the library generates correct BIND9 syntax and (optionally) places files into the required directories.

Table of contents

Features

  • Full support for all named.conf blocks - acl, controls, dnssec-policy, http, key, key-store, logging, options, remote-servers, server, statistics-channels, tls, trust-anchors, view, zone.
  • All common resource record types - A, AAAA, CAA, CERT, CNAME, DNAME, DNSKEY, DS, HINFO, LOC, MX, NAPTR, NSEC, NS, PTR, RP, RRSIG, SOA, SPF, SRV, SSHFP, TLSA, TXT.
  • Built-in validation - pass strings, numbers, IP addresses, durations, and bindantic formats them correctly for BIND.
  • Validated against a real BIND9, not just unit tests on strings - CI generates configuration for every block and resource record type and runs it through a real named-checkconf, so the output isn't just "what we believe BIND9 syntax looks like."
  • Syntax generation in one line - model.model_bind_syntax() for any block or the whole named.conf, zone.model_bind_syntax_zone_file() for a ready-to-use zone file.
  • Generate files without writing, or write straight to disk - config.generate_files() returns a list of generated files; config.write_files("./my_config") creates named.conf, zones, keys, and DNSSEC policies, organised into subdirectories.
  • Python 3.10+, static typing (py.typed), 97%+ test coverage.
  • No extra dependencies - only Pydantic.

Installation

pip install bindantic

[!WARNING] named-checkconf version: bindantic generates syntax according to the latest stable BIND 9.20.x release. The named-checkconf utility from your distro's bind9-utils/bind-utils package may be several minor versions older than that and reject directives it doesn't recognize yet (this project's own CI hit exactly that with an outdated apt package - see CHANGELOG.md). Always check generated configuration with the same named-checkconf version as your production server, if possible.

Quick start

Example of a minimal configuration:

from bindantic import (
    ARecord,
    NamedConfig,
    NSRecord,
    OptionsBlock,
    SOARecord,
    ZoneBlock,
    ZoneTypeEnum,
)

config = NamedConfig(
    options_block=OptionsBlock(
        directory="/etc/bind",
        recursion=True,
        allow_recursion=["localhost", "localnets"],
        listen_on=["any"],
        listen_on_v6=["any"],
    ),
    zone_blocks=[
        ZoneBlock(
            comment="optional comment",
            name="example.com",
            zone_type=ZoneTypeEnum.PRIMARY,
            file="zones/example.com.zone",
            resource_records=[
                SOARecord(
                    mname="ns1.example.com",
                    rname="admin.example.com",
                    serial=2026010101,
                    refresh=10800,
                    retry=3600,
                    expire=604800,
                    minimum=3600,
                    origin="example.com",
                    ttl=3600,
                ),
                NSRecord(nsdname="ns1.example.com", comment="optional comment"),
                ARecord(name="@", address="192.168.1.1"),
            ],
        )
    ],
)
Output of config.model_bind_syntax()
options {
    allow-recursion {
        localhost;
        localnets;
    };
    directory "/etc/bind";
    listen-on {
        any;
    };
    listen-on-v6 {
        any;
    };
    recursion yes;
};

# optional comment
zone example.com. {
    type primary;
    file "zones/example.com.zone";
};
Output of config.zone_blocks[0].model_bind_syntax_zone_file()
$TTL 3600
$ORIGIN example.com.
@                                                IN   SOA ns1.example.com. admin.example.com. (
                                                                 2026010101 ; Serial number (YYYYMMDDNN)
                                                                 10800      ; Refresh time
                                                                 3600       ; Retry time
                                                                 604800     ; Expire time
                                                                 3600       ; Minimum TTL
                                                      )
@                                                IN   NS         ns1.example.com. ; optional comment
@                                                IN   A          192.168.1.1
Output of config.generate_files()
[
    GeneratedFile(
        path=PosixPath("/etc/bind/zones/example.com.zone"),
        content="<CONTENT>",
        type="zone",
    ),
    GeneratedFile(
        path=PosixPath("/etc/bind/named.conf"),
        content="<CONTENT>",
        type="config",
    ),
]
Output of config.write_files(base_dir="./my_config")
my_config/
├── named.conf
└── zones/
    └── example.com.zone

named.conf (directory is rewritten to the base_dir you actually pass in):

# Automatically generated by bindantic - please adjust!

options {
    allow-recursion {
        localhost;
        localnets;
    };
    directory "my_config";
    listen-on {
        any;
    };
    listen-on-v6 {
        any;
    };
    recursion yes;
};

# optional comment
zone example.com. {
    type primary;
    file "zones/example.com.zone";
};

zones/example.com.zone is identical to the model_bind_syntax_zone_file() output above.

More examples

Focused, runnable scripts for common real-world setups - see also Examples in the documentation:

Documentation

Full documentation, including an exhaustive per-field API reference generated from the models themselves, is at DVSAWR.github.io/bindantic.

Contributing

Contributions are welcome - see CONTRIBUTING.md for the development setup and workflow. Please review the Code of Conduct before participating, and see SECURITY.md to report a security issue privately instead of opening a public one.

Versioning

bindantic follows Semantic Versioning.

  • Public API - everything importable from the top-level bindantic package (models, enums, field type aliases) is covered by semver guarantees.
  • Internal - any module prefixed with _ (e.g. bindantic._base_model, bindantic._base_types_validation) is an implementation detail and may change without notice.
  • Major - removing/renaming a public model or field, or a change that makes previously valid input invalid, or a change to the generated BIND syntax output.
  • Minor - new models, new optional fields, support for new BIND directives.
  • Patch - bug fixes that don't change the public API surface.

bindantic targets the latest stable BIND 9.20.x release; tracking a new BIND directive is treated as a minor bump unless it conflicts with existing behavior.

See CHANGELOG.md for the release history.

License

MIT - see LICENSE.

Release files for bindantic 2.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bindantic 2.0.0
File Size Uploaded
bindantic-2.0.0.tar.gz 60.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for bindantic 2.0.0
File Interpreter ABI Platform
bindantic-2.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 128.0 kB

Release files / bindantic-2.0.0.tar.gz

Download URL bindantic-2.0.0.tar.gz
Size 60.4 kB
Tags Source
SHA-256 checksum
How to use checksums
ef63613fe8a805c8be62f08bfda9e1ecaac8838490354202d05dee965ea932c5
BLAKE2b-256 checksum
How to use checksums
8f7bda6aef6e005e9808c9f7e1252e8bec1f70caebb1552b707d172ff177bd74
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 2, 2026.

Transparency log

Release files / bindantic-2.0.0-py3-none-any.whl

Download URL bindantic-2.0.0-py3-none-any.whl
Size 67.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c8b25bc10440bbac8c8ca445dfde5604357c216ce7411b5140be31771eeae387
BLAKE2b-256 checksum
How to use checksums
644be1a1909cd8365936deffc571376242e39f9593d8e9ae3a4f3e96f1132c68
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 2, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

2.0.0 This release

2 release files

1.0.0

2 release files

0.9.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page