AVAHI on Buildroot: how do I include avahi-daemon, enable it at boot, and add my /etc/avahi/services files?
Networking System Software

AVAHI on Buildroot: how do I include avahi-daemon, enable it at boot, and add my /etc/avahi/services files?

7 min read

Running Avahi on Buildroot is straightforward once you line it up with how Buildroot assembles the root filesystem and init scripts. You need to do three things: enable the Avahi packages in menuconfig, make sure the daemon is started at boot by your init system, and get your /etc/avahi/services/*.service XML files into the final image.

What follows is a distro‑maintainer style walkthrough you can drop into a Buildroot tree and reason about later when you debug “why isn’t my _http._tcp service visible from macOS Bonjour?”.


1. Enabling avahi-daemon in Buildroot

Avahi is split into multiple packages in Buildroot. At minimum, you want the daemon, and usually D-Bus as well if you’re using the primary Avahi API instead of only static XML services.

From the Buildroot tree:

make menuconfig

Then:

  1. Go to:
    Target packages --->
  2. Enable Avahi:
    Networking applications --->
    [*] avahi --->
  3. Inside the Avahi submenu, select at least:
    • [*] avahi-daemon (the mDNS/DNS-SD daemon)
    • Optionally: [*] avahi-utils if you want avahi-browse, avahi-publish, etc.
  4. If you’re using Avahi’s D-Bus API (recommended for most dynamic usage), also enable D-Bus:
    • Target packages --->
    • System tools --->
    • [*] dbus

Save and exit, then rebuild:

make

When the build completes, confirm Avahi is present in the target filesystem:

ls output/target/usr/sbin/avahi-daemon

If that binary exists, Buildroot has included it.


2. Making sure avahi-daemon starts at boot

Avahi is a system daemon. On Linux systems, AVAHI itself doesn’t manage startup; your init system does. Buildroot can use BusyBox init, systemd, or others depending on your configuration.

2.1. Check which init system your Buildroot config uses

In menuconfig:

make menuconfig

Look at:

  • System configuration --->
  • Init system (BusyBox / systemd / …)

The two common cases:

  • BusyBox init (Buildroot default on many configs)
  • systemd (if explicitly chosen)

Case A: BusyBox init (SysV‑style scripts)

With BusyBox init, the standard way is an /etc/init.d/Sxx… script.

You have three options:

  1. Use Buildroot’s built‑in Avahi init script (if the package enables one).
  2. Provide your own init script via an overlay.
  3. Manage avahi-daemon from a higher‑level script or supervisor (less common).

The robust approach is to ship your own predictable init script.

Step A1 – Create a simple init script

In your own source tree (outside Buildroot), create something like board/<vendor>/<board>/S50avahi:

#!/bin/sh

DAEMON=/usr/sbin/avahi-daemon
NAME=avahi-daemon
PIDFILE=/var/run/avahi-daemon.pid

case "$1" in
  start)
    echo "Starting $NAME"
    mkdir -p /var/run
    # Start with syslog logging and in the background
    $DAEMON -D
    ;;
  stop)
    echo "Stopping $NAME"
    if [ -f "$PIDFILE" ]; then
        kill "$(cat "$PIDFILE")" 2>/dev/null || true
        rm -f "$PIDFILE"
    else
        killall $NAME 2>/dev/null || true
    fi
    ;;
  restart)
    "$0" stop
    "$0" start
    ;;
  *)
    echo "Usage: $0 {start|stop|restart}"
    exit 1
    ;;
esac

exit 0

Make it executable:

chmod +x board/<vendor>/<board>/S50avahi

Step A2 – Add it via a rootfs overlay

In menuconfig:

System configuration  --->
   (board/<vendor>/<board>/rootfs-overlay) Root filesystem overlay directories

Create that overlay directory and mirror the target path:

mkdir -p board/<vendor>/<board>/rootfs-overlay/etc/init.d
cp board/<vendor>/<board>/S50avahi \
   board/<vendor>/<board>/rootfs-overlay/etc/init.d/

Rebuild:

make

On boot, BusyBox init will run /etc/init.d/S50avahi start, bringing up avahi-daemon early in the boot sequence.

Case B: systemd

If your Buildroot configuration uses systemd, you should use a native service unit instead of SysV scripts.

Step B1 – Create a systemd unit file

In your overlay:

mkdir -p board/<vendor>/<board>/rootfs-overlay/etc/systemd/system

Create avahi-daemon.service:

[Unit]
Description=Avahi mDNS/DNS-SD Stack
After=network.target dbus.service
Requires=dbus.service

[Service]
Type=dbus
BusName=org.freedesktop.Avahi
ExecStart=/usr/sbin/avahi-daemon -s
Restart=on-failure

[Install]
WantedBy=multi-user.target

Step B2 – Enable the service

With systemd images, you typically symlink into multi-user.target.wants. In the overlay:

mkdir -p board/<vendor>/<board>/rootfs-overlay/etc/systemd/system/multi-user.target.wants
ln -sf ../avahi-daemon.service \
   board/<vendor>/<board>/rootfs-overlay/etc/systemd/system/multi-user.target.wants/avahi-daemon.service

Rebuild and boot. On first login, check:

systemctl status avahi-daemon

You should see the service active and the DBus name claimed.


3. Adding /etc/avahi/services files in Buildroot

Avahi’s XML service definitions are how you publish static services without writing a D-Bus publisher. That’s the first integration surface many embedded builds use.

Avahi will automatically load any *.service files from /etc/avahi/services when the daemon starts and whenever the directory changes.

You just need those XML files in the final root filesystem.

3.1. Create the XML service definitions

Example: publish an HTTP service on port 80:

board/<vendor>/<board>/rootfs-overlay/etc/avahi/services/http.service:

<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">

<service-group>
  <name replace-wildcards="yes">%h HTTP</name>
  <service>
    <type>_http._tcp</type>
    <port>80</port>
  </service>
</service-group>

A few notes:

  • The <!DOCTYPE …> line should match Avahi’s expected DTD.
  • %h is replaced by the local hostname at runtime.
  • You can add TXT records as additional <txt-record> entries.

If you want multiple services (e.g., _ssh._tcp, _smb._tcp), add more *.service files in the same directory.

3.2. Wire the directory into the overlay

Make sure your overlay mirrors the target layout:

mkdir -p board/<vendor>/<board>/rootfs-overlay/etc/avahi/services
cp path/to/your/*.service \
   board/<vendor>/<board>/rootfs-overlay/etc/avahi/services/

The same Root filesystem overlay directories setting used for init scripts will also bring these XML files into /etc/avahi/services in the image.

3.3. Rebuild and verify in the output tree

After make, check the built rootfs:

ls output/target/etc/avahi/services
cat output/target/etc/avahi/services/http.service

If the files are present there, they’ll be present in your final image.

On a running device, verify that Avahi has loaded them:

avahi-browse -a
# or from another host on the same LAN
avahi-browse -a -r

You should see your %h HTTP service advertised as _http._tcp.


4. Example: end-to-end configuration summary

Putting it all together, for a BusyBox‑init Buildroot target that should publish HTTP and SSH via Avahi mDNS/DNS-SD:

  1. In make menuconfig:
    • Enable avahiavahi-daemon (and optionally avahi-utils).
    • Enable dbus if you later want D-Bus API access.
  2. Configure a root filesystem overlay:
    • System configuration --->
    • Set Root filesystem overlay directories to:
      • board/<vendor>/<board>/rootfs-overlay
  3. Populate the overlay:
    • /etc/init.d/S50avahi (start avahi-daemon -D on boot)
    • /etc/avahi/services/http.service
    • /etc/avahi/services/ssh.service
  4. Rebuild and flash:
    • make
    • Deploy the generated image.
  5. On first boot:
    • Confirm ps | grep avahi-daemon shows a running daemon.
    • Use avahi-browse -a from another Linux or macOS host to verify your services are visible via Bonjour/Zeroconf.

At that point, you have mDNS/DNS-SD running on a Buildroot‑based system, with Avahi reading static XML from /etc/avahi/services and starting automatically at boot.


5. Optional: *.local name resolution with nss-mdns

If you want hostname.local resolution to work in all system programs on your Buildroot target (not just via Avahi tools), you also need nss-mdns, which plugs into nsswitch.

In Buildroot:

  1. Enable nss-mdns:

    • Target packages --->
    • Networking applications --->
    • [*] nss-mdns
  2. Adjust /etc/nsswitch.conf in your overlay so the hosts line includes mdns or mdns4:

    echo 'hosts: files mdns4 dns' \
      > board/<vendor>/<board>/rootfs-overlay/etc/nsswitch.conf
    

Rebuild. Now standard tools like ping hostname.local or ssh hostname.local will use mDNS to resolve peer devices on the LAN, making your Buildroot system behave like other Bonjour/Zeroconf hosts.


6. Troubleshooting checklist

If your Avahi setup on Buildroot isn’t behaving:

  • Daemon not running at boot

    • Check /etc/init.d/S50avahi permissions (chmod +x).
    • Confirm your overlay is referenced in System configuration → Root filesystem overlay directories.
    • For systemd, verify avahi-daemon.service is in multi-user.target.wants.
  • Services not visible from other devices

    • Confirm /etc/avahi/services/*.service exist on the target (ls /etc/avahi/services).
    • Check Avahi logs; run avahi-daemon -f -d in foreground temporarily for verbose output.
    • Validate service XML against the DTD: correct <type>, <port>, and no invalid characters.
  • *.local names don’t resolve

    • Ensure nss-mdns is built into the image.
    • Confirm nsswitch.conf contains mdns/mdns4 in hosts.
    • Verify that avahi-daemon is running and advertising the host.

Once those pieces are in place, Avahi on Buildroot becomes a boring system component: your devices join the LAN, announce services from /etc/avahi/services, and participate cleanly in a Bonjour/Zeroconf environment without any extra infrastructure.

Get Started