Slipmat

Slipmat

Docker app from alexjsp's Repository

Overview

Self-hosted control and automation for a Sonos system, entirely over your local network: no cloud and no Sonos account. A web UI for everyday playback and grouping, plus presets that group speakers, set their volumes and play a shuffled mix of playlists, albums and favourites. Fire presets from the UI, a webhook (Shortcuts, Stream Deck, Node-RED) or an optional HomeKit switch.

Host networking is required: Sonos discovery is multicast and the speakers call back into Slipmat for live updates, neither of which crosses a bridge network.


Slipmat

Self-hosted control and automation for Sonos.
One tap to put the right music in the right rooms, at the right volumes.

Slipmat's Now Playing view in a browser, showing three rooms

Slipmat runs on your own server and talks to your speakers directly over the local network. There's no cloud and no Sonos account involved, and nothing leaves the house.

Its heart is presets. A preset groups a set of speakers, sets each one's volume, and starts a queue shuffled together from as many playlists, albums and favourites as you like. Start one from the web UI, from a webhook (Shortcuts, Stream Deck, Node-RED), on a schedule, or with a HomeKit switch that also shows whether it's playing.

Everyday playback

Now Playing and the grouping sheet on a phone
  • Every room on one screen, with artwork, transport controls and volume.
  • Group and ungroup rooms, and set each speaker's volume within a group.
  • Pause all stops the music everywhere and leaves TV audio alone.
  • Works as well on a phone as on a desktop.

Presets

The preset list, the preset editor, and the rule editor
  • Speakers and volumes: pick the rooms, set a volume for each, and choose which one leads.
  • Many sources, one queue: Sonos playlists, favourites and your music library, shuffled together, with duplicates removed.
  • Rules: change what a preset plays by day, month or time of day. Add Christmas music in December, rotate through a different playlist each day, or play quieter after 9pm. The editor shows what the preset would play right now.
  • Starts fast: sound begins within about a second, and the rest of the queue fills in behind it.
  • Wind down: start in every room, then carry on in just a few.
  • Optional crossfade, repeat, and pausing the rest of the house.

Sources and integrations

Pasting a streaming link as a source, and the settings page
  • Paste a link to a Spotify or Apple Music playlist, album, artist or track.
  • Schedules start or stop presets at set times, with sleep timers, and can pause music when the TV comes on.
  • Webhooks for every preset and for Pause All, using GET or POST.
  • HomeKit: an optional built-in bridge, with no Homebridge needed, that shows presets as switches in the Home app.
  • Blocked music: tracks, artists or albums that should never play, whichever preset queued them.

Running it

Unraid

Install Slipmat from Community Applications. Until it's listed there, fetch the template on the server and pick it from Docker → Add Container → Template:

wget -O /boot/config/plugins/dockerMan/templates-user/my-Slipmat.xml \
  https://raw.githubusercontent.com/alexjsp/unraid-community-apps/main/templates/slipmat.xml

Docker Compose

curl -O https://raw.githubusercontent.com/alexjsp/slipmat/main/compose.yml
docker compose up -d

Settings go in a .env beside it; every one is optional.

Docker

docker run -d --name slipmat \
  --network host \
  -v /path/to/appdata/slipmat:/data \
  ghcr.io/alexjsp/slipmat:latest

Then open http://<host>:5544.

latest is the most recent release. To follow every change on main instead, use edge, or pin a version such as 1.0.0 or 1.0.

--network host is required

Not a convenience — three things depend on it:

  • SSDP discovery is multicast and doesn't cross a Docker bridge network.
  • UPnP events: the speakers dial back into Slipmat's callback URL, so they need a routable address for it.
  • HomeKit (if enabled) advertises over mDNS.

If discovery still can't get through, set SLIPMAT_SEED_IP to any one speaker's IP address — Slipmat finds the rest of the household from there.

Docker Desktop on macOS has no real host networking. Develop natively with just dev instead.

Configuration

See .env.example for the full list. The ones that matter:

Variable Default Notes
SLIPMAT_PASSWORD — Optional. Setting it turns authentication on; unset means no login.
SLIPMAT_SESSION_SECRET generated Signs login sessions. Generated and stored on first run if unset.
SLIPMAT_PORT 5544
SLIPMAT_SEED_IP — Discovery fallback.
SLIPMAT_HOMEKIT 0 Set to 1 to enable the embedded HomeKit bridge.
SLIPMAT_HOMEKIT_PIN generated Pairing code. Generated on first run if unset, and shown in Settings.
PUID / PGID 10001 User and group the server runs as. /data is handed to them on start.

