How to Configure BIND with MySQL Backend for Dynamic DNS Zone Updates


11 views

Migrating from Windows-based DNS servers to Linux often requires dynamic DNS updates without restarting BIND. The most efficient approach is using a database backend like MySQL with DLZ (Dynamically Loadable Zones) support. Here's a comprehensive guide to set it up correctly.

First, download and compile BIND with MySQL DLZ patches:

wget https://downloads.isc.org/isc/bind9/9.16.15/bind-9.16.15.tar.gz
tar xvf bind-9.16.15.tar.gz
cd bind-9.16.15
patch -p1 < bind-mysql.patch
./configure --prefix=/usr --sysconfdir=/etc/bind --localstatedir=/var \
--enable-threads --enable-largefile --with-libtool --enable-shared \
--enable-static --with-openssl --with-gssapi --with-libxml2 \
--with-dlz-mysql=/usr
make
sudo make install

Create the database schema for DNS records:

CREATE DATABASE bind;
USE bind;
CREATE TABLE dns_records (
    zone VARCHAR(255) NOT NULL,
    host VARCHAR(255) NOT NULL,
    ttl INT DEFAULT NULL,
    type VARCHAR(10) DEFAULT NULL,
    mx_priority INT DEFAULT NULL,
    data VARCHAR(255) DEFAULT NULL,
    resp_person VARCHAR(255) DEFAULT NULL,
    serial INT DEFAULT NULL,
    refresh INT DEFAULT NULL,
    expire INT DEFAULT NULL,
    minimum INT DEFAULT NULL,
    PRIMARY KEY (zone,host)
);

Configure /etc/named.conf for MySQL backend:

options {
    directory "/var/named";
    allow-query { any; };
};

dlz "MySQL zone" {
    database "mysql
    {host=localhost dbname=bind user=bind_user pass=password}
    {SELECT zone FROM dns_records WHERE zone = '$zone$'}
    {SELECT ttl, type, mx_priority, 
     CASE WHEN type='TXT' THEN CONCAT('\"', data, '\"')
          WHEN type='SOA' THEN CONCAT(data, ' ', resp_person, ' ', 
               serial, ' ', refresh, ' ', retry, ' ', expire, ' ', minimum)
          ELSE data END
     FROM dns_records 
     WHERE zone = '$zone$' AND host = '$record$'}";
};

Create a systemd service file at /etc/systemd/system/named.service:

[Unit]
Description=BIND Domain Name Server
After=network.target

[Service]
ExecStart=/usr/sbin/named -f -4
ExecReload=/bin/kill -HUP $MAINPID
Restart=always

[Install]
WantedBy=multi-user.target

Verify your setup with these commands:

named-checkconf /etc/named.conf
systemctl start named
dig @localhost my.cloud SOA
  • Check /var/log/messages for BIND errors
  • Verify MySQL connection permissions
  • Test SQL queries directly in MySQL client
  • Ensure SELinux contexts are correct if enabled

Migrating from Windows DNS to Linux while maintaining dynamic zone updates requires a robust solution. The traditional zone file approach requires service restarts - a dealbreaker for production environments. Here's how to implement BIND with database backend properly:

For Amazon Linux/RHEL systems:

# MySQL version
sudo yum install -y bind bind-sdb bind-utils mysql mysql-server

# PostgreSQL alternative
sudo yum install -y bind bind-sdb bind-utils postgresql postgresql-server

First, compile BIND with MySQL support (if using custom build):

./configure --with-dlz-mysql
make
sudo make install

Then configure /etc/named.conf:

dlz "mysql-zone" {
    database "mysql
    {host=localhost dbname=bind user=bind password=securepass}
    {SELECT zone FROM dns_records WHERE zone = '$zone$'}
    {SELECT ttl, type, mx_priority, data, resp_person, 
     serial, refresh, retry, expire, minimum 
     FROM dns_records 
     WHERE zone = '$zone$' AND host = '$record$'}";
};

Essential MySQL table structure:

CREATE TABLE dns_records (
    zone VARCHAR(255) NOT NULL,
    host VARCHAR(255) NOT NULL,
    ttl INT DEFAULT 3600,
    type VARCHAR(10) NOT NULL,
    mx_priority INT DEFAULT NULL,
    data VARCHAR(255) DEFAULT NULL,
    resp_person VARCHAR(255) DEFAULT NULL,
    serial BIGINT DEFAULT 1,
    refresh INT DEFAULT 28800,
    retry INT DEFAULT 7200,
    expire INT DEFAULT 86400,
    minimum INT DEFAULT 28800,
    PRIMARY KEY (zone,host,type)
);

1. Service not starting: Check paths in systemd unit file or init script:
ExecStart=/usr/local/sbin/named -f -4 -c /etc/named.conf

2. Permission problems: Ensure DB user has proper grants:
GRANT SELECT ON bind.* TO 'bind'@'localhost' IDENTIFIED BY 'securepass';

3. Configuration validation: Always test with:
named-checkconf /etc/named.conf

For programmatic updates, create stored procedures:

DELIMITER //
CREATE PROCEDURE add_record(
    IN p_zone VARCHAR(255),
    IN p_host VARCHAR(255),
    IN p_type VARCHAR(10),
    IN p_data VARCHAR(255)
)
BEGIN
    REPLACE INTO dns_records (zone, host, type, data)
    VALUES (p_zone, p_host, p_type, p_data);
END //
DELIMITER ;

Then call from application code without restarting BIND.