User Tools

Site Tools


computing:bind9dns

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
computing:bind9dns [2025/12/28 04:44] – oemb1905computing:bind9dns [2026/10/25 19:41] (current) – oemb1905
Line 29: Line 29:
   * Configuring your Registrar's GLUE records, i.e., registering and pointing nameservers   * Configuring your Registrar's GLUE records, i.e., registering and pointing nameservers
  
-This tutorial presumes you already have a working and sufficiently hardened VM/VPS with a LAMP stack and access to PTR for three different external IPs. If you don't know what some or all of that is, take a step back and start with [[https://wiki.haacksnetworking.org/doku.php?id=computing:apachesurvival|Apache Survival]] before proceeding. If you feel comfortable so far, and you have three different VMs/VPSs setup and ready, well then carry on. +This tutorial presumes you already have three working and sufficiently hardened VMs/VPSs with LAMP stacks and access to PTR for each of the three different external IPs they leverage, six if you include IPv6. If you don't know what some or all of that is, take a step back and start with [[https://wiki.haacksnetworking.org/doku.php?id=computing:apachesurvival|Apache Survival]] before proceeding. If you feel comfortable so far, and you have three different VMs/VPSs setup and ready, well then carry on. 
  
 ------------------------------------------- -------------------------------------------
Line 37: Line 37:
 Make sure that you set your full hostname with ''hostnamectl set-hostname nsX.haacksnetworking.com'' and/or equivalent for your use-case on each node. Of course, install bind9 with ''apt install bind9 bind9-utils bind9-dnsutils bind9-doc -y''. After that, ensure that each host has local DNS resolution via ''/etc/hosts/'' that informs each node about itself, its alias, and those of every other node in its cluster. Something like this will suffice (on each node): Make sure that you set your full hostname with ''hostnamectl set-hostname nsX.haacksnetworking.com'' and/or equivalent for your use-case on each node. Of course, install bind9 with ''apt install bind9 bind9-utils bind9-dnsutils bind9-doc -y''. After that, ensure that each host has local DNS resolution via ''/etc/hosts/'' that informs each node about itself, its alias, and those of every other node in its cluster. Something like this will suffice (on each node):
  
-<code bash>+<code>
 127.0.0.1       localhost 127.0.0.1       localhost
 127.0.1.1       ns1.haacksnetworking.com ns1 127.0.1.1       ns1.haacksnetworking.com ns1
Line 58: Line 58:
  
 Here is [[http://ns1.haacksnetworking.com|ns1.haacksnetworking.com]]: Here is [[http://ns1.haacksnetworking.com|ns1.haacksnetworking.com]]:
-<code bash>+<code>
 ufw reset ufw reset
 ufw default deny incoming ufw default deny incoming
Line 71: Line 71:
  
 Here is [[http://ns2.haacksnetworking.com|ns2.haacksnetworking.com]]: Here is [[http://ns2.haacksnetworking.com|ns2.haacksnetworking.com]]:
-<code bash>+<code>
 ufw reset ufw reset
 ufw default deny incoming ufw default deny incoming
Line 88: Line 88:
  
 Here is [[http://ns3.haacksnetworking.com|ns3.haacksnetworking.com]]: Here is [[http://ns3.haacksnetworking.com|ns3.haacksnetworking.com]]:
-<code bash>+<code>
 ufw reset ufw reset
 ufw default deny incoming ufw default deny incoming
Line 104: Line 104:
 </code> </code>
  
-As you can see, ns2 and ns3 restrict all access on 80/443 to ns1. This is because there is no need to access these nodes directly, as both bind9 and later webmin will directly instruct these slaves with their configurations. Ns1, on the other hand, should be publicly accessible by design. We will secure it later with a strong password (25 characters or more), a reverse proxy, and fail2ban. One can additionally, if they so choose, add source-IP rules to the master node, but I think this is overkill. In my case, I want the master node to be accessible to me everywhere. The 10000-10010 range is for the webmin clustering features. +As you can see, ns2 and ns3 restrict all access on 80/443 to ns1. This is because there is no need to access these nodes directly, as both bind9 and later webmin will directly instruct these slaves with their configurations. Ns1, on the other hand, should be publicly accessible by design. We will secure it later with a strong password (25 characters or more), a reverse proxy, and fail2ban. One can additionally, if they so choose, add source-IP rules to the master node, but I think this is overkill. In my case, I want the master node to be accessible to me everywhere. The 10000-10010 range is for the webmin clustering features. Of course, none of the above is helpful unless you've registered your intended name servers with your registrar and established your glue records. I use Dynadot, and you first register the name servers, associate the IPs, and then you can leverage those nameservers, just like their nameservers, globally throughout their DNS host panel. Here's  what the name registration panel looks like: 
 + 
 +{{ :computing:screenshot_from_2025-12-27_21-47-30.png?direct&800 |}} 
 + 
 +Once the basics of your nodes and your registrar have the prerequisite configurations in place, we can move on to configuring the Bind9 server. 
  
 === Part 2 - Setting up the Bind9 sever(s) === === Part 2 - Setting up the Bind9 sever(s) ===
Line 110: Line 114:
 We can now establish the root zone on the master (ns1) and then tie the two slaves to it. Let's open ''/etc/bind/named.conf.options'' and enter the following for the global configuration: We can now establish the root zone on the master (ns1) and then tie the two slaves to it. Let's open ''/etc/bind/named.conf.options'' and enter the following for the global configuration:
  
-<code bash>+<code>
 options { options {
     directory "/var/cache/bind";     directory "/var/cache/bind";
Line 133: Line 137:
 Now, let's establish the haacksnetworking.com zone, required for the GLUE records and proper functioning of the authoritative part of the authoritative DNS server. Let's open ''/etc/bind/named.conf.local'' and enter the following: Now, let's establish the haacksnetworking.com zone, required for the GLUE records and proper functioning of the authoritative part of the authoritative DNS server. Let's open ''/etc/bind/named.conf.local'' and enter the following:
  
-<code bash>+<code>
 zone "haacksnetworking.com" { zone "haacksnetworking.com" {
     type master;     type master;
Line 144: Line 148:
 Now that we've created the base server entry and created the master zone, we should restart the service and add a few items to the zone record file it creates for us. Let's do ''systemctl restart bind9'' and then edit ''/etc/bind/db.haacksnetworking.com''. Remember, all we've done so far is create the zone itself and establish the zone record file location. We now need to open that location and enter the records we need both for the bind9 server itself and all of the nodes. We can setup some other common records at the same time: Now that we've created the base server entry and created the master zone, we should restart the service and add a few items to the zone record file it creates for us. Let's do ''systemctl restart bind9'' and then edit ''/etc/bind/db.haacksnetworking.com''. Remember, all we've done so far is create the zone itself and establish the zone record file location. We now need to open that location and enter the records we need both for the bind9 server itself and all of the nodes. We can setup some other common records at the same time:
  
-<code bash>+<code>
 $TTL    86400 $TTL    86400
 @       IN      SOA     ns1.haacksnetworking.com. hostmaster.haacksnetworking.com. ( @       IN      SOA     ns1.haacksnetworking.com. hostmaster.haacksnetworking.com. (
Line 173: Line 177:
 In my case, I had previously been using ISP Config for another hobbyist domain (for the kids and cats). So, I also configured that zone at the CLI, also in ''/etc/bind/named.conf.local'', as follows: In my case, I had previously been using ISP Config for another hobbyist domain (for the kids and cats). So, I also configured that zone at the CLI, also in ''/etc/bind/named.conf.local'', as follows:
  
-<code bash>+<code>
 zone "felinefantasy.club" { zone "felinefantasy.club" {
     type master;     type master;
Line 182: Line 186:
 </code> </code>
  
-Now that the family and cat website zone is created, we need to establish its DNS records again as well:+Now that the family and cat website zone is re-created, we can now establish its DNS records in the zone record file in ''/var/cache/bind/db.felinefantasy.club'' as follows:
  
-<code bash>$TTL 86400+<code> 
 +$TTL 86400
 @ IN SOA ns1.haacksnetworking.com. hostmaster.haacksnetworking.com. ( @ IN SOA ns1.haacksnetworking.com. hostmaster.haacksnetworking.com. (
     2025122311     2025122311
Line 207: Line 212:
 Now that we've created our base server and two zones, we can configure ns2 and ns3 as slaves. This is a one-time manual change that's required when doing all of this via the CLI. Eventually, we will cluster our instances using webmin which will create the zone file on the slaves upon creation on the master. At present, however, we are still covering how to do this manually using the CLI. Accordingly, here is the CLI stuffs we need to do on ns2 and ns3 in ''/etc/bind/named.conf.local'' on each node (one-time only): Now that we've created our base server and two zones, we can configure ns2 and ns3 as slaves. This is a one-time manual change that's required when doing all of this via the CLI. Eventually, we will cluster our instances using webmin which will create the zone file on the slaves upon creation on the master. At present, however, we are still covering how to do this manually using the CLI. Accordingly, here is the CLI stuffs we need to do on ns2 and ns3 in ''/etc/bind/named.conf.local'' on each node (one-time only):
  
-<code bash>+<code>
 zone "haacksnetworking.com" { zone "haacksnetworking.com" {
     type slave;     type slave;
Line 236: Line 241:
 At this point, we're still dealing strictly with bind9 and have not setup webmin or the automated clustering features. We will do that soon, but there's still one thing we need to cover how to do on the command line and that's DNSSEC. Below, let's create keys in the proper directory (mind this) and then sign them: At this point, we're still dealing strictly with bind9 and have not setup webmin or the automated clustering features. We will do that soon, but there's still one thing we need to cover how to do on the command line and that's DNSSEC. Below, let's create keys in the proper directory (mind this) and then sign them:
  
 +<code>
 cd /var/cache/bind cd /var/cache/bind
 dnssec-keygen -a ED25519 -b 256 -n ZONE haacksnetworking.com dnssec-keygen -a ED25519 -b 256 -n ZONE haacksnetworking.com
Line 241: Line 247:
 SALT=$(openssl rand -hex 8) SALT=$(openssl rand -hex 8)
 dnssec-signzone -S -K /var/cache/bind -A -3 $SALT -N INCREMENT -o haacksnetworking.com -t db.haacksnetworking.com dnssec-signzone -S -K /var/cache/bind -A -3 $SALT -N INCREMENT -o haacksnetworking.com -t db.haacksnetworking.com
 +</code>
  
 You can of course just run the ''openssl'' salt generation command by itself and manually insert the value, but someone had this online and I thought it was cool to share, whereby it creates a variable called SALT and then populates it into the subsequent command. Hilarious, and entirely not needed, but super fun. Once this is done, you've built the keys, you've signed the domain with them, and now you need to change the ''named'' entry to reflect the signed zone instead, and then finally update your registrar with the key and key values that you chose. First, let's update ''nano /etc/bind/named.conf.local'' with the signed record file location, for which I am using the ''felinefantasy.club'' zone record as an example, but this would apply to whatever zone you signed: You can of course just run the ''openssl'' salt generation command by itself and manually insert the value, but someone had this online and I thought it was cool to share, whereby it creates a variable called SALT and then populates it into the subsequent command. Hilarious, and entirely not needed, but super fun. Once this is done, you've built the keys, you've signed the domain with them, and now you need to change the ''named'' entry to reflect the signed zone instead, and then finally update your registrar with the key and key values that you chose. First, let's update ''nano /etc/bind/named.conf.local'' with the signed record file location, for which I am using the ''felinefantasy.club'' zone record as an example, but this would apply to whatever zone you signed:
  
-<code bash>+<code>
 zone "felinefantasy.club" { zone "felinefantasy.club" {
     type master;     type master;
Line 250: Line 257:
     allow-transfer { 8.28.86.114; 8.28.86.115; 2604:fa40:0:10::12; 2604:fa40:0:10::13; };     allow-transfer { 8.28.86.114; 8.28.86.115; 2604:fa40:0:10::12; 2604:fa40:0:10::13; };
     also-notify { 8.28.86.114; 8.28.86.115; 2604:fa40:0:10::12; 2604:fa40:0:10::13; };     also-notify { 8.28.86.114; 8.28.86.115; 2604:fa40:0:10::12; 2604:fa40:0:10::13; };
 +    };
 </code> </code>
  
Line 267: Line 275:
 Enter all of these values, adjusting as needed, into your registrar's DNSSEC section for this particular domain and you should be good to go. With this, we've completed the CLI portion of this tutorial. You can now, create a master bind9 server, two zones, two slaves that assist that master, and DNSSEC for any of those created zones/domains. The only caveat is that bind9 lacks an internal clustering system, so you do have to do the one-time config entry on each slave any time you create a new zone. This instructs the slave that it is an authority for this record and informs it as to who its master is for that zone/record. Our next job is to cover how to setup webmin and how to confgiure webmin to perform the same tasks we just did in the CLI with its bind9 web interface. Before moving on, make sure to verify your DNSSEC record with dig as follows ''dig felinefantasy.club DNSKEY +dnssec @8.28.86.113''. You should see some output resembling: Enter all of these values, adjusting as needed, into your registrar's DNSSEC section for this particular domain and you should be good to go. With this, we've completed the CLI portion of this tutorial. You can now, create a master bind9 server, two zones, two slaves that assist that master, and DNSSEC for any of those created zones/domains. The only caveat is that bind9 lacks an internal clustering system, so you do have to do the one-time config entry on each slave any time you create a new zone. This instructs the slave that it is an authority for this record and informs it as to who its master is for that zone/record. Our next job is to cover how to setup webmin and how to confgiure webmin to perform the same tasks we just did in the CLI with its bind9 web interface. Before moving on, make sure to verify your DNSSEC record with dig as follows ''dig felinefantasy.club DNSKEY +dnssec @8.28.86.113''. You should see some output resembling:
  
-<code bash>+<code>
 ; <<>> DiG 9.20.15-1~deb13u1-Debian <<>> felinefantasy.club DNSKEY +dnssec @8.28.86.113 ; <<>> DiG 9.20.15-1~deb13u1-Debian <<>> felinefantasy.club DNSKEY +dnssec @8.28.86.113
 ;; global options: +cmd ;; global options: +cmd
Line 329: Line 337:
 At this point, you should now have a cert for nsX.haacksnetworking.com. We can now swap the vhosts with our reverse proxy configurations and they will just work like magic when we restart the service. First, let's change our http vhost in ''/etc/sites-enabled'' to the following: At this point, you should now have a cert for nsX.haacksnetworking.com. We can now swap the vhosts with our reverse proxy configurations and they will just work like magic when we restart the service. First, let's change our http vhost in ''/etc/sites-enabled'' to the following:
  
-<code bash>+<code>
 <VirtualHost *:80> <VirtualHost *:80>
     ServerName ns1.haacksnetworking.com     ServerName ns1.haacksnetworking.com
Line 343: Line 351:
 And, for https vhost in ''/etc/apache2/sites-enabled'', use the following: And, for https vhost in ''/etc/apache2/sites-enabled'', use the following:
  
-<code bash>+<code>
 <VirtualHost *:443> <VirtualHost *:443>
  
Line 395: Line 403:
 {{ :computing:screenshot_from_2025-12-27_21-06-35.png?direct&800 |}} {{ :computing:screenshot_from_2025-12-27_21-06-35.png?direct&800 |}}
  
-Once you do that, we can create a zone. do cloudcommunity as example ... to be consistent with CLI / webmin gui divide.+Before we create our first master zone using webmin's bind9 GUI, let's activate rndc. To do that, navigate to Bind9 Server > Setup RNDC. Here's what that looks like below. Just click yes, and you are all set:
  
-  image of that+{{ :computing:screenshot_from_2025-12-27_22-35-32.png?direct&800 |}}
  
-Later on, once zone is created, it should be noted that the webmin tooling creates a redundant transfer to rule on the slaves. It can be left and is harmless, but here's where it populates in case you are curious. (If you know how to disable this, ping me on Matrix):+Once you do that, we can now create a new master zone. Here's what that looks like. For me, all the default values are fine:
  
-{{ :computing:screenshot_from_2025-12-27_21-16-25.png?direct&800 |}}+{{ :computing:screenshot_from_2025-12-27_22-06-24.png?direct&800 |}}
  
-Set up rndc in webmin gui+Doing this creates the zone on ns1. It looks a little different structurally than what I created on the CLI, but syntactically, it is equivalent. It used a different naming convention for the name of the zone file, but it is completely arbitrary. Here is ''/etc/bind/named.conf.local'' on ns1 for the newly created zone:
  
-  image of that+<code> 
 +zone "cloudcommunity.club" { 
 +        type master; 
 +        file "/var/cache/bind/cloudcommunity.club.hosts.signed"; 
 +        allow-transfer { 
 +                8.28.86.114; 
 +                8.28.86.115; 
 +                2604:fa40:0:10::12; 
 +                2604:fa40:0:10::13; 
 +                }; 
 +        also-notify { 
 +                8.28.86.114; 
 +                8.28.86.115; 
 +                2604:fa40:0:10::12; 
 +                2604:fa40:0:10::13; 
 +                }; 
 +        }; 
 +</code> 
 + 
 +The IPv6 addresses above did not populate despite me having those entered in webmin under Bind9 Server > Zone defaults. You can see them in that area below and you can see that a test.club domain lacks them despite being populated there as seen in the screenshot below: 
 + 
 +{{ :computing:screenshot_from_2025-12-27_22-16-32.png?direct&800 |}} 
 + 
 +This glitch is a bit annoying, but it is not strictly required for the zone to function as only IPv4 is sufficient. If, however, you want to add the IPv6 entries, you do so by navigating to Bind9 Server > Zone Name > Edit Zone Options and simply add them: 
 + 
 +{{ :computing:screenshot_from_2025-12-27_22-11-48.png?direct&800 |}} 
 + 
 +It is not required to change anything on the slaves because these are master node entries and the slaves don't require any of these blocks. The slaves, on the other hand, have created corresponding zone entries like follows in ''/etc/bind/named.conf.local'': 
 + 
 +<code> 
 +zone "cloudcommunity.club" { 
 +        type slave; 
 +        masters { 
 +                8.28.86.113; 
 +                2604:fa40:0:10::11; 
 +                }; 
 +        allow-transfer { 
 +                8.28.86.113; 
 +                2604:fa40:0:10::11; 
 +                }; 
 +        file "/var/lib/bind/cloudcommunity.club.hosts"; 
 +        }; 
 +</code> 
 + 
 +Webmin redundantly creates the transfer rule, but that won't hurt or change anything because it is moot due to the ''type slave;'' declaration earlier. Therefore, this can be left along during initial zone and record creation as it is harmless. If you want to remove those redundant entries, you go to Webmin on ns1 > Webmin Servers Index > Click ns2 or ns3 as needed > Bind9 Server > Zone > Edit Zone Options. In there, you can easily remove the redundant entries: 
 + 
 +{{ :computing:screenshot_from_2025-12-27_21-16-25.png?direct&800 |}}
  
-Once we do that, we show examples of how to create A, AAAA, SPF, and dmarc. NOTE: Remember to test the populate with "dmarc" and verify back end becomes "_dmarc" web gui quirk when populating this tutorial portion+Of course, you could also shell into the slaves and remove those transfer rules via the CLI, this is just to show that both methods work and are dealing with the exact same bind9 underbelly. Once we do that, we can !!FINALLY!! create A, AAAA, dmarc, spf, and or any other records we need. Here's what the zone's landing page looks like and what the record pages within it look like:
  
-  images of that stuff+{{ :computing:screenshot_from_2025-12-27_22-37-52.png?direct&800 |}} 
 +{{ :computing:screenshot_from_2025-12-27_22-38-38.png?direct&800 |}} 
 +{{ :computing:screenshot_from_2025-12-27_22-39-12.png?direct&800 |}} 
 +{{ :computing:screenshot_from_2025-12-27_22-40-16.png?direct&800 |}}
  
 Now, we do some host testing again. Repeat host commands above Now, we do some host testing again. Repeat host commands above
Line 417: Line 474:
   host cloudcommunity.club ns3.haacksnetworking.com   host cloudcommunity.club ns3.haacksnetworking.com
      
-Once that's working, let's setup DNSSEC using the webmin gui on master ns1.+Once that's working, let's setup DNSSEC using the webmin gui on master ns1. To do that navigate to Bind9 DNS Server > Zone > Setup DNS Key:
  
-  image of that+{{ :computing:screenshot_from_2025-12-27_22-50-57.png?direct&8800 |}} 
 +   
 +Once the DNSSEC key is created and the zone signed, you will, just like above, have to navigate over to your registrar and enter in the algorithm, digest, digest tag, and key tag. To see those values, just select Bind9 DNS Server > Zone > Setup DNS Key and instead of showing you the option to create it anew, it now shows the key you just created:
  
-Add section above to use dig in order to verify DNSSEC and then use that down here as well in the test section+{{ :computing:screenshot_from_2025-12-27_22-55-45.png?direct&800 |}} 
 +   
 +As a final step, we can use the dig command to verify the record against all nodes:
  
-  dig command+  dig cloudcommunity.club DNSKEY +dnssec @8.28.86.113 
 +  dig cloudcommunity.club DNSKEY +dnssec @8.28.86.114 
 +  dig cloudcommunity.club DNSKEY +dnssec @8.28.86.115
      
-Verify what webmin is doing under the hood. Show examples of the slave entries it makes in named on ns2 and ns3 on the CLI but via webmin. Similarly, show a screen shot of the zone record file for cloudcommunity.club that it created. Now that this is done, we can optionally secure each node with unbound DNS for added privacy and speed.+Each node should report the following: 
 + 
 +<code> 
 +; <<>> DiG 9.20.15-1~deb13u1-Debian <<>> cloudcommunity.club DNSKEY +dnssec @8.28.86.113 
 +;; global options: +cmd 
 +;; Got answer: 
 +;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 21022 
 +;; flags: qr aa rd; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1 
 +;; WARNING: recursion requested but not available 
 + 
 +;; OPT PSEUDOSECTION: 
 +; EDNS: version: 0, flags: do; udp: 1232 
 +; COOKIE: f9d0bef39e0c56da010000006950c6e270c6a99b26e97171 (good) 
 +;; QUESTION SECTION: 
 +;cloudcommunity.club. IN DNSKEY 
 + 
 +;; ANSWER SECTION: 
 +cloudcommunity.club. 3600 IN DNSKEY 256 3 15 yCykkNhKUB0H3F7B+F1ydS6lmTaQAhRkVLgq6Fy6xWo= 
 +cloudcommunity.club. 3600 IN DNSKEY 257 3 15 g61Yq+dJTUxZpQDvQfqqK59CUv3IsDXyO8Sy229YVic= 
 +cloudcommunity.club. 3600 IN RRSIG DNSKEY 15 2 3600 20260123020922 20251224020922 188 cloudcommunity.club. sbVDXR4RZpR0s2eXn3wyyJ4JGO2AZpX/81UiOp/6fv9BWlVhkGXnsr50 JMHTFiKTVRwPtfRFONdrU1VUhrScDQ== 
 +cloudcommunity.club. 3600 IN RRSIG DNSKEY 15 2 3600 20260123020922 20251224020922 30893 cloudcommunity.club. AjoUcCUneoXo/sTDgyfbAJV5wc/TxuJN50Uhs2WY6B8FfBV586ZCcell ztTYercorXsQf1mtHXpSh5bKZBscCg== 
 + 
 +;; Query time: 100 msec 
 +;; SERVER: 8.28.86.113#53(8.28.86.113) (UDP) 
 +;; WHEN: Sat Dec 27 22:57:54 MST 2025 
 +;; MSG SIZE  rcvd: 402 
 +</code> 
 + 
 +=== Part 4 - Optional Unbound Recursive Resolver === 
 + 
 +Now that you can create any record you please and sign your zones/domains with DNSSEC using both the CLI and the webmin Bind9 DNS server GUI, we can optionally secure each node with unbound DNS for added privacy and speed.
  
   sudo apt install unbound   sudo apt install unbound
      
-The full unbound tutorial, including lan-side setups, can be found here. For this setup, a simple config such as this should work:+The full unbound tutorial, including lan-side setups, can be found [[https://wiki.haacksnetworking.org/doku.php?id=computing:unbounddns|Unbound]]. For this setup, however, a simple config in ''/etc/unbound/unbound.conf'' such as this should work:
  
-  provide my public config+  server: 
 +    # Bind to localhost only 
 +    interface: 127.0.0.1 
 +    interface: ::1 
 +    port: 5335 
 +    do-ip4: yes 
 +    do-ip6: yes 
 +    prefer-ip6: yes 
 +    access-control: 127.0.0.0/8 allow 
 +    access-control: 0.0.0.0/0 refuse 
 +    access-control: ::0/0 refuse 
 +    # Optimize for 8 cores 
 +    num-threads: 4 
 +    msg-cache-slabs: 4 
 +    rrset-cache-slabs: 4 
 +    infra-cache-slabs: 4 
 +    key-cache-slabs: 4 
 +    # Cache settings for high query volume 
 +    cache-max-ttl: 86400 
 +    cache-min-ttl: 3600 
 +    rrset-cache-size: 128m 
 +    msg-cache-size: 64m 
 +    key-cache-size: 32m 
 +    neg-cache-size: 8m 
 +    # Enable prefetch and expired responses 
 +    prefetch: yes 
 +    prefetch-key: yes 
 +    serve-expired: yes 
 +    serve-expired-ttl: 3600 
 +    # DNSSEC validation for DANE 
 +    #do-dnssec: yes 
 +    harden-dnssec-stripped: yes 
 +    harden-referral-path: yes 
 +    harden-below-nxdomain: yes 
 +    harden-algo-downgrade: no 
 +    # Performance tweaks 
 +    #so-rcvbuf: 4m 
 +    #so-sndbuf: 4m 
 +    edns-buffer-size: 1232 
 +    outgoing-range: 4096 
 +    num-queries-per-thread: 1024 
 +    jostle-timeout: 200 
 +    #low-resolver-mem: no 
 +    # Logging (minimal) 
 +    verbosity: 1 
 +    log-queries: no 
 +    log-replies: no 
 +    use-syslog: yes 
 +    # Security and privacy 
 +    hide-identity: yes 
 +    hide-version: yes 
 +    use-caps-for-id: yes 
 +    qname-minimisation: yes 
 +    harden-large-queries: yes 
 +    harden-glue: yes 
 +    aggressive-nsec: yes 
 +    # Protocol settings 
 +    do-tcp: yes 
 +    do-udp: yes 
 +    # Disable subnetcache 
 +    module-config: "validator iterator"
      
 It's crucial to bind unbound to 5335 since bind9 is already listening on 53. In order to have local recursive queries use unbound, we need to hijack all outbound resolver queries to ''/etc/resolv.conf'' to use 5335. To be clear, make sure ''/etc/resolv.conf'' has the following entries: It's crucial to bind unbound to 5335 since bind9 is already listening on 53. In order to have local recursive queries use unbound, we need to hijack all outbound resolver queries to ''/etc/resolv.conf'' to use 5335. To be clear, make sure ''/etc/resolv.conf'' has the following entries:
Line 440: Line 593:
 After that, adjust the ufw rules to hijack all 53 url queries and send them to 5335. Open ''/etc/ufw/before.rules'' and enter the following block at the end: After that, adjust the ufw rules to hijack all 53 url queries and send them to 5335. Open ''/etc/ufw/before.rules'' and enter the following block at the end:
  
-<code bash>+<code>
 # === Added NAT table for local DNS redirection to Unbound on port 5335 === # === Added NAT table for local DNS redirection to Unbound on port 5335 ===
 *nat *nat
Line 455: Line 608:
 </code> </code>
  
 +Make sure you can ping a common website on both ipv4 and ipv6 and you should be good to go:
 +
 +  ping4 google.com
 +  ping6 google.com
 +  
 +If you are interested in setting up one of these authoritative Bind9 DNS clusters that are configured to use either CLI or the convenient webmin interface, just hit me up on Matrix. I'm available here:
 +
 +  * [[https://matrix.to/#/@haacksnetworking:gnulinux.club|Haack's Networking on Matrix]]
 +
 +Updates ... tmp directory was too small:
 +
 +  sudo mkdir -p /webmin/tmp
 +  sudo chown root:root /webmin/tmp
 +  sudo chmod 700 /webmin/tmp
 +  
 +After that, navigate to Webmin Settings > Webmin Configuration and then specify custom tmp directory and enter ''/webmin/tmp''. Even if/when fail2ban is setup, enough brute force attempts can still trigger webmin's internal security. In order to stop that from happening, enable apache's module for source IP restrictions with ''sudo a2enmod authz_host'' and then specify approved IPs in your vhost as follows:
 +
 +<code>
 +<VirtualHost *:80>
 +    ServerName ns1.haacksnetworking.com
 +        <Location />
 +                Require ip 185.242.226.78
 +                Require ip 2606:4700:3037::6815:4f2f
 +        </Location>    
 +    RewriteEngine On
 +    RewriteCond %{HTTPS} off
 +    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
 +    ProxyPass /.well-known !
 +</VirtualHost>
 +</code>
 +
 +Alternately, you can setup a custom fail2ban jail. While fail2ban already has a built-in jail called webmin-auth, this jail only works for direct logins via domain:10000 - it does nothing if webmin is behind a reverse proxy (which it should be). By using a reverse proxy, we are letting a much more mature and reliable tool face the public, but/and we still need to configure it to query bad log in attempts and block those IPs. First, create the filter:
 +
 +<code>
 +sudo nano /etc/fail2ban/filter.d/webmin-apache.conf
 +[Definition]
 +failregex = ^<HOST> -.*"(GET|POST) /session_login\.cgi.*HTTP/.*" (200|401|403)
 +ignoreregex = ^<HOST> -.*"POST /session_login\.cgi.*HTTP/.*" 302
 +</code>
 +
 +After the filter is created, let's establish the jail:
 +
 +<code>
 +sudo nano /etc/fail2ban/jail.local
 +[webmin-apache]
 +enabled   = true
 +port      = http,https
 +filter    = webmin-apache
 +logpath   = /var/log/apache2/access.log
 +          /var/log/apache2/other_vhosts_access.log
 +maxretry  = 3
 +#findtime  = 10m #optional jail-only directive
 +#bantime   = 1h #optional jail-only directive
 +</code>
  
 +Once you have setup the filter and jail, reload the configuration ''sudo fail2ban-client reload
 +sudo'' and ''fail2ban-client status webmin-apache'' and then periodically check the jail and/or your email reports and you should see some bans start coming in. You can optionally keep this and apache's source IP rules in place for extra security. Likewise, if the firewall fails and/or someone somehow starts hammering on domain.com:10000 directly, you can also safely keep the default webmin-auth jail activated for even more failover/backup security.
  
- --- //[[alerts@haacksnetworking.org|oemb1905]] 2025/12/28 03:42//+ --- //[[alerts@haacksnetworking.org|oemb1905]] 2026/10/24 13:41//
computing/bind9dns.1766897099.txt.gz · Last modified: by oemb1905