Authentication is optional

Slipmat runs without a login by default, and that's deliberate rather than an oversight: Sonos has no authentication of its own, so anything already on your network can control the speakers. Putting a password in front of Slipmat wouldn't change that.

Set SLIPMAT_PASSWORD to turn it on. Worth doing if you expose Slipmat beyond the LAN, or if not everyone in the house should be able to edit presets.

Two protections apply either way:

  • Webhook URLs always carry a per-preset secret token rather than relying on a session, so they work from Shortcuts, Node-RED and the like. Regenerate a token from the preset editor if one leaks.
  • A host-header allowlist blocks DNS rebinding, which is the one thing a browser on your network can do to an open LAN service.

Development

SLIPMAT_FAKE_SONOS=1 runs against an invented household instead of real speakers. It's what the screenshots above were taken from: just readme-images regenerates them.

Requires Node 24+, pnpm and just.

just install
just dev        # API on :5544, UI on :5545 with a proxy to the API
just check      # lint, typecheck, test

⚠️ Tests never touch real speakers. They run against the fake Sonos layer. Anything that would mutate real hardware needs an explicit ask first — see CLAUDE.md.

just release tags a new version, offering the next major, minor or patch, and CI publishes it as latest once the checks pass. Pushes to main publish edge only.

Personal recipes, such as a deploy to your own server, can go in a gitignored local/local.just; the justfile imports it when it exists.

Prior art

jishi/node-sonos-http-api pioneered this shape and its preset semantics were a useful reference. Slipmat is built on @svrooij/sonos instead — actively maintained, fully typed, with the event subscriptions the preset state tracking needs.

License

MIT

Media gallery

1 / 4

Requirements

Host networking (set by this template), and Sonos speakers on the same network as the server.

Related apps

Details

Repository
ghcr.io/alexjsp/slipmat:latest
Last Updated2026-10-11
First Seen2026-10-11

Runtime arguments

Web UI
http://[IP]:[PORT:5544]/
Network
host
Shell
sh
Privileged
false

Template configuration

AppdataPathrw

Presets, schedules, settings and the source cache (a small SQLite database), plus HomeKit pairing data if enabled.

Target
/data
Default
/mnt/user/appdata/slipmat
Value
/mnt/user/appdata/slipmat
Web UI portVariable

Port the web UI and API listen on. With host networking this is a port on the Unraid server itself.

Target
SLIPMAT_PORT
Default
5544
Value
5544
PasswordVariable

Optional. Setting a password turns on login for the web UI and API. Webhooks keep working through their own secret URLs either way.

Target
SLIPMAT_PASSWORD
Allowed hostnamesVariable

Comma-separated hostnames you reach Slipmat by, such as a domain behind a reverse proxy. IP addresses, localhost, *.local and *.ts.net always work; anything else is refused to block DNS rebinding.

Target
SLIPMAT_ALLOWED_HOSTS
Speaker IPVariable

Optional. The IP of any one speaker, for networks where discovery can't get through (VLANs, multicast filtering). Slipmat finds the rest of the system from it.

Target
SLIPMAT_SEED_IP
Time zoneVariable

Optional IANA time zone (for example Europe/London) for schedules and time-based rules. Defaults to the container's time zone, and can also be changed in Settings.

Target
SLIPMAT_TZ
HomeKit bridgeVariable

Set to 1 to expose presets as HomeKit switches.

Target
SLIPMAT_HOMEKIT
Default
0
Value
0
HomeKit PINVariable

Optional pairing code for the HomeKit bridge, in the form 123-45-678. Left blank, one is generated on first run and shown in Settings.

Target
SLIPMAT_HOMEKIT_PIN
HomeKit nameVariable

Name of the bridge as it appears in the Home app.

Target
SLIPMAT_HOMEKIT_NAME
Default
Slipmat
Value
Slipmat
Callback addressVariable

Optional. The server address speakers should send live updates to, when the server has several network interfaces and Slipmat guesses the wrong one.

Target
SLIPMAT_CALLBACK_HOST
Log levelVariable

One of trace, debug, info, warn, error.

Target
SLIPMAT_LOG_LEVEL
Default
info
Value
info
PUIDVariable

User the server runs as. /data is handed to this user on start.

Default
99
Value
99
PGIDVariable

Group the server runs as.

Default
100
Value
100