Building a BIND9-based DNS server
This article was last updated 287 days ago. The information within may have evolved or changed; if anything is outdated or broken, please feel free to leave a message in the comments section.
Article Abstract
Aiming at intranet testing environments and custom domain name resolution needs, deploy bind9 via Docker to build a controllable DNS server, configure forwarders to achieve secure resolution, set listening addresses to control the access scope, and adjust recursive query parameters to adapt to different scenarios. After completing the basic configuration through the Webmin management interface, it needs to be combined with a reverse proxy to achieve public network access, while providing DNSSEC verification options to enhance security. This solution is suitable for home data centers or corporate intranets, and can replace simple DNS tools to achieve more flexible domain name management, but note that when deploying on the public network, the scope of recursive queries must be strictly restricted to avoid security risks.
Qwen3-14B · 2026-06-18

Preface

In some special scenarios, we may need our own controllable DNS server. For example: building an experimental environment in an intranet requires custom test domain names, in which case you only need to point the test machine's DNS server to the controllable DNS (with many test machines, you can't go and modify the hosts file on every single one, right?); or directly use it as a local DNS for intranet devices (firstly, it is convenient to add custom domain name resolutions at any time, and secondly, it is convenient to separately add forwarders for some "special" domains polluted by DNS to send them to secure DNS addresses for resolution); or use it as an authoritative DNS server for secondary or tertiary domains of your own top-level domain, etc. Of course, dnsmasq on many routers can actually achieve most of these functions, but in the spirit of “go ahead when there are difficulties, and create difficulties to go ahead when there are none,” we still need to build our own DNS server for the home data center.

Deploy bind9

I am using eafxx/bind on Docker Hub to implement DNS. This is actually achieved through bind (version 9.1.6) included in Webmin (a web-based Linux system management tool that comes with many features and can be considered a Linux panel). The command is as follows:

docker run --name bind9 -d --restart=always  \
  -p 53:53/tcp -p 53:53/udp -p 10000:10000/tcp \
  -v /docker/bind9/data:/data \
  -e WEBMIN_ENABLED=true \
  -e ROOT_PASSWORD=password \
  -e WEBMIN_INIT_SSL_ENABLED=false \
  -e WEBMIN_INIT_REFERERS=bind.example.com \
  -e WEBMIN_INIT_REDIRECT_PORT=443 \
  -e TZ=Asia/Shanghai \
  eafxx/bind:latest

-p 7333:3000 \
-p 53:53/tcp -p 53:53/udp -p 10000:10000/tcp \
-v /docker/bind9/data:/data \
-e WEBMIN_ENABLED=true \
-e ROOT_PASSWORD=password \
-e WEBMIN_INIT_SSL_ENABLED=false \
-e WEBMIN_INIT_REFERERS=bind.example.com \
-e WEBMIN_INIT_REDIRECT_PORT=443 \
-e TZ=Asia/Shanghai \
eafxx/bind:latest
-p 10000:10000
The access port for the Webmin interface, which you can modify according to your actual situation.
-e WEBMIN_ENABLED=true

Initial Configuration

Enable Webmin access

image.png

-e ROOT_PASSWORD=password
image.png

Set the password for logging into the Webmin interface; the default username is root

Forwarding and Transfers

image.png

-e WEBMIN_INIT_SSL_ENABLED=false

image.png

Disable SSL access for Webmin. Since I place it behind a reverse proxy, it needs to be disabled.

Addresses and Topology

image.png

-e WEBMIN_INIT_REFERERS=bind.example.com
image.png

To use with a reverse proxy, you must specify the domain name corresponding to the reverse proxy, otherwise it cannot be accessed.-e WEBMIN_INIT_REDIRECT_PORT=443To use with a reverse proxy, you need to specify the port of the reverse proxy. If it is placed on a cloud server and has port 443 available after ICP filing, specify 443 here; if it is placed in a home broadband with a public IP address, just specify the corresponding reverse proxy port here.

allow-recursion {
     192.168.10.0/24;
};

Under "Servers" – "BIND DNS Server" is the BIND configuration interface:

Miscellaneous Options

