How to lower TTL just before an IP change

DirectAdmin provides the ability to edit users' TTL values via the panel: User Level -> DNS Management -> TTL (bottom):
http://www.directadmin.com/features.php?id=1130open in new window

Global method

This method will only work if you temporarily disable per-record ttl valuesopen in new window by setting dns_ttl=0 in the directadmin.conf :

cd /usr/local/directadmin
./directadmin set dns_ttl 0
service directadmin restart
1
2
3

You can turn it back on after you're done.

Note that this method sets all records in all zones to the same TTL value.

Also, you may set your desired default ttlopen in new window in the directadmin.conf the same way and restart DirectAdmin.

Once both dns_ttl=0 and default_ttl=300 are set, just issue the Named rewrite:

cd /usr/local/directadmin
echo "action=rewrite&value=named" >> data/task.queue
./dataskq d2000
1
2
3

Once done, you can set your dns_ttl=1 and default_ttl=14400 again, and restart DirectAdmin.

How to add a SRV record

SRV records provide a standard way of allowing services to use different values, and for a program to determine what those connection values are.

Related Wikipedia page:
http://en.wikipedia.org/wiki/SRV_recordopen in new window

As per the Wikipedia page, the format will look like this:

_service._proto.name TTL class SRV priority weight port target
1

We'll use their example, but formatted for better understanding:

LEFTmidRIGHT
_sip._tcp.example.com.86400 IN SRV0 5 5060 sipserver.example.com.

The LEFT portion goes onto the left side of the SRV record in DA, and the RIGHT portion goes onto the right side (DA sets the TTL automatically for you).

The LEFT portion contains the service, protocol, and name, in that order, separated by the period '.' character.

In the above example, the values match up as follows:

service:  _sip
protocol: _tcp
name:     example.com.

priority: 0
weight:   5
port:     5060
target:   sipserver.example.com.
1
2
3
4
5
6
7
8

Note that the "name" value will always match the name of the zone.

As such, these 2 left-side values are equivalent, and either could be used:

_sip._tcp.example.com.
_sip._tcp
1
2

where any left-side value that does not end with a period '.' will have the zone name appended to the end.

The "target" value can be any domain value, but should resolve using an A or CNAME record.

The same rule about the value ending in a period applies, and would be mandatory if the target is on a different domain name.

How to enable DNSSEC on a DirectAdmin server

DNSSEC is a tool used to verify the validity of a DNS lookup.

cd /usr/local/directadmin/scripts
./dnssec.sh install
1
2

which should confirm if your named.conf is set, and will enable the dnssec=1 in the directadmin.conf automatically. If the script thinks you're missing anything from your named.conf, it will tell you what to add.

  • To enable DNSSEC on a domain, go to Admin Level -> DNS Admin -> domain.com
  1. Click "Generate Keys"
  2. Click "Sign"
  3. You should now see values at the bottom of the zone. Copy the 2 DS records, and paste them into your domain registrar's website.

A sample DS value might look like this, with the following tags:

Key TagAlgorithmDigest TypeDigest
2752951BF698E47B53CC0B887AAF07B84586ABB289E3AAB

Where spaces are normal in the Digest Type=2, so be sure to paste in the whole Digest value.

  • If you have any subdomains created as full domains, you'll need to follow extra steps to continue the chain of trust up the line into the main domain's zone. For normal subdomains created under a domain, no extra action is required, as they're part of the domain's normal zone.

DNSSEC technical details

The script /usr/local/directadmin/scripts/dnssec.sh has few keys and parameters:

  ./dnssec.sh install
  ./dnssec.sh keygen <domain>
  ./dnssec.sh sign <domain>
1
2
3

The "install" may need you to manually add bits to your named.conf.

MONTHLY RESET

Will automatically re-sign all zones that have keys and already signed. If a zone has keys, but is not signed, this domain will be skipped.

TASK.QUEUE

echo "action=rewrite&value=dnssec" >> /usr/local/directadmin/data/task.queue
1

