Skip to content

Installation — Docker Compose

import { Aside, Steps } from ‘@astrojs/starlight/components’;

  • Docker Engine and Docker Compose
  • Bluetooth adapter on the host
  • PulseAudio or PipeWire on the host
  • Music Assistant on your network

The published image supports linux/amd64, linux/arm64, and linux/arm/v7.

  1. Pair the speaker on the host first

    Terminal window
    bluetoothctl
    scan on
    pair AA:BB:CC:DD:EE:FF
    trust AA:BB:CC:DD:EE:FF
    connect AA:BB:CC:DD:EE:FF
    exit
  2. Create .env

    AUDIO_UID=1000
    TZ=Europe/London
    WEB_PORT=8080
    BASE_LISTEN_PORT=8928
  3. Create docker-compose.yml

    services:
    sendspin-client:
    image: ghcr.io/trudenboy/sendspin-bt-bridge:latest
    container_name: sendspin-client
    restart: unless-stopped
    network_mode: host
    volumes:
    - /var/run/dbus:/var/run/dbus
    - /run/user/${AUDIO_UID:-1000}/pulse:/run/user/${AUDIO_UID:-1000}/pulse
    - /run/user/${AUDIO_UID:-1000}/pipewire-0:/run/user/${AUDIO_UID:-1000}/pipewire-0
    - /etc/docker/Sendspin:/config
    environment:
    - SENDSPIN_SERVER=auto
    - TZ=${TZ:-UTC}
    - WEB_PORT=${WEB_PORT:-8080}
    - BASE_LISTEN_PORT=${BASE_LISTEN_PORT:-8928}
    - CONFIG_DIR=/config
    - PULSE_SERVER=unix:/run/user/${AUDIO_UID:-1000}/pulse/native
    - XDG_RUNTIME_DIR=/run/user/${AUDIO_UID:-1000}
    devices:
    - /dev/bus/usb:/dev/bus/usb
    cap_add:
    - NET_ADMIN
    - NET_RAW
  4. Start the container

    Terminal window
    mkdir -p /etc/docker/Sendspin
    docker compose up -d
  5. Open the web UI

    http://<host-ip>:<WEB_PORT>
  • WEB_PORT controls the direct web UI/API listener in Docker mode.
  • BASE_LISTEN_PORT is the default Sendspin listener base for devices that do not define listen_port explicitly.
  • Each device without a manual port uses BASE_LISTEN_PORT + device_index.
  • Advanced setups can assign a per-device listen_port and listen_host in the web UI or /config/config.json after the first start.

Example device block in /config/config.json:

{
"mac": "11:22:33:44:55:66",
"player_name": "Kitchen Speaker",
"listen_port": 8935,
"listen_host": "192.168.1.50"
}

listen_host only changes the advertised host/IP shown for the player; it does not change the bind address inside the container.

If you run more than one bridge container on the same machine:

  • give each container a unique WEB_PORT
  • give each container a unique BASE_LISTEN_PORT
  • do not configure the same Bluetooth speaker in two running containers

network_mode: host is required for:

  • mDNS discovery when SENDSPIN_SERVER=auto
  • access to the host Bluetooth stack through D-Bus

Required capabilities:

CapabilityPurpose
NET_ADMINBluetooth adapter control
NET_RAWRaw Bluetooth/HCI socket access
Terminal window
docker logs -f sendspin-client
curl -s http://localhost:${WEB_PORT:-8080}/api/preflight | python3 -m json.tool

Changes to devices, adapters, WEB_PORT, BASE_LISTEN_PORT, and Music Assistant connection settings require a container restart.