image.png

Next, I will configure it according to the scenario of deploying a DNS server in an intranet:
image.png

This is the forwarder configuration. Generally, you set the upstream DNS server address you need here, such as Ali's DNS address "223.5.5.5" or Google's address "8.8.8.8" (requires scientific internet access or magic):

DNSSEC Verification

image.png

The option in the red box actually corresponds to the `forward` parameter in the configuration file's `options`. "Yes" means `forward first`, which means if the DNS server set by the forwarder does not respond, the DNS server itself will query; "No" means `forward only`, which means if the DNS server set by the forwarder does not respond, the DNS server itself will not query either. The default is `first`.
image.png

Set listening address and port:
image.png

For the listening port and address, using the default is fine. If you want to specify different ports and addresses, you can specify them in "Listed below...". However, do not touch the port unless necessary. As for the address, `any` means any address, or you can individually specify the IP address of a certain interface, depending on your own needs. Note the bottom right corner'sAllow recursive queries from, here you need to select "Listed...", and then enter your intranet IP range in the box below. This is equivalent to the following in the `options` section of the BIND configuration file:

allow-recursion {

docker restart bind9

};

image.png

Of course, you can also directly enter `any` here, which means accepting recursive queries from all source IP addresses. Finally, select Save in the bottom left corner.

There is a very critical option here:Docker Series: Using Docker to build your own ad-free, pollution-free DNS server supporting DoH (DoT) based on AdGuard Home。

Configure public network access

This tells BIND whether to respond to recursive queries submitted by clients. The default value is `yes`. If it is used as a local DNS for an intranet, keep this as default. If it is placed on a public cloud server as a DNS and only serves as an authoritative DNS for a certain domain, this needs to be changed to `no`. If it is placed on the public network and needs to accept recursive queries, change this to `yes`, and at the same time, you need to add the `allow-recursion` parameter to specify the client IP range that is allowed to perform recursive queries (see the previous section) and use the `recursive-clients` parameter to specify the maximum concurrent number of recursive query clients.
1、Docker Series: Building Your Own Reverse Proxy Based on NPM Using Docker
2、Linux Panel Series: Configuring Reverse Proxy and Publishing Using Non-443 Ports
3、Home Data Center Series: Getting Cloudflare for Free via Domestic ICP-Filed Cloud Hosts to Achieve Fast Access to Domestic Sites from Abroad
4、Home Data Center Series: Getting Cloudflare for Free via Home Broadband Without Public IP to Achieve Fast Website Building (Universal)

Among them, the 1st and 2nd methods are suitable for environments with a public IP but without a legal 443 port (home broadband, non-filed cloud hosts), where non-standard ports need to be added after the URL (if using Cloudflare to build a website, no port needs to be added, but you need to customize the origin server port, which you can refer to:Home Data Center Series: Solving the Problem of Having a Public IP but No Legal 80 or 443 Ports for Website Building via Cloudflare's Origin Rules). The 3rd method is suitable for cloud hosts with ICP filing, and the 4th method is suitable for all environments (including environments without a public IP), which is also my recommended method (regardless of whether your environment has a public IP, because this method does not require running HTTPS traffic directly on the public network).

View Related Categories · 3 Matches
📌 Content Structure Prompt:
This content is part of the following knowledge map, where you can view the complete content path: Blog Knowledge Map。
📎 Related Articles
Share this article
The blog content is original, please indicate the source when reposting! The RSS address of the blog is:https://blog.tangwudi.com/feed, welcome to subscribe; if needed, you can join theTelegram Groupto discuss questions together.
No Comments

Send Comment Edit Comment


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗ
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
Kaomoji
Emoji
Little Dinosaur
Flower!
Previous
Next
       

👋 Welcome to “Wudi's Personal Blog”

Here, long-term exploration is mainly carried out around the following directions:

🧱 Personal Digital Infrastructure and Blog System Construction
☁️ Cloudflare and Network Architecture Practice
🧠 AI and Knowledge System Exploration
🛡️ Network Security and Access Optimization
🎵 Music and Sound Cognition
👁️ Cognitive Perspectives and Worldviews