The above command will issue a re-signing, with the same rules as with the monthly reset. That being said, this is not to be used for the initial key/signing (it won't do anything without the key/signs already in place).

You do not need to add this as a cronjob. The monthly reset will re-sign the zones automatically. This is just a manual way to re-sign the zones if needed (requires that they already have keys).

MULTI-SERVER SETUP

By default, the directadmin.conf value will be:

dnssec_mss_use_signed_zone=1
1

meaning if you're using the MSS (Multi-Server Setup), DA will send over the signed zone to the remote box, rather than the raw zone you'd be editing.

Note, DA will also not let you edit a signed zone on a remote box because its format is fairly different and DA can't read it (at this time) plus going backwards to a raw zone would just get very messy.

For DNSSEC, always edit from the main DNS server to send the signed zones (from where the keys live).

How to enable DNSSEC for a Subdomain

DS records can now be added to the zone in the interface. This is not for the normal DNSSEC zone signing (that's hidden in the signed zone). The DS records in this context are for subdomain zone delegation.

If you create a sub.domain.com value as a full domain, its DS records need to go up the chain of trust. The next link in the chain for a subdomain zone is not your domain registrar, it's your domain.com zone.

So, the solution to make sub.domain.com pass the DNSSEC validation is to add the DS records from the sub.domain.com zone (created with the signing) in the standard DS records in your domain.com zone (aka: this feature).

Note, when you paste in the subdomain DS record into the domain.com zone, you must also create NS records for the subdomain in the domain.com zone.

subdomain.domain.com.  NS  ns1.domain.com.
subdomain.domain.com.  NS  ns2.domain.com.
1
2

where you'd specify the server that holds the subdomain.domain.com zone. (The subdomain zone can exist on a delegated remote server if you need). Without the NS records for the subdomain in the domain's zone, the domain will not be able to resign its keys.

Reported that you only need to add the first DS record into higher-level chain (zone one level up). For a sub.domain.com, you'd use the first DS record, and add it to domain.com zone (along with the 2 NS records).

Remember: adding/removing values from a signed zone will try to automatically resign the zone. To be sure, manually click the "Sign" button after setting up the DS and NS records in the domain.com zone.

Related forum threadopen in new window.

The DNSSEC info will now be displayed in the User Level zone, if DNSSEC is enabled. A directadmin.conf variable, and its default value below:

user_dnssec_control=0
1

If this is changed to 1, then the "Generate Keys" and "Sign" buttons will be available for use by the User.

How to enable DNSSEC for a Subdomain created as a full domain in DirectAdmin

DirectAdmin 1.51.0+ support the automated adding of the DS records over to the parent zone, enabled by default:
https://directadmin.com/features.php?id=1904open in new window

As well as for Multi-Server Setup combinations where the parent zone is on a remote MSS server with DirectAdmin 1.54.0+, this feature is enabled by default: https://directadmin.com/features.php?id=1963open in new window

How to disable DNSSEC for a domain

This functionalityopen in new window adds support to delete all keys and revert to a non-signed zone.

Related CMD_* calls include:

CMD_DNS_ADMIN
CMD_DNS_CONTROL
CMD_API_DNS_ADMIN
CMD_API_DNS_CONTROL
1
2
3
4

And are used like so:

method: POST
action=dnssec
domain=domain.com
remove_dnssec=<ANYTEXT>
1
2
3
4

which will clear all related keys, and revert the named.conf to using the "domain.com.db" zone file, instead of "domain.com.db.signed", eg:
https://help.directadmin.com/item.php?id=631open in new window

Old method (retained for older versions of DirectAdmin and troubleshooting)

After enabling DNSSEC for a domain, if you wish to disable it, use the following guide.

Let's assume you have it enabled for

  1. Edit the /etc/named.conf and change the zone entry for that domain from domain.com.db.signed to domain.com.db

  2. Delete the files:

/var/named/domain.com.ksk.*
/var/named/domain.com.zsk.*
/var/named/domain.com.db.signed
/var/named/dsset-domain.com.
/var/named/dlvset-domain.com.
1
2
3
4
5

Note: For Debian, use /etc/bind/, and for FreeBSD, use /etc/namedb/.

  1. Restart Named
service named restart
1
  1. Clear the DNSSEC keys from your domain registrar.

  2. If you're running the Multi-Server Setup, you'll want to push the change over to the remote box. Run this on the master:

echo 'action=rewrite&value=named&domain=domain.com' >> /usr/local/directadmin/data/task.queue
/usr/local/directadmin/dataskq d80
1
2

and confirm the local zone matches the remote zone.

How to automatically add TLSA records with Let's Encrypt updates

NOTE

This guide is incomplete. The SMTP checks are still failing.

If you must use it, do it for 443 only, comment out the _25._tcp lines for now.


This guide assumes you've already got DNSSEC up and running on your domain.

The first step is to set up a script that will actually generate and add the records to your zone.

Create the script here (not directly called by DA) /usr/local/directadmin/scripts/custom/set_tlsa.sh with code

#!/bin/sh

DOMAIN=$1
TQ=/usr/local/directadmin/data/task.queue
DTQ=/usr/local/directadmin/dataskq

if [ "${DOMAIN}" = "" ] || [ ! -d /etc/virtual/$DOMAIN ]; then
       echo "$DOMAIN is not a valid domain";
       exit 1;
fi

#F=lets-encrypt-x2-cross-signed.pem
#F=lets-encrypt-x1-cross-signed.pem
F=lets-encrypt-x3-cross-signed.pem
wget -O $F https://letsencrypt.org/certs/$F
V=`openssl x509 -in $F -outform DER | openssl dgst -sha256 -hex | awk '{print "2 0 1", $NF}'`

echo "Value is: $V"

#clear the old le-ca
echo "action=dns&do=delete&domain=${DOMAIN}&type=CNAME&name=_443._tcp&value=*" >> ${TQ}.cb;
echo "action=dns&do=delete&domain=${DOMAIN}&type=CNAME&name=_25._tcp.mail&value=*" >> ${TQ}.cb;
echo "action=dns&do=delete&domain=${DOMAIN}&type=TLSA&name=le-ca&value=*" >> ${TQ}.cb; ${DTQ} --custombuild

#add the new one
echo "action=dns&do=add&domain=${DOMAIN}&type=TLSA&name=le-ca&value=$V" >> ${TQ}

#adding
echo "action=dns&do=add&domain=${DOMAIN}&type=CNAME&name=_443._tcp&value=le-ca" >> ${TQ}
echo "action=dns&do=add&domain=${DOMAIN}&type=CNAME&name=_25._tcp.mail&value=le-ca" >> ${TQ}

echo 'action=named&value=reload' >> ${TQ}

exit 0;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

And make it executable:

chmod 755 /usr/local/directadmin/scripts/custom/set_tlsa.sh
1

Next, create this custom script to call it, triggered by any LE update: /usr/local/directadmin/scripts/custom/letsencrypt_post.sh with the following code:

#!/bin/sh
/usr/local/directadmin/scripts/custom/set_tlsa.sh $domain
exit 0;
1
2
3

And also make it executable:

chmod 755 /usr/local/directadmin/scripts/custom/letsencrypt_post.sh
1

This will set the TLSA on all domains that are using Let's Encrypt, so ** be sure they're all using DNSSEC** before setting this up.

How to add a new DNS record to all existing domains and pointer zones

This guide contains a script which goes through all domains and domain pointers, and will add a new A record with a specific value you want, using that User's existing IP address.

Replace mynewrecord with the value that you want.

Adjust the /var/named path if you're running FreeBSD or Debian.

Create a backup of zones before running it.

#!/bin/sh
DATAU=/usr/local/directadmin/data/users
for u in `ls $DATAU`; do
{
      IP=`grep ip= $DATAU/$u/user.conf | cut -d= -f2`
      for d in `cat $DATAU/$u/domains.list $DATAU/$u/domains/*.pointers 2>/dev/null | cut -d= -f1`; do
      {
            echo "adding new record with IP $IP to $d";
            echo "mynewrecord   14400    IN   A   $IP" >> /var/named/${d}.db
      };
      done;
};
done;
exit 0;
1
2
3
4
5
6
7
8
9
10
11
12
13
14

Don't forget to restart Named after running the script.

Mass removal of an NS record from all zones

If you need to remove an NS record from all zones quickly, Perl can be useful.

Let's assume you want to remove all NS records with the value ns1.domain.com. from all zones.

  1. Make a backup of all of your zones, just in case something goes wrong:
cd /var/named
tar cvzf /root/dns_backup.tar.gz *
1
2
  1. Run the following code:
perl -pi -e 's#^.*NS\s+ns2\.domain\.com\.\n##' *.db
1

taking note of the character before all literal period characters in the NS value.

  1. Lastly, you'll need to update the serial on all zones:
echo "action=rewrite&value=named" >> /usr/local/directadmin/data/task.queue
/usr/local/directadmin/dataskq d400
1
2

NOTE A zone must have at least one NS record, or it will not be loaded.

Be sure to check inside a few random zones to ensure it worked. Check /var/log/messages for any named errors after it gets reloaded.

How to do a mass DNS update

If you need to change all of your DNS servers through DirectAdmin one by one, it's easier to use Perl to do a regex (regular expression) to do the replacement for us with one command.

Let's assume these are the old values:
NS1: NS2:

and these are the new values:

NS1: NS2:

To do this, you can run the following:

cd /usr/local/directadmin/data/users
perl -pi -e 's/ns1.old.com/ns1.new.com/' */user.conf
perl -pi -e 's/ns2.old.com/ns2.new.com/' */user.conf
perl -pi -e 's/ns1.old.com/ns1.new.com/' */reseller.conf
perl -pi -e 's/ns2.old.com/ns2.new.com/' */reseller.conf
1
2
3
4
5

Do a backup of all zones to be safe (/var/named on RedHat/CentOS, /etc/bind on Debian, and /etc/named on FreeBSD):

cd /var/named
tar cvzf /root/dns_backup.tar.gz *
perl -pi -e 's/ns1.old.com/ns1.new.com/' *.db
perl -pi -e 's/ns2.old.com/ns2.new.com/' *.db
1
2
3
4

Once your changes are done, it's a good idea to rewrite all .db files to update your serials, and also to trigger any syncs to remote DNS systems:

echo "action=rewrite&value=named" >> /usr/local/directadmin/data/task.queue
/usr/local/directadmin/dataskq d400
1
2

How to do a mass update of a single A record for all domains

If you're looking to change the IP value of 1 A record in all db files for all domains, Perl will be your best friend.

In this example, we'll change the mail A record from any previous IP to a new value of 1.2.3.4. This will route all mail to 1.2.3.4 when the MX record is queried.

First, you'll want to change to the directory where your db files live.
On Redhat/CentOS systems, it's /var/named.
On Debian, /etc/bind.
On FreeBSD, /etc/namedb.

So, the example would be as follows for Redhat systems:

cd /var/named
tar cvzf /root/dns_backup.tar.gz *
perl -pi -e 's#^mail\s14400\sIN\sA\s(.*)$#mail\t14400\tIN\tA\t1.2.3.4#' *.db
1
2
3

Next rewrite all .db files to update your serials:

echo "action=rewrite&value=named" >> /usr/local/directadmin/data/task.queue
/usr/local/directadmin/dataskq d400
1
2

Note that these steps can be applied to other A records with different names (like pop and SMTP), and even to other record types like MX, NS, TXT, etc.

How to swap all TXT/SPF records from ~all to -all

In an attempt to lower your spam score, using the forceful -all SPF value instead of the neutral ~all is one simple way of doing this. However, as -all is enforced, it means that all of your clients who send on a domain using -all MUST use your server to send their email, and cannot send email through their own IPs, unless you include their SPF settings in the DNS record.

  1. Future Domains

To use the -all format for all future domains, not yet created, type:

cd /usr/local/directadmin/data/templates/custom
cp ../dns_txt.conf .
cp ../dns_spf.conf .
1
2
3

Then edit both of these files, and change ~all to -all.

  1. Existing Domains

To swap all existing domains** to the -all format**, enter directory with zones (/var/named on RedHat/CentOS, /etc/bind on Debian, and /etc/named on FreeBSD):

cd /var/named
tar cvzf /root/dns_backup.tar.gz *
perl -pi -e 's/\~all/\-all/' *.db
1
2
3

Next rewrite all .db files to update your serials:

echo "action=rewrite&value=named" >> /usr/local/directadmin/data/task.queue
/usr/local/directadmin/dataskq d400
1
2

How to change the SPF records for all domains

If you're making DNS changes or you are having domains send email from other IPs, you might want to make alterations to your SPF records.

For mass changes, there are a few ways to go about this.

  1. If you are not using DKIM and don't mind losing all of your TXT records, you can use the named.db method of temporarily altering the zone template:
cd /usr/local/directadmin/data/templates
perl -pi -e 's/\|TXT\|/|DOMAIN|. 14400 IN TXT "v=spf1 a mx ip4:1.2.3.4 include:masterdomain.com -all"/' named.db
1
2

Where you can adjust the values as desired.

You might notice the

include:masterdomain.com
1

which is basically like an SPF pointer, in that it will let the current domain use all SPF records that the masterdomain.com has set, making future changes very easy in a single place, should they be needed. This would save you from having to re-edit all zones, instead just editing the master, and all domains that have this include will automatically get those changes.

Once the named.db has the TXT removed, rewrite all zones with the new values:

cd /usr/local/directadmin
echo "action=rewrite&value=named" > data/task.queue; ./dataskq d2000
1
2

and confirm all zones are updated with the new TXT record.

**MAKE SURE **you then revert your named.db back to having the |TXT| token after, else TXT records won't be able to be added through DA!

Option 2 is to do a mass regex on the SPF records. This is going to be more surgical, and will not affect your other TXT records. A sample regex might look like:

cd /var/named
tar cvzf /root/dns_backup.tar.gz *
perl -pi -e 's/v=spf1.*$/v=spf1 a mx ip4:1.2.3.4 include:masterdomain.com -all"'/ *.db
1
2
3

with the same rules as before, adjust the values as desired. Note that a regex may require you to escape some special characters (Google for more info on how to write regex).

You'll also want to issue a rewrite of all zones to increase the serial numbers:

cd /usr/local/directadmin
echo "action=rewrite&value=named" > data/task.queue; ./dataskq d2000
1
2

Changing the default for new domains

Either method, above, will affect existing domains, but will not affect anything for new domains.

For this, you have 2 options, depending on what you need to do.

  1. The cleanest/simplest method will be to use the extra_spf_value feature, which appends some data directly into the default TXT/spf record.

For example, for the above example, you'd add this to your directadmin.confusing the directadmin binary, making sure to note the leading space in the value:

cd /usr/local/directadmin/
./directadmin set extra_spf_value " include:masterdomain.com"
service directadmin restart
1
2
3

BUT this will not affect items before or after the |EXTRA_SPF| token from the dns_txt.conf file, so it will use the defaults, like ~all, etc. Use option 2 below if you need more control.

  1. Edit the TXT template directly:
cd /usr/local/directadmin/data/templates/custom
cp ../dns_txt.conf ./
vi dns_txt.conf
1
2
3

and make it look something like:

|DOMAIN|.="v=spf1 a mx ip4:|SERVER_IP||EXTRA_SPF| include:masterdomain.com -all"
1

or adjust to suit your needs. Note that it will look like this if ipv6=1 and dns_add_spf_ipv6=1 are set in the directadmin.conf:

|DOMAIN|.="v=spf1 a mx ip4:|SERVER_IP||EXTRA_SPF||SPF_IPV6| include:masterdomain.com -all"
1

This will be safe from DA updates, as it's in the custom folder. It will apply to all new zones created after it's set.

If your version of Named supports actual "SPF" type records, and you've enabled it in the directadmin.conf then in addition to the dns_txt.conf, you'll want to repeat the same steps on dns_spf.conf.

The dns_spf.txt and dns_txt.conf templates

Both templates consist of the following:

|DOMAIN|.="v=spf1 a mx ip4:|SERVER_IP||EXTRA_SPF|| ~all"
1

Or the following if ipv6=1 and dns_add_spf_ipv6=1 are set in the directadmin.conf:

|DOMAIN|.="v=spf1 a mx ip4:|SERVER_IP||EXTRA_SPF||SPF_IPV6| ~all"
1

How to script own logic on DNS records

The named.db template (used to create domain.com.db files) supports username scripting.

The scripts will be run as root, so you have full access to everything, but be very careful with this high access level, to ensure you don't do any damage to your system.

Sample addition to the bottom of the named.db code for DNSSEC:

|$/usr/local/bin/php
<?php
if (file_exists("/var/named/|DOMAIN|.zsk.key"))
{
        echo "\t\$include        /var/named/|DOMAIN|.zsk.key\n";
}
if (file_exists("/var/named/|DOMAIN|.zsk.key"))
{
        echo "\t\$include        /var/named/|DOMAIN|.ksk.key\n";
}
?>
DONE|
1
2
3
4
5
6
7
8
9
10
11
12

Note that DA may not support thing you add, so if you add any values that the DA dns parser cannot read (eg: $include lines) ensure you're adding them to the bottom of the file.

You should really also be only adding things here that DA cannot see... else you'll end up with duplicates each time you re-save the zone.

For example, do not add A records with this feature, else you'll get another A record each time you save the zone. For A records, use the dns_a.conf. It also supports shell scripting.

How to recreate all zone db files

If, for whatever reason, you've managed to delete your zones' db files, you can use this script to recreate them.

Note, this will destroy all of your previous zone data, so you'll want to ensure you really want to start all zones over again.

Any custom zone data that was added will be removed.

You'd only want to use this if you have no other alternatives for recovering your DNS data.

Create a new script called fix_db.sh, and fill it with this code:

#!/bin/sh

NAMED_DIR=/var/named
DA_USERS_DIR=/usr/local/directadmin/data/users
NS1=`grep ns1= /usr/local/directadmin/conf/directadmin.conf | cut -d= -f2`
NS2=`grep ns2= /usr/local/directadmin/conf/directadmin.conf | cut -d= -f2`

for DA_USER in `ls ${DA_USERS_DIR}`; do
{
          for DOMAIN in `cat ${DA_USERS_DIR}/${DA_USER}/domains.list; cat ${DA_USERS_DIR}/${DA_USER}/domains/*.pointers 2>/dev/null | cut -d= -f1;`; do
          {
                    echo $DOMAIN
                    rm ${NAMED_DIR}/${DOMAIN}.db

                    if [ ! -r "${NAMED_DIR}/${DOMAIN}.db" ]; then
                              IP=`cat ${DA_USERS_DIR}/${DA_USER}/domains/${DOMAIN}.conf | grep ip= | cut -d= -f2`
                              if [ "$IP" = "" ]; then
                                         IP=`cat ${DA_USERS_DIR}/${DA_USER}/user.conf | grep ip= | cut -d= -f2`
                              fi
                              
                              echo "\$TTL 14400"  >  ${NAMED_DIR}/${DOMAIN}.db
                              echo "@         IN      SOA     ${NS1}.         hostmaster.${DOMAIN}. ("        >> ${NAMED_DIR}/${DOMAIN}.db
                              echo "                                                          2010101901"                     >> ${NAMED_DIR}/${DOMAIN}.db
                              echo "                                                          14400"                          >> ${NAMED_DIR}/${DOMAIN}.db
                              echo "                                                          3600"                           >> ${NAMED_DIR}/${DOMAIN}.db
                              echo "                                                          1209600"                        >> ${NAMED_DIR}/${DOMAIN}.db
                              echo "                                                          86400 )"                        >> ${NAMED_DIR}/${DOMAIN}.db
                              echo ""                                                                                         >> ${NAMED_DIR}/${DOMAIN}.db
                              echo "${DOMAIN}.        14400   IN              NS      ${NS1}."                >> ${NAMED_DIR}/${DOMAIN}.db
                              echo "${DOMAIN}.        14400   IN              NS      ${NS2}."                >> ${NAMED_DIR}/${DOMAIN}.db
                              echo ""  >> ${NAMED_DIR}/${DOMAIN}.db
                              echo "${DOMAIN}.        14400   IN              A       ${IP}"                             >> ${NAMED_DIR}/${DOMAIN}.db
                              echo "ftp               14400   IN              A       ${IP}"                             >> ${NAMED_DIR}/${DOMAIN}.db
                              echo "localhost         14400   IN              A       127.0.0.1"                              >> ${NAMED_DIR}/${DOMAIN}.db
                              echo "mail              14400   IN              A       ${IP}"                             >> ${NAMED_DIR}/${DOMAIN}.db
                              echo "pop               14400   IN              A       ${IP}"                             >> ${NAMED_DIR}/${DOMAIN}.db
                              echo "smtp              14400   IN              A       ${IP}"                             >> ${NAMED_DIR}/${DOMAIN}.db
                              echo "www               14400   IN              A       ${IP}"                             >> ${NAMED_DIR}/${DOMAIN}.db
                              echo ""  >> ${NAMED_DIR}/${DOMAIN}.db
                              echo "${DOMAIN}.        14400   IN              MX      10 mail"                                >> ${NAMED_DIR}/${DOMAIN}.db
                              echo "${DOMAIN}.        14400   IN              TXT     \"v=spf1 a mx ip4:${IP} ~all\""    >> ${NAMED_DIR}/${DOMAIN}.db

                              echo ""  >> ${NAMED_DIR}/${DOMAIN}.db

                              for SUB in `cat ${DA_USERS_DIR}/${DA_USER}/domains/${DOMAIN}.subdomains`; do
                              {
                                echo "${SUB}              14400   IN              A       ${IP}"                             >> ${NAMED_DIR}/${DOMAIN}.db
                              }
                              done;

                              chown bind:bind ${NAMED_DIR}/${DOMAIN}.db

                              echo "  - database created."

                    fi
          }
          done;
}
done;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

Make it executable with chmod 755 fix_db.sh and then run it.

Thanks to Desmond from from w3media for contributing this script.

How to re-add all zone entries into the named.conf

If your system already has all of the domain.com.db zone files, but the named.conf is missing zone entries for those db files, you can use the following script to re-add them to the named.conf.

This assumes that DA is already installed, as it grabs the named.conf and db file paths from the directadmin binaries.

Create a fix.sh script somewhere, and fill it with the following code:

#!/bin/sh

NAMED_PATH=`/usr/local/directadmin/directadmin c | grep nameddir | cut -d= -f2`
NAMED_CONF=`/usr/local/directadmin/directadmin c | grep namedconfig | cut -d= -f2`

if [ ! -s $NAMED_CONF ]; then
            echo "Cannot find $NAMED_CONF. Aborting";
            exit 1;
fi

if [ ! -d $NAMED_PATH ]; then
            echo "Cannot find directory $NAMED_PATH. Aborting";
            exit 2;
fi

for u in `ls /usr/local/directadmin/data/users`; do
{
   for i in `cat /usr/local/directadmin/data/users/$u/domains.list; cat /usr/local/directadmin/data/users/$u/domains/*.pointers 2>/dev/null | cut -d= -f1`; do
   {
            echo -n "Checking $i ... ";
       
            COUNT=`grep -c "zone \"$i\"" $NAMED_CONF`
            if [ "$COUNT" -gt 0 ]; then
                        echo "Already exists. Skipping";
                        continue;
            fi
       
            echo "";
            echo "*** Adding $i to ${NAMED_CONF}";
            echo "zone \"${i}\" { type master; file \"${NAMED_PATH}/${i}.db\"; };" >> ${NAMED_CONF}
       
            DBFILE=${NAMED_PATH}/${i}.db
            if [ ! -s ${DBFILE} ]; then
                        echo "Warning: Cannot find ${DBFILE}";
            fi
   };
   done;
};
done;
exit 0;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

Make the script executable with:

chmod 755 fix.sh
1

and run it:

./fix.sh
1

It can be run multiple times. It checks the named.conf to ensure the domain doesn't already exist.

The domain values are taken from the User domain.list files.

How to reset all user zones

If you need to reset every User-created zone back to the default when viewing a zone (same as the "Reset Defaults" button), you can use the following task.queue command to do it:

cd /usr/local/directadmin
echo "action=reset&value=all_zones" >> data/task.queue; ./dataskq d2000
1
2

Note, it only resets domains which are listed in /etc/virtual/domainowners . It does not reset other zones.

It's highly recommended you back up all of your zones prior to the reset, in case it does not give you the desired result.

Ability to add/delete DNS records from the task.queue

Very raw feature with limited user validation. Use very carefully.

Samples, add/delete:

echo 'action=dns&do=add&domain=domain.com&type=A&name=mail&value=1.2.3.4&ttl=500' >> /usr/local/directadmin/data/task.queue
echo 'action=dns&do=delete&domain=domain.com&type=A&name=mail&value=1.2.3.4' >> /usr/local/directadmin/data/task.queue
echo 'action=dns&do=delete&domain=domain.com&type=TXT&name=_acme-challenge&value=*' >> /usr/local/directadmin/data/task.queue
1
2
3

Note, that the do=delete does require you pass the "value" as most record types allow duplicate names, thus the value is used to differentiate the records. The ttl can optionally be passed during do=add, but is not required. If dns_ttl=1 is not enabled, the ttl value will have no effect.

For do=delete, if value=* then it will delete all records of that type, with the given name=. So in the example, it will delete all TXT records from domain.com, that have a left-side name of _acme-challenge. This will not catch any full records, like "_acme-challenge.domain.com." as the tool is quite basic.

This method saves needing an API call, and supports all of the clustering pushes.

Note the type must be an upper case character, one of:

  • A
  • NS
  • MX
  • CNAME
  • PTR
  • TXT
  • AAAA
  • SRV
  • SPF
  • TLSA
  • CAA
  • DS

Note: if some features are not enabled, that given type might not get added to the db file, e.g.,:
dns_tlsa=1
dns_caa=1
dns_spf=1

DNS: action=dns&do=add|delete: allow domain to be sub-value, DA will find the parent zone

We already have task.queue commands, which allow for adding/removing records, e.g.,

echo 'action=dns&do=add&domain=domain.com&type=CNAME&name=smtp&value=mail' >> /usr/local/directadmin/data/task.queue
1

which would add a CNAME:

smtp CNAME mail
1

This change allows DA to do some work if you're not 100% sure where the closest zone is, say a subdomain is a full zone or just an A record in a parent zone. So for example, say you wanted to do something similar:

action=dns&do=add&domain=sub.domain.com&type=CNAME&name=smtp&value=mail
1

where you wanted the smtp.sub.domain.com. CNAME mail.sub.domain.com. effective value, but don't want to hunt if there's a sub.domain.com zone or domain.com zone. If sub is a subdomain under the domain.com zone (just an A record), then for the above command, DA will notice there is no sub.domain.com.db file, and find the domain.com.db to use.

The resulting values would internally be converted to:

action=dns&do=add&domain=domain.com&type=CNAME&name=smtp.sub&value=mail.sub
1

where DA:

  1. Moves from left to right, to find the lowest zone.. in this case 'domain.com' and sets the domain as such.
  2. for the name, if there is no trailing dot, the removed leading domain portion is appended to the end of the name
  3. for the value, if there is no trailing dot, the removed leading domain portion is appended to the end of the value

2 and 3 only apply to types CNAME, NS, and MX records.

TEST MODE

If you're curious to see how DA converts the domain, name, and value, you can add:

test=yes
1

to your task.queue request and DA will output the effective data, e.g.,

[root@es6-64 directadmin]# echo 'test=yes&action=dns&do=add&domain=sub.es60-64.com&type=CNAME&name=foo.com.&value=bar.com.' > data/task.queue.cb; ./dataskq d530 --custombuild
Debug mode. Level 530

root priv set: uid:0 gid:0 euid:0 egid:0
pidfile written
starting queue
dataskq: command: test=yes&action=dns&do=add&domain=sub.es60-64.com&type=CNAME&name=foo.com.&value=bar.com.
Named::taskq_dns: found local sub-zone es60-64.com from sub.es60-64.com
****************************************************
Loaded parameters for add
 0: action=dns
 1: do=add
 2: domain=es60-64.com
 3: name=foo.com.
 4: test=yes
 5: type=CNAME
 6: value=bar.com.
****************************************************
done queue
[root@es6-64 directadmin]#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

The ability to use the package token in dns templates

The PACKAGE token could be used in dns_*.conf templates, as well named.db . The PACKAGE value will not be present if the zone does not have an associated User on this box. However, for any domains that are created on this box under a DA User, the token should be there.

For example, you may want to set your MX records differently, based on package. To do this, type:

cd /usr/local/directadmin/data/templates/custom
cp ../dns_mx.conf .
1
2

Edit the dns_mx.conf file in custom directory, and set this in the file:

|*if PACKAGE="remotemail"|
mail.remoteserver.com.=10
|*else|
mail=10
|*endif|
1
2
3
4
5

where "remotemail" is the name of the User package set that is to use as the mail server:

mail.remoteserver.com.
1
Last Updated: 6/23/2021, 9:36:08 PM