ChangeLog: v1.2 - modified Slave Configuration #4. Instead of copying and deleting the incoming file, we just move the new file over. This keeps us from renaming and deleting it, which jlasman proposed. I think this method effectively solves the problem he posed in one of his replies below.
v1.1 - modifed Slave Configuration #4. Use named stop and named start instead of just name restart.
- modified the Mater Configuration #5. Moved the "rm" statement from the "start()" function to the "restart()" function.
- changes were made so that if you use two name servers, and each one is a slave for the other, you don't wind up with an infinite loop of restarts.
A lot of us have been looking for a way to automate our DNS updates. Many of us run several servers and maybe use some of these servers as "slaves". Personally, I use one server as a slave (ns2) to my other master DNS servers. Trying to keep these in sync has been an excercise in futility. I have come up with a way to have your master servers automatically add new domains to the slave(s). It's a push/pull system and requires a few cron entries to work properly.
First off, we need to get our files a little more organized for this.
We will configure the slave server first. I writing this HOWTO with only a single slave in mind. Simply repeat the process for multiple slaves. If you are attempting to follow this HOWTO, it is assumed you would know how to do this
Slave Configuration
1. Create a directory to hold the slave files
Normally, all your zone files are tossed into the /var/named directory. That is fine for the zone files for which this server is the master, if there are any. However, to keep things clean, we want to seperate all the zone files we are slaving. So first, we need to create a directory for the master server. You should create one for each master server this slave server is a slave for. In my case, ns2.protollix.com is a slave for ns1.protollix.com. So I shell into the ns2 machine and su to root. I then execute the following commands:
2. Modify your /etc/named.conf file
Next, we need to tell BIND where to find the zone files. Basically what we are doing, is storing the zone lines in a seperate file so we can just include the file into our master named.conf file. So, what you need to do is BACKUP THIS FILE.
Next, remove any slave lines from this file for the master server we are configuring. You probably only need to do this if you were maintaining a master/slave relationship by hand.
Then, you need to add a line to tell BIND to include a configuration file. I am using my file as an example. Add (probably at the end of the file)
You can save and close this file.
3. Setup a user account to store the config files
I removed this section as you also must add the user somewhere else so he can ftp in. I don't have time to figure that out
You can use the user "admin" for this. I have changed the directories below to reference the admin's home dir for now.
4. Create the pull script and add it to cron
Create the below shell script and save it somewhere. I put scripts like this in /usr/local/sbin.
This script was written on RedHat EL 3.0 system. /etc/init.d/named refers to a BIND startup script. If you are on Debian or FreeBSD or something else, you might have a different startup script placed elsewhere.
Don't worry if these seems a little confusing, since we have created the push script to create the file we are pulling with this script. It should all become clear at the end.
Basically, what this script does is:
1. checks to see if a new slave config file exists
2. if it does, it copies to where BIND expects it to be and changes the ownership of the file to the right user/group
3. we then restart BIND and remove the uploaded file so we don't reload BIND every time the script runs
Next, add this to cron. I execute it once per minute.
then insert:
Obviously, "copy_slaves_config.sh" is the filename I chose. You can use whatever you wish. Just make sure you have made the file executable. If you have not done that yet then issue:
We are now done with the slave configuration.
Master Configuration
1. Intro and Directories
First things first, since you probably already have several domains on this server, we need to clean up the named.conf file and also tell DA to use the proper notify settings when creating new zone files. So go ahead and SSH into your master server and su to root.
We need to keep things clean and organized here too. issue the following (salt to taste):
2. Configure DA to use a new zone line
We need to use a custom template here:
Next, we need to modify this custom template. Edit /usr/local/directadmin/data/templates/custom/zone.conf with your favorite editor and change the one line in there to this (replace the IP address with the IP address(es) of your slave server(s))
(replace 12.12.12.12 with the IP of you slave server)
Save the file and close your editor.
3. Clean up the named.conf file
What I did was write a PHP script that grabs the domains DA says is hosted on the server, and write a new line to the named.conf file. You need to remove *all* master lines from this file first otherwise we will end up with duplicate lines, and BIND will whine! BACKUP YOUR named.conf FILE NOW. DO NOT SKIP THE BACKUP! We need to backup the file incase something gets hosed up.
So go ahead and delete all the master lines from the named.conf file. I could have added something in the below script to do this auotmatically, but I didn't. Namely because I had some zones that DA didn't know about yet. Here is the PHP script to grab the list of domains and stick the proper lines back into the named.conf file:
Replace 12.12.12.12 with the IP address of your Slave server.
go ahead and execute that script. I named it rewrite_named_conf.php and saved it in /usr/local/sbin. so I would issue the following command:
Open up /etc/named.conf and verify your domains are there!
4. Setup the push script and add it to cron
Sweet, we are almost done!
Next thing we need to do is create the script that will write the slave configuration file and push it to the slave server.
I create the below php file as /usr/local/sbin/push_to_slave.php
Replace 12.12.12.12 with the IP address of this master nameserver.
Next, add this script to cron. I run it every minute. You can run it less frequently if you don't have a lot of DNS changes going on.
paste in:
if the path to your php binary is different, please replace that path with what it is on your system.
5. Modify the BIND startup script
The below is for a RedHat EL 3.0 system. If you are on a different OS, you will probably need to modify a different file.
We need to edit the named init.d script to tell it to delete the slave config file when we restart BIND so our push script knows that it needs to rewrite the config file. We could make the script smarter to only upload a new file when a domain has been added or deleted, but that is outside the scope of this HOWTO.
Open /etc/init.d/named in your favorite text editor. Find this section (yours might vary slightly. The important thing is to find the "restart() function):
Right after the last echo statement, add the following:
It shoud now resemble:
save the file and close the editor.
Conclusion
You should now be good to go. Every time your master server adds a new zone file, or modifies a zone file and restarts BIND, it will notify the slave that it needs to pull the new record. It will also automatically configure the slave server, telling the slave that it indeed should be slave for the domains on the master server.
NOTE/Indemnification
I wrote this after setting this up on my own systems. It is possible I have left out something. By following this HOWTO you agree that if your configuration becomes corrupt, it doesn't work as expected, your head explodes or anything else occurs, that you will not hold the author of this HOWTO, Sean Finkel, responsible for said damages. This is a "do it at your own risk" HOWTO. Please proceed with caution, and only if you know what you are doing.
On a more positive note
If you notice any typos or other errors, please let me know and I will edit this HOWTO.
I hope this HOWTO helps some of you that have been clamoring for master/slave clustering!
JOHN
I know you are reading this
Maybe you can add this to DA as the master/slave clustering for DNS. Obviously, it would need some changes, but I think it could be a decent base system to start with!
Also, can we get a config rewrite for the task queue that rewrites the named.conf file?
v1.1 - modifed Slave Configuration #4. Use named stop and named start instead of just name restart.
- modified the Mater Configuration #5. Moved the "rm" statement from the "start()" function to the "restart()" function.
- changes were made so that if you use two name servers, and each one is a slave for the other, you don't wind up with an infinite loop of restarts.
A lot of us have been looking for a way to automate our DNS updates. Many of us run several servers and maybe use some of these servers as "slaves". Personally, I use one server as a slave (ns2) to my other master DNS servers. Trying to keep these in sync has been an excercise in futility. I have come up with a way to have your master servers automatically add new domains to the slave(s). It's a push/pull system and requires a few cron entries to work properly.
First off, we need to get our files a little more organized for this.
We will configure the slave server first. I writing this HOWTO with only a single slave in mind. Simply repeat the process for multiple slaves. If you are attempting to follow this HOWTO, it is assumed you would know how to do this

Slave Configuration
1. Create a directory to hold the slave files
Normally, all your zone files are tossed into the /var/named directory. That is fine for the zone files for which this server is the master, if there are any. However, to keep things clean, we want to seperate all the zone files we are slaving. So first, we need to create a directory for the master server. You should create one for each master server this slave server is a slave for. In my case, ns2.protollix.com is a slave for ns1.protollix.com. So I shell into the ns2 machine and su to root. I then execute the following commands:
Code:
mkdir /var/named/ns1
chown named.named /var/named/ns1
2. Modify your /etc/named.conf file
Next, we need to tell BIND where to find the zone files. Basically what we are doing, is storing the zone lines in a seperate file so we can just include the file into our master named.conf file. So, what you need to do is BACKUP THIS FILE.
Code:
cp /etc/named.conf /etc/named.conf.bak
Next, remove any slave lines from this file for the master server we are configuring. You probably only need to do this if you were maintaining a master/slave relationship by hand.
Then, you need to add a line to tell BIND to include a configuration file. I am using my file as an example. Add (probably at the end of the file)
Code:
include "/var/named/ns1/ns1.protollix.com.txt";
You can save and close this file.
3. Setup a user account to store the config files
I removed this section as you also must add the user somewhere else so he can ftp in. I don't have time to figure that out

4. Create the pull script and add it to cron
Create the below shell script and save it somewhere. I put scripts like this in /usr/local/sbin.
This script was written on RedHat EL 3.0 system. /etc/init.d/named refers to a BIND startup script. If you are on Debian or FreeBSD or something else, you might have a different startup script placed elsewhere.
Code:
#!/bin/sh
if [ -f "/home/admin/named/ns1.protollix.com.txt" ] ; then
/bin/mv -f /home/admin/named/ns1.protollix.com.txt /var/named/ns1/ns1.protollix.com.txt
chown named.named /var/named/ns1/ns1.protollix.com.txt
/etc/init.d/named stop
/etc/init.d/named start
Don't worry if these seems a little confusing, since we have created the push script to create the file we are pulling with this script. It should all become clear at the end.
Basically, what this script does is:
1. checks to see if a new slave config file exists
2. if it does, it copies to where BIND expects it to be and changes the ownership of the file to the right user/group
3. we then restart BIND and remove the uploaded file so we don't reload BIND every time the script runs
Next, add this to cron. I execute it once per minute.
Code:
crontab -e
then insert:
Code:
*/1 * * * * /usr/local/sbin/copy_slave_configs.sh
Code:
chmod 700 /usr/local/sbin/copy_slave_configs.sh
We are now done with the slave configuration.
Master Configuration
1. Intro and Directories
First things first, since you probably already have several domains on this server, we need to clean up the named.conf file and also tell DA to use the proper notify settings when creating new zone files. So go ahead and SSH into your master server and su to root.
We need to keep things clean and organized here too. issue the following (salt to taste):
Code:
mkdir /var/named/pushtoslave
chown named.named /var/named/pushtoslave
2. Configure DA to use a new zone line
We need to use a custom template here:
Code:
cd /usr/local/directadmin/data/templates
cp zone.conf custom
chown diradmin.diradmin custom/zone.conf
Code:
zone "|DOMAIN|" { type master; file "|PATH|/|DOMAIN|.db"; notify yes; also-notify {12.12.12.12;}; };
Save the file and close your editor.
3. Clean up the named.conf file
What I did was write a PHP script that grabs the domains DA says is hosted on the server, and write a new line to the named.conf file. You need to remove *all* master lines from this file first otherwise we will end up with duplicate lines, and BIND will whine! BACKUP YOUR named.conf FILE NOW. DO NOT SKIP THE BACKUP! We need to backup the file incase something gets hosed up.
So go ahead and delete all the master lines from the named.conf file. I could have added something in the below script to do this auotmatically, but I didn't. Namely because I had some zones that DA didn't know about yet. Here is the PHP script to grab the list of domains and stick the proper lines back into the named.conf file:
PHP:
<?php
function getDomains() {
$domains = array();
// open the domains file for reading
$fp = @fopen('/etc/virtual/domains', 'r+');
while (!feof($fp)) {
$domains[] = str_replace("\n", "", fgets($fp));
}
fclose($fp);
asort($domains);
return $domains;
}
function writeDomains($domains) {
// for each domain, we create a new "zone" entry
foreach ($domains as $key=>$val) {
if (!empty($val))
$zone_string = "zone \"$val\" {type master; file \"/var/named/$val.db\"; notify yes; also-notify {12.12.12.12;}; };\r\n";
$correct_domains[] = $zone_string;
}
$fp = fopen('/etc/named.conf', 'a+');
foreach($correct_domains as $key=>$val) {
fwrite($fp, $val);
}
fclose($fp);
}
$domains = getDomains();
writeDomains($domains);
?>
go ahead and execute that script. I named it rewrite_named_conf.php and saved it in /usr/local/sbin. so I would issue the following command:
Code:
php /usr/local/sbin/rewrite_named_conf.php
Open up /etc/named.conf and verify your domains are there!
Code:
cat /etc/named.conf
4. Setup the push script and add it to cron
Sweet, we are almost done!
Next thing we need to do is create the script that will write the slave configuration file and push it to the slave server.
I create the below php file as /usr/local/sbin/push_to_slave.php
PHP:
<?php
function getDomains() {
$domains = array();
// open the domains file for reading
$fp = @fopen('/etc/virtual/domains', 'r+');
while (!feof($fp)) {
$domains[] = str_replace("\n", "", fgets($fp));
}
fclose($fp);
asort($domains);
return $domains;
}
function writeDomains($domains) {
// for each domain, we create a new "zone" entry
$fp = fopen('/var/named/pushtoslave/ns1.protollix.com.txt', 'w+');
foreach ($domains as $key=>$val) {
if (!empty($val))
$zone_string = "zone \"$val\" {type slave; masters {12.12.12.12;}; file \"/var/named/ns1/$val.db\"; };\r\n";
fwrite($fp, $zone_string);
}
fclose($fp);
}
function uploadFile() {
$conn = ftp_connect('ns2.protollix.com');
$login_result = ftp_login($conn, 'admin', 'password');
if (!$conn) {
die('Unable to upload named config');
}
$upload = ftp_put($conn, 'named/ns1.protollix.com.txt', '/var/named/pushtoslave/ns1.protollix.com.txt', FTP_ASCII);
if (!$upload) {
die('Error uploading file!');
}
ftp_close($conn);
}
// we only continue if the push file does not exist. If it does exist, then we have already pushed it since the last named restart
$test = @fopen('/var/named/pushtoslave/ns1.protollix.com.txt', 'r');
if (!$test) {
$domains = getDomains();
writeDomains($domains);
uploadFile();
}
?>
Replace 12.12.12.12 with the IP address of this master nameserver.
Next, add this script to cron. I run it every minute. You can run it less frequently if you don't have a lot of DNS changes going on.
Code:
crontab -e
Code:
*/1 * * * * /usr/local/bin/php /usr/local/sbin/push_to_slave.php
if the path to your php binary is different, please replace that path with what it is on your system.
5. Modify the BIND startup script
The below is for a RedHat EL 3.0 system. If you are on a different OS, you will probably need to modify a different file.
We need to edit the named init.d script to tell it to delete the slave config file when we restart BIND so our push script knows that it needs to rewrite the config file. We could make the script smarter to only upload a new file when a domain has been added or deleted, but that is outside the scope of this HOWTO.
Open /etc/init.d/named in your favorite text editor. Find this section (yours might vary slightly. The important thing is to find the "restart() function):
Code:
restart() {
stop();
start();
}
Right after the last echo statement, add the following:
Code:
/bin/rm -f /var/named/pushtoslave/ns1.protollix.com.txt
It shoud now resemble:
Code:
restart() {
stop();
start();
/bin/rm -f /var/named/pushtoslave/ns1.protollix.com.txt
}
save the file and close the editor.
Conclusion
You should now be good to go. Every time your master server adds a new zone file, or modifies a zone file and restarts BIND, it will notify the slave that it needs to pull the new record. It will also automatically configure the slave server, telling the slave that it indeed should be slave for the domains on the master server.
NOTE/Indemnification
I wrote this after setting this up on my own systems. It is possible I have left out something. By following this HOWTO you agree that if your configuration becomes corrupt, it doesn't work as expected, your head explodes or anything else occurs, that you will not hold the author of this HOWTO, Sean Finkel, responsible for said damages. This is a "do it at your own risk" HOWTO. Please proceed with caution, and only if you know what you are doing.
On a more positive note

If you notice any typos or other errors, please let me know and I will edit this HOWTO.
I hope this HOWTO helps some of you that have been clamoring for master/slave clustering!
JOHN
I know you are reading this

Maybe you can add this to DA as the master/slave clustering for DNS. Obviously, it would need some changes, but I think it could be a decent base system to start with!
Also, can we get a config rewrite for the task queue that rewrites the named.conf file?

Last edited: