A lightweight DNS server for homelabs: local records, ad-blocking, VLAN segmentation, and DoT support. No database, no web UI, just DNS.
BMDNS is a self-hosted DNS server for homelabs and small networks. It gives you local DNS resolution, ad-blocking via blocklists, and VLAN segmentation—without the overhead of a web UI or database.
- Simple configuration — Single YAML file
- VLAN-aware — Serve different records to different networks
- Blocklist support — Block ads and trackers at the DNS level
- DoT support — Encrypted upstream queries to protect your privacy
- Cross-platform — Linux, Windows, Docker
- Supported OS
- OS Requirements
- Log Analyzer - BMDLA
- Install
- Update
- Uninstall
- Configuration
- Cascading Search
- Log
- Error Log
The software officially supports GNU/Linux and Windows.
It should work on FreeBSD and MacOS systems, but it is untested.
The install/update/uninstall scripts are specifically written for GNU/Linux and Windows, any attempt of running them in other OS may lead to errors and unexpected behavior.
Compilation requires python3 python3-venv python3-pip packages to be installed. Install them using your OS's package manager
e.g.
sudo apt update && sudo apt install -y python3 python3-venv python3-pip
BMDLA is the software specifically written to analyze the log files from BMDNS.
It provides a series of actions, allowing to check for most requested domains, most active requestants and more.
On Linux run the installation script as root
sudo bash ./scripts/install.sh
The installation script
- compiles the software
- creates the required directories (
/etc/bmdnsand/var/log/bmdns) - copies the default configuration file into
/etc/bmdns/conf.yaml - installs the compiled binary (into
/usr/local/bin) - adds
bmdns.serviceto systemd services
Run the following line in a dedicated directory
wget https://github.com/ryzeon-dev/bmdns/releases/download/v5.1.1/bmdns_5.1.1_amd64.deb && sudo dpkg -i ./bmdns_5.1.1_amd64.deb
Warning: the executables were compiled and packed into .deb on Debian 13, the package might not work on older Debian releases (because of glibc versions)
On Windows run the installation script as an administrator:
.\scripts\install.bat
The installation script
- compiles the software
- creates the required directories (
%PROGRAMFILES%\bmdns\,%PROGRAMFILES%\bmdns\bin\,%PROGRAMFILES%\bmdns\log\) - copies the default configuration file into
%PROGRAMFILES%\bmdns\conf.yaml - installs the compiled binary into
%PROGRAMFILES%\bmdns\bin\
In order to create a Service for this software, you'll need to use some intermediary, such as srvany or alwaysup
To instance bmdns in a docker container, run the following command
sudo docker run --name <name> -p 53:53/udp --mount type=bind,src=<conf-mountpoint>,dst=/etc/bmdns ryzeondev/bmdns:latest
Replace:
<name>with the name you want to give the container<conf-mountpoint>with a local directory where to mount/etc/bmdnsfrom the container; this allows to edit the configuration file
Optionally, you can add --mount type=bind,src=<log-mountpoint>,dst=/var/log/bmdns argument, replacing <log-mountpoint>
with a local directory where to mount /var/log/bmdns from the container; this allows to inspect log file(s)
The update script compiles and installs a new version of bmdns without touching the existing configuration files
On Linux run the update script as root
sudo bash ./scripts/update.sh
On windows run the update script as an administrator
.\scripts\update.bat
On Linux run the uninstallation script as root
sudo bash ./scripts/uninstall.sh
On Windows run the uninstallation script as an administrator
.\scripts\uninstall.bat
Configuration involves editing:
/etc/bmdns/conf.yamlfile on linux systems%PROGRAMFILES%/bmdns/conf.yamlon windows systems
Rember to restart the service after editing the configuration file.
A sample configuration file is
host: 0.0.0.0
port: 53
persistent-log: false
static:
me.local: 0.0.0.0
root-servers:
- 1.1.1.1
- 1.0.0.1
blocklists:
-A complete configuration file example can be found here
To add a personalized dns resolution, add the hostname with its ip address to static section.
Static remap supports A, AAAA, TXT and CNAME types.
e.g. you have a server named my-server with ip address 192.168.0.2
To only set IPv4 (A) resolution, just specify as follows
static:
my-server: 192.168.0.2Wildcard static resolution is supported, and only requires the user to add a "*" in the position associated with the wildcard.
e.g. you have a server named my-server with ip address 192.168.0.2 wich provides multiple web services,
each one identified as a subdomain of the server name itself
static:
'*.my-server': 192.168.0.2Remember that yaml does not like "*" as the first character, so it is required to wrap the name with quotes or double-quotes.
Be aware that excessively wide wildcard remaps may shadow real world domain names: use this functionality carefully and at your own risk.
To set multiple resolution types for the same domain name, specify as follows
static:
my-server:
A: 192.168.0.2
TXT: key=value
AAAA: fe80:deeb::beef
CNAME: my-server.lanNote that record types can be omitted if not needed (e.g. you only want to set IPv4 [A] and IPv6 [AAAA] types)
static:
my-server:
A: 192.168.0.2
AAAA: fe80:deeb::beefEvery record can have multiple values. To set more than one record, write them in a yaml list after the type identifier
static:
my-server:
A:
- 192.168.0.2
- 192.168.0.8
TXT:
- key=value
- my_verification_string
- very_important_dns_txt_recordBMDNS's static remaps support vlans. This way a single DNS server can be used for multiple vlans (provided that the host has the ability to access all of them). When using vlans, only the requestant whose address belongs to a certain vlan may access its static remaps.
Vlan remaps follow the same syntax-scheme as standard remaps
e.g. you have two vlans (with addresses 192.168.0.0 and 192.168.1.0), and you have a server that lives on both named my-server with ip addresses (respectively) 192.168.0.2 and 192.168.1.2
static:
me.local: 0.0.0.0
_vlan0:
__vlanmask: 192.168.0.0/24
my-server: 192.168.0.2
_vlan1:
__vlanmask: 192.168.1.0/24
my-server: 192.168.1.2When creating a vlan space, a certain syntax is required:
- a vlan name must start with
_vlan, which tells the configuration parser to create a new vlan static space - inside the just created vlan object, create an object named
__vlanmaskwith<ip-address>/<cidr>as value- if no
cidris specified,24is assumed
- if no
- then follow with the static remaps
BMDNS vlans can be configured to block access to external resolutions (root server's ones),
and only allow satic vlan remaps to be forwarded.
To do so, add __block-external: yes to your vlan configuration
static:
_vlan0:
__vlankmask: 192.168.0.0/24
__block-external: yesBMDNS vlans require a "vlanmask", which includes all the possible IP addresses in that network. However, it is possible
to exclude certain addresses using the __exclude field.
e.g. You have a BMDNS vlan configured on 10.0.0.0/16 and you want to block IP addresses 10.0.2.4 and 10.0.4.8
static:
_vlan0:
__vlanmask: 10.0.0.0/16
__exclude:
- 10.0.2.4
- 10.0.4.8At least one root server is required for BMDNS to work properly.
Root servers are queried when BMDNS doesn't have the answer in its cache or in the static mapping
e.g. you want to use AdGuard as DNS root server
root-servers:
- 94.140.14.14
- 94.140.15.15 BMDNS supports wrapping request in DoT, so it is possible to use tls root servers
e.g. AdGuard and Cloudflare tls root servers
root-servers:
- tls://dns.adguard-dns.com
- tls://1.1.1.1 List of text files which contain static mappings for websites you want to block
e.g. you have a blocklist file at /opt/adlist.txt which contains
0.0.0.0 ads.google.com
0.0.0.0 *advertising*
0.0.0.0 *ads*
Its file path has to be added under blocklists section
blocklists:
- /opt/adlist.txtBMDNS searches for an answer to a given query in the following order:
- static mappings
- blocklist files
- internal cache
- root servers
Useful note: static mappings are faster to search into than blocklist files
Log files are written into:
/var/log/bmdns/directory on linux systems%PROGRAMFILES%/bmdns/log/directory on windows systems
If log-persistency is set to false, BMDNS writes its log in the file LOG_DIR/bmdns.log, which is created during the installation process.
The log is wiped at every restart of the service
If log-persistency is set to true, BMDNS will create a new file at every restart of the service, naming it bmdns_[$date]_[$time].log.
Error log, which is written only if BMDNS is unable to start, is written into:
/var/log/bmdns/bmdns_error.logfile on linux systems%PROGRAMFILES%/bmdns/log/bmdns_error.logfile on windows systems
The text contained into the file describes the specific issue with BMDNS startup; it could be a configuration error, insufficiente permissions or unrecognized operative system