Skip to content

alexanderadam/lyrionmusicserver_avahi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

lyrionmusicserver_avahi

Lyrion Music Server (the rebranded Logitech Media Server) packaged with avahi-daemon and dbus so the AirPlay, Chromecast and UPnP bridge plugins actually work.

The upstream image lmscommunity/lyrionmusicserver does not ship avahi. Without it the following plugins are broken or limited:

  • ShairTunes2W (publishes squeeze players as AirPlay sinks for iOS, macOS, PipeWire). Its bundled shairport_helper-linux-x86_64 v1.9.5 tries to publish mDNS itself, has a broken CLI, and exits with Can't start server. With avahi-publish-service in PATH the plugin uses it via D-Bus and the squeeze players appear as AirPlay sinks.
  • RaopBridge (AirPlay receivers as squeeze players), CastBridge (Chromecast), UPnPBridge (DLNA). These also need mDNS / SSDP to find or announce devices on the LAN.
  • C-3PO transcoder. The plugin's environment check calls findbin("ffmpeg"), which only looks in LMS's own bin dirs. The image installs ffmpeg from apt and symlinks it into the right place.

What is in the image

  • everything from upstream lmscommunity/lyrionmusicserver
  • avahi-daemon, avahi-utils, libnss-mdns
  • dbus (avahi talks D-Bus)
  • ffmpeg, symlinked into /lms/Bin/<arch>/ so C-3PO can find it
  • node 22 LTS at /usr/bin/node, copied from the official node:22-bookworm-slim image. needed by yt-dlp's JavaScript challenge solver. debian bookworm only ships node 18 which yt-dlp rejects as "unsupported", causing YouTube playback to fail with "Signature solving failed" on most videos.
  • an entrypoint wrapper that starts dbus and avahi, waits for both to register on the system bus, and hands off to the upstream start-container

Pulling

podman pull ghcr.io/alexanderadam/lyrionmusicserver_avahi:latest
docker pull ghcr.io/alexanderadam/lyrionmusicserver_avahi:latest

Tags match the upstream Lyrion version, for example 9.1.1. There is also latest which points at the newest upstream version that has been built.

Running

mDNS, SSDP and AirPlay multicast do not cross the default container bridge, so the image only works with host networking. This applies to podman and docker both.

podman

podman run --rm -d \
  --name lyrion \
  --network=host \
  --security-opt seccomp=unconfined \
  -v ./config:/config \
  -v ./music:/music:ro \
  -v ./playlists:/playlists \
  ghcr.io/alexanderadam/lyrionmusicserver_avahi:latest

docker compose

services:
  lyrion:
    image: ghcr.io/alexanderadam/lyrionmusicserver_avahi:latest
    network_mode: host
    security_opt:
      - seccomp=unconfined
    volumes:
      - ./config:/config
      - ./music:/music:ro
      - ./playlists:/playlists
    restart: unless-stopped

Why seccomp=unconfined

Only needed on hosts older than kernel 5.3 with a container runtime older than late 2021 (docker < 20.10.10 or equivalent podman). On those, the default seccomp profile returns EPERM for the unknown clone3 syscall instead of ENOSYS, so modern glibc never falls back to clone() and pthread_create inside shairport_helper silently never spawns the worker threads. The helper opens its HTTP listener, then LMS times out after 15 seconds with "Can't connect to server".

If your host is on a recent kernel and a recent runtime, drop the seccomp=unconfined line. Better security defaults, same behaviour.

Building locally

podman build -t lyrionmusicserver-avahi:local -f Containerfile .
docker build -t lyrionmusicserver-avahi:local -f Containerfile .

To target a specific Lyrion version:

podman build \
  --build-arg LYRION_VERSION=9.1.1 \
  -t lyrionmusicserver-avahi:9.1.1 \
  -f Containerfile .

To pin the avahi advertise interface at build time (otherwise avahi defaults apply, which advertise on every visible nic):

podman build \
  --build-arg AVAHI_ALLOW_INTERFACES=eth0 \
  -t lyrionmusicserver-avahi:local \
  -f Containerfile .

How the published image is updated

.github/workflows/build.yml runs once a day. It:

  1. Lists the semver tags on Docker Hub for lmscommunity/lyrionmusicserver.
  2. Lists the tags already present on ghcr for this image.
  3. For every upstream tag that is missing on ghcr, builds with --build-arg LYRION_VERSION=<tag> and pushes under the same tag.
  4. The newest semver also gets the latest tag.

So the version of this image always matches the upstream Lyrion version it is based on.

A push to main that touches the Containerfile, the entrypoint, or the workflow itself also rebuilds the newest upstream tag, so wrapper changes ship without waiting for the next upstream release.

You can also trigger a build by hand from the Actions tab with a specific version.

Why a wrapper entrypoint

avahi-daemon needs a running D-Bus system bus to be useful, and neither of them is started by the upstream image's start-container. The wrapper at entrypoint.sh:

  1. Sets up /run/dbus and a machine id if missing.
  2. Starts a system D-Bus daemon.
  3. Starts avahi-daemon in the background.
  4. Hands off to the original upstream entrypoint (/usr/bin/start-container.orig).

If you want to see what upstream's entrypoint does, it is preserved at /usr/bin/start-container.orig.

Not in this image

  • A specific avahi allow-interfaces= setting. Pin it at build time with the AVAHI_ALLOW_INTERFACES build arg if you need to.
  • Anything related to the LMS prefs or music directory. Mount them in as volumes like with the upstream image.
  • Plugin preinstallation. Install through the LMS web UI as usual.

License

The wrapper bits (Containerfile, entrypoint, workflow) are MIT, see LICENSE. The base image lmscommunity/lyrionmusicserver keeps its own licensing. Lyrion Music Server itself is GPL, see the upstream project.

Releases

No releases published

Packages

 
 
 

Contributors