{"id":127,"date":"2019-06-02T16:51:35","date_gmt":"2019-06-02T15:51:35","guid":{"rendered":"https:\/\/blog.inplico.uk\/?p=127"},"modified":"2023-08-15T20:43:35","modified_gmt":"2023-08-15T19:43:35","slug":"bind-dns","status":"publish","type":"post","link":"https:\/\/blog.inplico.uk\/?p=127","title":{"rendered":"BIND dns"},"content":{"rendered":"<p>Getting bind right can be a bit if a bind (if you pardon the pun) so in this example we are going to start be outlining what our zones actually do.<\/p>\n<p style=\"margin-left: 40px;\"><strong>servicedomain.com<\/strong> is the domain name that we purchased from our domain name supplier.<br \/>\n<strong>mail.zone1.servicedomain.com<\/strong> will be the public name of our mail server (The service domain)<br \/>\n<strong>mail.zone2.<\/strong> <strong>servicedomain.com<\/strong> will be a second backup mail server at a different location. (A second service domain)<br \/>\n<strong>privatenet.local<\/strong> will be the internal domain used for local client to client connectivity.<br \/>\n<strong>nameserverdomain.com<\/strong> will be a second domain purely so that we can name the name servers.<\/p>\n<p><strong>Subnets and IP addresses<\/strong><\/p>\n<p style=\"margin-left: 40px;\">172.17.0.0\/16 will be the local subnet on our master (server1)<br \/>\n10.8.1.0\/24 will be the subnet for openvpn on our master (server1)<br \/>\n172.18.0.0\/16 will be the local subnet on our master (server2)<br \/>\n10.8.2.0\/24 will be the subnet for openvpn on our master (server2)<br \/>\n172.17.0.0\/16 will be the local subnet on our master (server1)<br \/>\n10.8.2.0\/24 will be the subnet for openvpn on our master (server1)<br \/>\n123.123.123.1 will be the public ip address of the master (server1)<br \/>\n169.169.169.1 will be the public ip address of the slave (server2)<\/p>\n<p><strong>Servers<\/strong><\/p>\n<p>Internally the servers and clients will be called<\/p>\n<p style=\"margin-left: 40px;\">server1\u00a0\u00a0 This will be our master DNS server<br \/>\nserver2\u00a0\u00a0 This will be our slave DNS server<br \/>\nclient1<br \/>\nclient2<br \/>\nclient3<\/p>\n<p>None of the clients will be accessible from the internet and the servers will not be accessible by their internal names<\/p>\n<p>&nbsp;<\/p>\n<p><strong>First install bind<\/strong><\/p>\n<pre class=\"lang:sh decode:true\">#apt-get install bind9<\/pre>\n<p>This will install bind and add a user and group, both called \u201cbind\u201d.<\/p>\n<p>Now check that bind is not running &#8211; This is particularly important if your router\/modem allows access from the internet as you don\u2019t want to become a free DNS server for all and sundry. Us the command line to check and stop the service if necessary.<\/p>\n<pre class=\"lang:sh decode:true \"># service bind9 status\r\n# service bind9 stop<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>conf.options<\/strong><\/p>\n<p>The next thing to do is edit named.conf.options in order to set the global options for our dns server.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Access Control List<\/strong><\/p>\n<p>The first thing we do at the top of the file is to create an access control list. We are going to call this list \u201c<strong>trusted_anywhere<\/strong>\u201d but you can call it anything just as long as you reference it correctly. You can also create multiple access control lists for more complex configurations.<\/p>\n<p>In our example we want to allow our local intranet, our vpn and our local server and networks full access<\/p>\n<p>NOTE: The following special <strong>acl-name<\/strong> values are built into BIND:<\/p>\n<p style=\"margin-left: 40px;\"><strong>&#8220;none&#8221;<\/strong> &#8211; matches no hosts<\/p>\n<p style=\"margin-left: 40px;\"><strong>&#8220;any&#8221;<\/strong> &#8211; matches all hosts<\/p>\n<p style=\"margin-left: 40px;\"><strong>&#8220;localhost&#8221;<\/strong> &#8211; matches all the IP address(es) of the server on which BIND is running e.g. if the server has a single interface with an IP address of 192.168.2.3 then localhost will match 192.168.2.3 and 127.0.0.1 (the loopback address is always present).<\/p>\n<p style=\"margin-left: 40px;\"><strong>&#8220;localnets&#8221;<\/strong> &#8211; matches all the IP address(es) and subnetmasks of the server on which BIND is running i.e. if the server has a single interface with an IP address of 192.168.2.3 and a netmask of 255.255.255.0 (or 192.168.2.2\/24) then localnets will match 192.168.2.0 to 192.168.2.255 and 127.0.0.1 (the loopback is assumed to be a single address). Some systems do not provide a way to determine the prefix lengths of local IPv6 addresses. In such a case, localnets only matches the local IPv6 addresses, just like localhost.<\/p>\n<p>In our example we want to permit local clients and servers to perform recursive lookps, we also want to allow clients connecting by our VPN to do the same. So with reference to our the parameters given in our example above here is our \u201ctrusted_anywhere\u201d access control list:<\/p>\n<p>Server 1:<\/p>\n<pre class=\"lang:sh highlight:0 decode:true \">acl trusted_anywhere {\r\n    172.17.0.0\/16;\r\n    10.8.1.0\/24;\r\n    localhost;\r\n};<\/pre>\n<p>Server 2:<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">acl trusted_anywhere {\r\n    172.17.0.0\/16;\r\n    10.8.2.0\/24;\r\n    localhost;\r\n};<\/pre>\n<p>which is to be placed at the top of <strong>\/etc\/bind\/named.conf.options<\/strong>. We can also restrict certain addresses or groups if we like by prefixing their addresses with a \u2018!\u2019 eg.<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">acl trusted_anywhere {\r\n    172.17.0.0\/16;\r\n    10.8.2.0\/24;\r\n    localhost;\r\n    !111.111.111.111\r\n};<\/pre>\n<p>This will allow all hosts with the exception of 111.111.111.111 to do something (as yet unspecified) Note that we do not want to do this in our configuration, it is just an example.<\/p>\n<p>If we want to we can create multiple ACL\u2019s grant permissions to various groups to perform various tasks the it can be helpful. It can also make your DNS records more manageable even if you have only one address or group in the list.<\/p>\n<p>A second ACL that lists the servers can be handy for setting transfer and notify options so we will go ahead and create one now:<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">acl servers {\r\n    123.123.123.1;\r\n    169.169.169.1\r\n    localhost;\r\n};<\/pre>\n<p>Finally, although not strictly an ACL we need to create a <strong>masters<\/strong> This only needs to be done on servers with <strong>slave zones<\/strong>:<\/p>\n<p>On our slave server (<strong>Server2 ONLY<\/strong>) we want to create our masters list. I call it a list, it is really a list of one, but it makes it much easier to change the servers ip if we do it this way:<\/p>\n<pre class=\"lang:sh highlight:0 decode:true \">masters master_servers {\r\n    123.123.123.1;\r\n};<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Options <\/strong><\/p>\n<p>Ok, so now we have our access control lists configured we now move on to our options. There are some directives in options that can be overridden by the individual zone files. We are not going to go through every available option as that would overly complicate things so we are just going to stick with the ones that we need for our configuration.<\/p>\n<p>The recursion directive is what allows the server to forward requests to other servers for domains that it cannot resolve itself. Although we want to limit who can perform recursive queries, we do need to enable it with<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">options {\r\n    .......\r\n    recursion yes;\r\n    .......\r\n}<\/pre>\n<p>The next directives limit the scope of who can do what; from a security point of view these are the most important directives to get right.<\/p>\n<p>The first one is <strong>allow-query{ }<\/strong>. Setting this will determine who can submit requests to your server. In our case servers and clients on the internet will need to use our server to determing the ip addresses for the mail servers. as we have no idea which servers or clents may which to obtain this information we want to permit all traffic to query our dns servers so we set<\/p>\n<pre class=\"lang:sh highlight:0 decode:true \">options {\r\n    .......\r\n    allow-query { any; };\r\n    .......\r\n}<\/pre>\n<p>Ok, at this point we are allowing clients access to our server and we are also allowing our server to perform recursive queries (in essence what we have created is an open public DNS server &#8211; which is not really what we want). In order to prevent this we need to set some more directives: \u201c<strong>allow-recursion<\/strong>\u201d and \u201c<strong>allow-query-cache<\/strong>\u201d. This time we want to restrict recursion so that only certain devices can perform recursive queries. This is where our access control list comes in:<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">options {\r\n    .......\r\n    allow-recursion { trusted_anywhere; };\r\n    allow-query-cache { trusted_anywhere; };\r\n    .......\r\n}<\/pre>\n<p>The next configuration (setting forwarder) is optional. If you do not set any forwarders then Bind will use root hints to perform lookups insetead. Root hints are special dns servers that are basically the grandparents of all other DNS servers on the internet. These days using root hints alone is not particularly slow, but it may be a little slower than using forwarders (although if the forward server doesn\u2019t have your address in its cache it will have to forward the request on anyway so the advantage of using them is debatable). In our example we will use forwarders just to show how it is done.<\/p>\n<p>I am not the greatest fan of companies slurping your data in order to build a profile of you; usually to sell you things (basically I am not a fan of google) and believe that care must be taken when and if you choose a forwarder for this reason. The public DNS servers we will use for this example are provided by WatchDns (who claim that they do not collect, monetise or cache your data) The ip addresses for the WatchDns servers are correct at the time that this was written.<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">options {\r\n    .......\r\n    forwarders {\r\n        84.200.69.80;\r\n        84.200.70.40;\r\n    };\r\n    .......\r\n}<\/pre>\n<p>The next 2 directives should alredy be set but you can check them, they are:<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">dnssec-validation auto;\r\nauth-nxdomain no;<\/pre>\n<p>Now we want to tell our server which servers it should notify about what it is doing. This is where our <strong>servers<\/strong> ACL comes:<\/p>\n<pre class=\"lang:sh decode:true\">options {\r\n    .......\r\n    allow-notify {\r\n        servers;\r\n    };\r\n    .......\r\n}<\/pre>\n<p>IPV6 is on a very slow boat form china and at the moment and while no doubt one day it will take over for now we simply want to disable it. There is more to disabling IPV6 than just this (we will deal with the rest later) but as far as the options configuration goes all we have to do is tell bind not to listen on IPV6.<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">options {\r\n    .......\r\n    listen-on-v6 { none; };\r\n    .......\r\n}<\/pre>\n<p>The listen on directive tells bind what addresses to listen for requests on. This is another way of restricting traffic (at least it is if you have multiple ports and are routing everything through your server) as we could tell the server to listen to requests from a certain ip address. eg. listen-on { 127.0.0.1; 192.168.1.254; };<\/p>\n<p>As we are using Access Control Lists we can set our server to listen out for all traffic from all ports, it will then use the ACL to determine how to handle it. To do this we need to set<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">options {\r\n    .......\r\n    listen-on { any; };\r\n    .......\r\n}<\/pre>\n<p>And that is it for our options file; all being well you should have something that looks like this:<\/p>\n<pre class=\"lang:sh highlight:0 decode:true \">acl trusted_anywhere {\r\n    172.17.0.0\/16;\r\n    10.8.2.0\/24;\r\n    localhost;\r\n};\r\n\r\n\r\nacl servers {\r\n    123.123.123.1;\r\n    169.169.169.1;\r\n    localhost;\r\n};\r\n\r\n\r\n\/\/Slave server only\r\nmasters master_servers {\r\n    123.123.123.1;\r\n};\r\n\r\n\r\noptions {\r\n    directory \"\/var\/named\";\r\n    recursion yes;\r\n    allow-query { any; };\r\n    allow-recursion { trusted_ anywhere; };\r\n    allow-query-cache { trusted_ anywhere; };\r\n    forwarders {\r\n        84.200.69.80;\r\n        84.200.70.40;\r\n    };\r\n    dnssec-validation auto;\r\n    auth-nxdomain no;\r\n    listen-on-v6 { none; };\r\n    listen-on { any; };\r\n    allow-notify { servers; };\r\n};<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Zones<\/strong><\/p>\n<p>Now we need to configure the zones, but first we may want to configure the names of the nameservers themselves.<\/p>\n<p>The next bit of configuration will depend on how your domains are set up with your provider and what facilities are available.<\/p>\n<p>The goal of this tutorial is to have 2 nameservers that will perform lookups for your domain. In order to do this you will need to have requests forwarded from another domain higher up the food chain (usually your domain name provider). Form experience most of them require you to provide a name for your domain name server rather than an IP address (which can create a paradox if you are not very careful).<\/p>\n<p>In essence you cannot use the domain name that you are serving because the parent nameserver will not know where to look for that domain until it has contacted your name server.<\/p>\n<p>In reality very few mail servers actually serve mail for their own domains so you could use one of the user domains if you are on a budget, if not you could purchase a cheap domain with just about any name you like. For our example we will use a separate domain which according to our example will be <strong>nameserverdomain.com<\/strong>. We will call our name servers <strong>ns1<\/strong> and <strong>ns2<\/strong>.<\/p>\n<p>How exactly you do this will depend on your provider, but you will need 2 \u2018A\u2019 records<\/p>\n<p><strong style=\"margin-left: 40px;\">ns1.nameserverdomain.com<\/strong> resolves to <strong>123.123.123.1<\/strong><br \/>\n<strong style=\"margin-left: 40px;\">ns2.nameserverdomain.com <\/strong>resolves to <strong>169.169.169.1<\/strong><\/p>\n<p>The only other thing that you will need to do is your providers domain server to forward requests to your own DNS servers. Again it depends on who your provider is, but you want to forward requests for the domain <strong>com<\/strong> to the 2 nameservers listed above. You do not need to add any other records.<\/p>\n<p>We are now going to add some zones which are<\/p>\n<p><strong style=\"margin-left: 40px;\">servicedomain.com<\/strong><br \/>\n<strong style=\"margin-left: 40px;\">zone1.mailservicedomain.com<\/strong><br \/>\n<strong style=\"margin-left: 40px;\">zone2.mailservicedomain.com<\/strong><\/p>\n<p>The configuration for each of these zones is identical so we are only going to demonstrate one here:<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">zone \u201cservicedomain.com\u201d IN {\r\n    type master;\r\n    file \u201cnamed.servicedomain.com\u201d;\r\n    allow-update { none; }\r\n    allow-transfer { servers; };\r\n};<\/pre>\n<p>Here we are telling bind that it is a master server for the domain <strong>com<\/strong>. The naming convention for the zone files (which we will create later) is to prefix \u201c<strong>named.<\/strong>\u201d to the fully qualified domain name.<\/p>\n<p>We do not want to allow any other servers to update the domain records so we set <strong>allow-update<\/strong> to <strong>none<\/strong>. We are happy to allow transfers though, but only to our own servers hence:<\/p>\n<pre class=\"lang:sh highlight:0 decode:true \">allow-transfer { servers; };<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Zone files (master)<br \/>\n<\/strong><\/p>\n<p>The zone files are kept in \/var\/cache\/bind and will be called<\/p>\n<p style=\"margin-left: 40px;\">named.servicedomain.com<br \/>\nnamed.zone1.servicedomain.com<br \/>\nnamed.zone2.servicedomain.com<\/p>\n<p>We are only going to show how to configure 1 zone files here but before we do, a quick word on why we are creating zone files rather than just adding records to the servicedoamin.com zone. The reason is that later on when we get to our email validation configuration we will want to isolate certain records in order to prevent lookups from becoming convoluted. It will also be much easier to check our servers using online tools.<\/p>\n<p>Ok so now for our first zone servicedomain.com. First we will create the file<\/p>\n<pre class=\"lang:sh decode:true\">#touch \/var\/cache\/bind\/named.servicedomain.com<\/pre>\n<p>There are several ways to configure bind, each with their own merits, but for better or worse, this is the way we are doing it.<\/p>\n<p>The first line in the file is the \u201cORIGIN\u201d directive which is simply a dot \u2018.\u2019 to denote that there is nothing prepending the domain name record. This is my preferred way to create zones files because they are easily readable. Strictly you do not need to do it this way, but if you don\u2019t then it isn\u2019t clear from reading the contents of the file which zone it is supposed to be attributed to. So the first line in our zone file is:<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">$ORIGIN .<\/pre>\n<p>Note that the space between the dot and the declaration is important, without it the zone will not load.<\/p>\n<p>Now we can create our first record, which is our Start of Authority record. This is the record that tells other domain servers and clients which domain server is ultimately responsible for the domain. It also sets some parameters for the domain and assigns the record a serial number.\u00a0\u00a0 The serial number is what the slave servers rely upon to ensure they are up to date and it is usually a serialised version of the date. It is not important to know what the other paramters do, but the serial number must be incremented with every change.<\/p>\n<p>Here is the Start of Authority record for our servicedomain.com domain.<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">servicedomain.com\u00a0\u00a0\u00a0\u00a0 IN\u00a0\u00a0 SOA ns1.nameserverdomain.com yourname.emailaddress.com (\r\n                               2018060501;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 serial\r\n                               8H;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0refresh\r\n                               2H;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0retry\r\n                               4W;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0expire\r\n                               3600;\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0minimum\r\n                           )<\/pre>\n<p>NOTE: the part before the bracket \u2018(\u2018 should be on a single line. Just a quck word about the <strong>emailaddress.com<\/strong> section. This is to provide information about who you should email in the event of a problem however you will note that it does not use the standard email address naming convention. Suffice it to say <strong>yourname.emailaddress.com <\/strong>equateds to<strong> yourname@emailaddress.com<\/strong>. This email address does not need to be resolvable by your dns server so can be any valid email address.<\/p>\n<p>Even though we have told bind who is responsible for the start of authority, we still need to expressly define the nameservers (both master and slave). To do this we simply need to add<\/p>\n<pre class=\"lang:sh highlight:0 decode:true \">NS\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ns1.nameserverdomain.com\r\nNS\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ns2.nameserverdomain.com<\/pre>\n<p>underneath our SOA record.<\/p>\n<p>Note: Style convention says that you should keep the record type descriptions in line so you would type \u201cNS\u201d in line with \u201cSOA\u201d.<\/p>\n<p>The next thing to cerate is our \u2018A\u2019 records. Usually our top level domain is used for administration and perhaps a website so you may want pgadmin and www as your \u2018A\u2019 records, but this is very much dependent on your desired configuration.<\/p>\n<p>To save typing the full domain over and over again we create another ORIGIN:<\/p>\n<pre class=\"lang:sh highlight:0 decode:true \">$ORIGIN servicedomain.com.<\/pre>\n<p>Of particular interest and easy to miss is the dot \u2018.\u2019 after the \u201c.com\u201d. This is important because we are telling bind that there will be something appending this declaration.<\/p>\n<p>For our first record we do not want to append anything however because we want to resolve our whole domain, To tell bind to look no further we use the \u2018@\u2019 symbol.<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">@\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 A\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 123.123.123.1<\/pre>\n<p>after \u201c$ORIGIN servicedomain.com.\u201d will cause bind to resolve \u201cservicedomain.com\u201d to the ip address 123.123.123.1. Now say we wanted to resolve pgadmin.servicedomain.com we would add<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">pgadmin\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 A\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 123.123.123.1<\/pre>\n<p>to our list of \u2018A\u2019 records.<\/p>\n<p>You will note that the we are using the pubic IP address of the master server here but the address could be any server you desire (whether on your network or not).<\/p>\n<p>The other zone files will have an SOA record pointing to their respective fully qualified domains and there will be at least one \u2018A\u2019 record which will be<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">mail\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 A\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 123.123.123.1<\/pre>\n<p>on the master and<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">mail\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 A\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 169.169.169.1<\/pre>\n<p>on the slave.<\/p>\n<p>At this point we should have a working dns server. Run<\/p>\n<pre class=\"lang:sh decode:true\">#service bind9 start<\/pre>\n<p>and check the error logs. Bind logs errors to \/var\/log\/syslog so you can either run<\/p>\n<pre class=\"lang:sh decode:true\">#tail -f \/var\/log\/syslog<\/pre>\n<p>or<\/p>\n<pre class=\"lang:sh decode:true \">#cat \/var\/log\/syslog | grep bind<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Slave server zones<\/strong><\/p>\n<p>With the slave server it is only necessary to configure named.conf.default-zones as the zone files themselves will be grabbed from the master.<\/p>\n<p>The slave servers are very similar to the masters other than they declare their type to be \u201cslave\u201d and have a \u201cmasters\u201d directive. Each zone will have<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">zone \" servicedomain.com \" IN {\r\n    type slave;\r\n    masters { master_servers; };\r\n    file \" named.servicedomain.com \";\r\n    allow-transfer { servers; };\r\n}<\/pre>\n<p><strong>allow-transfers<\/strong> is the directive that permits the devices in the \u201c<strong>servers<\/strong>\u201d ACL to provide each other with administrative information.<\/p>\n<p>Once you have configured all your zones on your slave server, all you have to do is restart bind and provided that you have configured your servers properly the zone files will automatically be created (if not then the first place to start is to check the file permissions).<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Private zones<\/strong><\/p>\n<p>As well as serving your public DNS zones it is more than likely that you will want to resolve local intranet zones for services such as samba and ntp.<\/p>\n<p>With the exception that local zones will resolve to local ip addresses the creation of the zone files themselves is identical to the public zones. The major difference is that you only want to permit your local clients and servers to carry out the lookups (i.e. the <strong>trusted_anywhre<\/strong> ACL). In order to do this we need to override the configuration set in the \u201coptions\u201d directive by adding \u201c<strong>allow-query { trusted_anywhere; };<\/strong>\u201d to our zone<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">zone \"privatenet.local\" IN {\r\n    type master;\r\n    file \"named. privatenet.local\"\r\n    allow-update { none; };\r\n    allow-transfer { none; };\r\n    allow-query { trusted_anywhere; };\r\n};<\/pre>\n<p>Now when we create our zone our A records can use the private subnet and our local private network cannot be resolved from a public client or server (which is exactly what we want).<\/p>\n<p>There is no good reason for your private domain to have master and slave server (although you could create a backup server if you have a very complex configuration &#8211; this would be a slave server of sorts but it would not ordinarily resolve any queries, it would just store the zone information).<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Testing<\/strong><\/p>\n<p>We will start with the easy tests first. While logged on to a the terminal of your dns server:<\/p>\n<pre class=\"lang:sh decode:true\">#dig google.com @localhost<\/pre>\n<p>This should work at both the master and the slave server.<\/p>\n<p>NOTE: If you haven\u2019t got dig run <strong>apt-get install dnsutils<\/strong><\/p>\n<p>and make sure that something is returned like<\/p>\n<pre class=\"lang:sh highlight:0 decode:true \">; &lt;&lt;&gt;&gt; DiG 9.9.5-9+deb8u3-Debian &lt;&lt;&gt;&gt; google.com\r\n;; global options: +cmd\r\n;; Got answer:\r\n;; -&gt;&gt;HEADER&lt;&lt;- opcode: QUERY, status: NOERROR, id: 60632\r\n;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 4, ADDITIONAL: 5\r\n\r\n\r\n\r\n;; OPT PSEUDOSECTION:\r\n; EDNS: version: 0, flags:; udp: 4096\r\n;; QUESTION SECTION:\r\n;google.com.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 IN\u00a0\u00a0\u00a0\u00a0\u00a0 A\r\n\r\n\r\n\r\n;; ANSWER SECTION:\r\ngoogle.com.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 300\u00a0\u00a0 IN\u00a0\u00a0\u00a0\u00a0\u00a0 A\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 216.58.210.78\r\n\r\n\r\n\r\n;; AUTHORITY SECTION:\r\ngoogle.com.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 172799\u00a0\u00a0\u00a0\u00a0\u00a0 IN\u00a0\u00a0\u00a0\u00a0\u00a0 NS\u00a0\u00a0\u00a0\u00a0 ns1.google.com.\r\ngoogle.com.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 172799\u00a0\u00a0\u00a0\u00a0\u00a0 IN\u00a0\u00a0\u00a0\u00a0\u00a0 NS\u00a0\u00a0\u00a0\u00a0 ns3.google.com.\r\ngoogle.com.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 172799\u00a0\u00a0\u00a0\u00a0\u00a0 IN\u00a0\u00a0\u00a0\u00a0\u00a0 NS\u00a0\u00a0\u00a0\u00a0 ns4.google.com.\r\ngoogle.com.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 172799\u00a0\u00a0\u00a0\u00a0\u00a0 IN\u00a0\u00a0\u00a0\u00a0\u00a0 NS\u00a0\u00a0\u00a0\u00a0 ns2.google.com.\r\n\r\n\r\n\r\n;; ADDITIONAL SECTION:\r\nns1.google.com.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 172799\u00a0\u00a0\u00a0\u00a0\u00a0 IN\u00a0\u00a0\u00a0\u00a0\u00a0 A\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 216.239.32.10\r\nns2.google.com.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 172799\u00a0\u00a0\u00a0\u00a0\u00a0 IN\u00a0\u00a0\u00a0\u00a0\u00a0 A\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 216.239.34.10\r\nns3.google.com.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 172799\u00a0\u00a0\u00a0\u00a0\u00a0 IN\u00a0\u00a0\u00a0\u00a0\u00a0 A\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 216.239.36.10\r\nns4.google.com.\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 172799\u00a0\u00a0\u00a0\u00a0\u00a0 IN\u00a0\u00a0\u00a0\u00a0\u00a0 A\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 216.239.38.10\r\n\r\n\r\n\r\n;; Query time: 663 msec\r\n;; SERVER: 172.17.1.20#53(172.17.1.20)\r\n;; WHEN: Sat Nov 28 01:20:46 GMT 2015\r\n;; MSG SIZE rcvd: 191<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Testing recursion<\/strong><\/p>\n<p>Testing recursion can be a little difficult if you are behind a NAT because if the server your are configuring is behind the same NAT or is trusted then you may not get the results that you are expecting. The best way to check for recursion if this is the case is to use your phone. If you install <strong>termux<\/strong> on your phone you can then install dns utilities so that you can run dig from the command line. (if you type dig and it is not installed it will directy you on how to install it)<\/p>\n<p>With termux and dns utilities installed on your phone and wifi disabled when you run<\/p>\n<pre class=\"lang:sh decode:true\">#dig google.com @ns1.nameserverdomain.com<\/pre>\n<p>if your server is configured correctly the result shoud return a warning<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">;; WARNING: recursion requested but not available<\/pre>\n<p>Now if you run<\/p>\n<pre class=\"lang:sh decode:true\">#dig servicedomain @ns1.nameserverdomain.com<\/pre>\n<p>you should get a result in the answer section.<\/p>\n<p>Finally you can test name resolution from your private domain<\/p>\n<pre class=\"lang:sh decode:true\">#dig privatenet.local @ns1.nameserverdomain.com<\/pre>\n<p>should return a warning however if you run the same command from the server or a local client then you should get a proper result.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Logging<\/strong><\/p>\n<p>Bind uses the standard syslog so if you are debugging bind it is probably best to use grep named to filter out unwanted messages<\/p>\n<pre class=\"lang:sh decode:true\">#tail -f \/var\/log\/syslog | grep named<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>RNDC<\/strong><\/p>\n<p>Next check that rndc is working. If it is then ignore the RNDC steps:<\/p>\n<pre class=\"lang:sh decode:true\">#rndc status<\/pre>\n<p>should return something like<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">version: 9.9.5-9+deb8u3-Debian &lt;id:f9b8a50e&gt;\r\nCPUs found: 4\r\nworker threads: 4\r\nUDP listeners per interface: 4\r\nnumber of zones: 103\r\ndebug level: 0\r\nxfers running: 0\r\nxfers deferred: 0\r\nsoa queries in progress: 0\r\nquery logging is OFF\r\nrecursive clients: 0\/0\/1000\r\ntcp clients: 0\/100\r\nserver is up and running<\/pre>\n<p>if it does not then it is probably not configured.<\/p>\n<p>NOTE: If rndc is working out of the box then you will not find any of the directives below in the configuration files, you only need to add them if it is not working. I have built 2 machines so far and in one it just worked and in the other it didn&#8217;t and I had to go through this manual configuration. First run:<\/p>\n<pre class=\"lang:sh decode:true\">#rndc-confgen -a<\/pre>\n<p>which should return:<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">wrote key file \"\/etc\/bind\/rndc.key\"<\/pre>\n<p>now edit you \/etc\/bind\/named.conf by adding the following:<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">include \"\/etc\/bind\/rndc.key\";\r\n\r\ncontrols {\r\n    inet 127.0.0.1 allow { localhost; } keys { \"rndc-key\"; };\r\n};<\/pre>\n<p>At this point you should be able to restart bind and run rndc status.<\/p>\n<pre class=\"lang:sh decode:true\">#service bind restart\r\n#rndc status<\/pre>\n<p>Now further check that bind is running properly. I had some permission issues at this point, namely:<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">\/etc\/bind\/managed-keys.bind.jnl: create: permission denied<\/pre>\n<p>in order to resolve this you need to make sure that \/etc\/bind has the correct permissions. This should already have been done if you have followed this guide, but otherwise<\/p>\n<pre class=\"lang:sh decode:true\">#chown -R bind:bind \/etc\/bind\r\n#chown -R bind:bind \/var\/cache\/bind<\/pre>\n<p>Now edit the \/etc\/named.conf file by adding<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">include \"\/etc\/bind\/rndc.key\";<\/pre>\n<p>and named.conf.options by adding<\/p>\n<pre class=\"lang:sh highlight:0 decode:true\">managed-keys-directory \"\/etc\/bind\";<\/pre>\n<p>and finally bind was working as it should be. If you restart bind and have a load of ipv6 name resolution errors then ignore them, stop bind and wait for a few seconds then start it and get its status, it should be ok.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>FURTHER INFORMATION:<\/strong><\/p>\n<p>For slave servers you do not need to make the individual zone files (they will be created when bind is started (or at least they should be) you will have to configure and set the \/var\/cache\/bind directory and permissions though.<\/p>\n<p>If you want to reload a domain on a master then you will need to run the following:<\/p>\n<pre class=\"lang:sh decode:true\">#rndc freeze mydomain.com\r\n#rndc reload mydomain.com\r\n#rndc thaw mydomain.com<\/pre>\n<p>If you want to do the same thing but you have different &#8220;views&#8221; then you will need to append IN <i>viewname<\/i> to the commands.<\/p>\n<p>eg.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">#rndc freeze mydomain.com IN myview\r\n#rndc reload mydomain.com IN myview\r\n#rndc thaw mydomain.com IN myview<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Getting bind right can be a bit if a bind (if you pardon the pun) so in this example we are going to start be outlining what our zones actually do. servicedomain.com is the domain name that we purchased from our domain name supplier. mail.zone1.servicedomain.com will be the public name of our mail server (The [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10],"tags":[],"class_list":["post-127","post","type-post","status-publish","format-standard","hentry","category-debian-server"],"_links":{"self":[{"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/posts\/127","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=127"}],"version-history":[{"count":11,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/posts\/127\/revisions"}],"predecessor-version":[{"id":454,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=\/wp\/v2\/posts\/127\/revisions\/454"}],"wp:attachment":[{"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=127"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=127"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.inplico.uk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=127"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}