Subdomains with Avahi
- Created at
- 16 January 2026
- Last modified
- 16 February 2026
- Last promoted at
- 19 January 2026
- Status
- 🌲 tree
- Tagged
Multicast DNS (or mDNS) is a protocol that allows devices on a local network to publish (and be referenced by) their own addresses (eg computername.local) rather than forcing everyone to resort to IP addresses (eg 192.168.1.52).
It's pretty cool because:
- It's easier to remember your computer is at
computername.localthan it is to remember it's at192.168.1.52. - While it's possible to set up your router so that your computer is always at the same IP, it's still a little work.
mDNS is implemented in OS X through Apple's Bonjour implementation, and (generally) in Linux through Avahi. When you do this, your device's URL will usually be <devicename>.local.
If you're running a homeserver, you might have multiple services, each running on its own port. And if you've hung out on the web for a bit, you'll be wondering if there's any way to set up subdomains of your lovely mDNS-implemented local URL. If you give it a web search, you'll find some people doing the same, some people telling you to use python libraries for Avahi (which I'm not sure are still maintained), and even some AI slop telling you to change config settings in Avahi which don't exist.
And here's how you actually do it.
- Date of writing: January 2026
- Operating system: Fedora release 43
- Avahi version: 0.9~rc2
Step 0: Prerequisites
This assumes you're running on a Linux distro which usessystemd for service management. You should install avahi using your preferred package manager.
Step 1: Outline the subdomains you want
We're going to be cute for this step: we're going to set up a little file in Avahi's config space for our subdomains. For me, this is /etc/avahi. Your mileage may vary.
Let's set up three subdomains: tv, music, and wiki (again, assuming we're running some services on our home server) - these will go to eg tv.computername.local, music.computername.local and wiki.computername.local. Which will be pretty cool.
In your terminal:
cd /etc/avahi
echo tv\nmusic\nwiki > subdomains
This will create a file subdomains with three lines, each line showing a subdomain. Easy!
Step 2: Build the publication process
To let other devices on our network know about these subdomains, we need Avahi to publish them. The following shell script does this, leaning heavily on u1aryz' how-to-avahi-subdomain script.
#!/usr/bin/env bash
set -euo pipefail
# Default interface
readonly DEFAULT_INTERFACE="wlp0s20u2"
# Where we store aliases
readonly SUBDOMAIN_FILE="/etc/avahi/subdomains"
# Logging functions
log_info() {
echo -e "[INFO] $*" >&2
}
log_error() {
echo -e "[ERROR] $*" >&2
}
show_usage() {
cat >&2 <<-EOF
Usage: $0 [-i <interface>]
Options:
-i <interface> Network interface to use (default: $DEFAULT_INTERFACE)
-h Show this help message
EOF
}
check_requirements() {
local missing_deps=()
local required_commands=("avahi-publish" "ip")
for cmd in "${required_commands[@]}"; do
if ! command -v "$cmd" &>/dev/null; then
missing_deps+=("$cmd")
fi
done
if [[ ${ #missing_deps[@]} -gt 0 ]]; then
log_error "Missing required dependencies: ${missing_deps[*]}"
exit 1
fi
}
validate_interface() {
local interface="$1"
if ! ip link show "$interface" &>/dev/null; then
log_error "Network interface '$interface' not found."
log_error "Available interfaces:"
ip link show | grep -E '^[0-9]+:' | awk -F': ' '{print " " $2}' | sed 's/@.*//' >&2
exit 1
fi
}
get_interface_addresses() {
local interface="$1"
local ipv4_addresses=$(ip -4 -o addr show dev "$interface" scope global | awk '{print $4}' | cut -d/ -f1)
# Check if we have IPv4 addresses
if [[ -z "$ipv4_addresses" ]]; then
log_error "No IPv4 addresses found on interface '$interface'."
exit 1
fi
local ipv6_addresses=$(ip -6 -o addr show dev "$interface" scope global | awk '{print $4}' | cut -d/ -f1)
# Combine IPv4 and IPv6 addresses
local all_addresses="$ipv4_addresses"$'\n'"$ipv6_addresses"
echo "$all_addresses"
}
publish_addresses() {
local fqdn="$1"
local addresses="$2"
log_info "Publishing '$fqdn' with addresses:"
for addr in $addresses; do
log_info " $addr"
avahi-publish -f -a -R "$fqdn" "$addr" &
done
}
main() {
local interface="$DEFAULT_INTERFACE"
# Parse command line options
while getopts ":i:h" opt; do
case "$opt" in
i) interface="$OPTARG" ;;
h)
show_usage
exit 0
;;
\?)
log_error "Invalid option -$OPTARG"
show_usage
exit 1
;;
:)
log_error "Option -$OPTARG requires an argument"
show_usage
exit 1
;;
esac
done
shift $((OPTIND - 1))
# Validate arguments
if [[ $# -ne 0 ]]; then
log_error "No arguments are required."
show_usage
exit 1
fi
# Check alias file exists
if [ ! -f $SUBDOMAIN_FILE ]; then
log_error "File $SUBDOMAIN_FILE does not exist."
exit 1
fi
# Check dependencies
check_requirements
# Validate interface
validate_interface "$interface"
# Get addresses
local addresses=$(get_interface_addresses "$interface")
# Populate
for subdomain in $(cat $ALIAS_FILE)
do
local fqdn="${subdomain}.$(hostname).local"
# Publish addresses
publish_addresses "$fqdn" "$addresses"
done
# Wait for all background processes
wait
}
main
If you've had to change where you keep your subdomain file, change the constant SUBDOMAIN_FILE. Depending on your computer, your wireless interface may also be different from mine - check out how you're connected to the network through ip link show and select the appropriate interface.
As a guided tour of the script:
- Lines 1-85 set up various constants and auxiliary functions.
- Lines 88-118 parse arguments to ensure we're advertising through the right interface.
- Lines 119-123 are simply us checking a subdomain file exists.
- Lines 125-132 involve us ensuring the system has the right things installed, that the interface exists, and collecting our IP address(es) on that interface.
- Lines 134-141 are the loop where we do the work - we use
avahi-publishto publish each subdomain, pointing to our IP addresses. These processes are run in the background as child processes to this one. - On Line 144 we call
wait, allowing all background processes to halt before we quit out.
Store this where you will - I've saved mine as /usr/local/bin/avahi-publish-subdomain (and run chmod +x on it to ensure it can be run).
Of course, it sucks having to open up your terminal and run this script just to get the functionality going. Thankfully, we can run it through systemd.
Step 3: Run through systemd
To do this, we'll make a nice simple systemd entry. cd to /etc/systemd/system, and create a file avahi-subdomain.service with the content:
[Unit]
Description=Publish mDNS subdomains under %H.local
Requires=avahi-daemon.service
After=avahi-daemon.service
StartLimitBurst=5
StartLimitIntervalSec=10s
[Service]
Type=simple
ExecStart=/usr/local/bin/avahi-publish-subdomain
Restart=on-failure
RestartSec=2
[Install]
WantedBy=multi-user.target
You'll notice that this file references our script avahi-publish-subdomain above - point it to wherever your file is.
Now all we need to do it queue it up in systemd:
sudo systemctl enable avahi-publish-subdomain
And you should be good to go!