| Both sides previous revisionPrevious revisionNext revision | Previous revision |
| computing:bind9dns [2025/12/28 08:21] – oemb1905 | computing:bind9dns [2026/10/25 19:41] (current) – oemb1905 |
|---|
| 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 |
| |
| 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 |
| |
| 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 |
| |
| 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 |
| 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"; |
| 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; |
| 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. ( |
| 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; |
| 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: | 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 |
| 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; |
| 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 |
| 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; |
| 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> |
| |
| 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 |
| 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 |
| 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> |
| |
| 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: | 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: |
| |
| <code bash> | <code> |
| zone "cloudcommunity.club" { | zone "cloudcommunity.club" { |
| type master; | type master; |
| 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'': | 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 bash> | <code> |
| zone "cloudcommunity.club" { | zone "cloudcommunity.club" { |
| type slave; | type slave; |
| {{ :computing:screenshot_from_2025-12-27_21-16-25.png?direct&800 |}} | {{ :computing:screenshot_from_2025-12-27_21-16-25.png?direct&800 |}} |
| |
| 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. | 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: |
| | |
| image?? | |
| | |
| Once we do that, we can 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: | |
| |
| {{ :computing:screenshot_from_2025-12-27_22-37-52.png?direct&800 |}} | {{ :computing:screenshot_from_2025-12-27_22-37-52.png?direct&800 |}} |
| Each node should report the following: | Each node should report the following: |
| |
| <code bash> | <code> |
| ; <<>> DiG 9.20.15-1~deb13u1-Debian <<>> cloudcommunity.club DNSKEY +dnssec @8.28.86.113 | ; <<>> DiG 9.20.15-1~deb13u1-Debian <<>> cloudcommunity.club DNSKEY +dnssec @8.28.86.113 |
| ;; global options: +cmd | ;; global options: +cmd |
| 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 |
| * [[https://matrix.to/#/@haacksnetworking:gnulinux.club|Haack's Networking on Matrix]] | * [[https://matrix.to/#/@haacksnetworking:gnulinux.club|Haack's Networking on Matrix]] |
| |
| --- //[[alerts@haacksnetworking.org|oemb1905]] 2025/12/28 04:50// | 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]] 2026/10/24 13:41// |