Security
Multi-scrobbler is not designed to accessible from the public internet.
It is designed for self-hosting on a secure, private network or in something like a tailscale mesh network. If you are considering exposing your instance publicly with no security, DO NOT.
Why Not Expose It?
Currently, there are no destructive actions that can be taken in multi-scrobbler but that will likely change in the near future. Even without destructive actions, an actor can trigger bulk scrobble/retries that exhaust rate limits for things like tealfm or cause you to be blocked for excessive activity for services like listenbrainz/musicbrainz.
Additionally, exposing MS without security can potentially leak personally identifable information. Consider:
- some Services, like Spotify, have descriptive device names that can be seen in MS like
bobs-android-autoormarys-apartment-roku- these can potentially tell a bad actor where you are or what you are currently not doing (at home? in the car?)
- if the device name is named after a location it's even worse, like an airbnb:
123-fun-street-samsung-tv
- general listening activity can be a sign of your daily routine
- EX listening usually stops at 11:45pm -> you go to sleep before midnight
- EX high listening activity between 7:30 - 8:30am -> you are commuting
Securing Multi-Scrobbler
If you absolutely need to host Multi-Scrobbler on a machine that is also accessible from the public internet then use one of the mitigating solutions below to harden your instance.
Without Ingress
If you do not need
- any Ingress-based Sources like Webscrobbler, Listenbrainz Endpoint, or Last.fm Endpoint
then use of these methods:
Restrict Docker Port
If running MS in a Docker container, you can run MS headless by removing the exposed port from the compose file. Note: this will also remove your ability to access the dashboard.
services:
multi-scrobbler:
# ...
# comment out ports section
#
# ports:
# - 9078:9078
Alternatively, lock the exposed port to a specific IP address:
services:
multi-scrobbler:
# ...
ports:
# only accessible from private ip or tailscale ip
- 192.168.0.101:9078:9078
Disable Web
Alternatively, use the Disable Web option to completely disable the web server. This is useful if you are not using the docker image or cannot control port exposure in your environment. Note: this will also remove your ability to access the dashboard.
With Ingress or Remote Instance Dashboard
If you:
- need to use an Ingress-based Source
- or your instance is on a machine outside your private network and you cannot/do not want to run it headlessly
then do one of these:
Alternative for Listenbrainz Endpoint
For Subsonic-based music services (like Navidrome) you can use a Subsonic Source instead of a Listenbrainz Endpoint to avoid needing ingress.
VPN
Use something like Tailscale or Netbird to create a private VPN-like mesh for your machines/devices to communicate over. This is the most secure option since it does not require MS to be publicly exposed at all.
MS only needs to be on a mesh network with the devices that are sending it Ingress scrobbles, or with the devices that will be viewing the dashboard. It does not need to be in the same mesh as any other services it is monitoring.
Reverse Proxy with Authentication
Use a reverse proxy with some kind of authentication gate. Optionally, restrict the gate to protect all routes that are not related to ingress.
The simplest (and least secure) version of this would be using basic auth.
- Traefik basic auth
- NPM auth gatway or nginx basic auth
- Caddy basic auth
Optimally, you should be using a more robust authentication implementation IE tinyauth, authentik, keycloak, etc... that integrates into your reverse proxy.
List of Unprotected Routes
Routes that need to be unprotected in order for devices to communicate with MS:
/1/*- standard route for Listenbrainz Endpoint/api/listenbrainz*- custom Listenbrainz Endpoint with slug/2.0/- standard route for Last.fm Endpoint/api/lastfm*- custom Last.fm Endpoint with slug/api/webscrobbler*- standard/custom route for Webscrobbler
In the examples below you can remove any of the above routes for Sources/Clients you are not using.
Below are examples of protecting all non-ingress and callback routes with basic auth for the above reverse proxies.
- Traefik
- Caddy
Using a file provider:
http:
routers:
ms-route:
entryPoints:
- "websecure"
# can remove any set in the parenthesis group that is unused. Order:
# LZ endpoint, webscrobbler, LFM endpoint
#
# if not using any then leave only -> Host(`...`)
rule: >
Host(`ms.mydomain.com`) && (
!PathPrefix(`/1/`)
&& !PathPrefix(`/api/listenbrainz`)
&& !PathPrefix(`/api/webscrobbler`)
&& !PathPrefix(`/2.0/`)
&& !PathPrefix(`/api/lastfm`)
)
middlewares:
- ms-auth
service: ms-service
services:
ms-service:
loadBalancer:
servers:
# can use container/docker service name if
# traefik and MS are on the same docker network
#
# otherwise replace domain with the host IP
- url: "http://multi-scrobbler:9078"
middlewares:
ms-auth:
basicAuth:
users:
# use htpasswd cli to generate password
#
# or self-hosted https://github.com/sharevb/it-tools/tree/v2026.7.11
# has an htpasswd generator tool
- "testUsername:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
The above could also be done using docker provider labels.
multi-scrobbler.domain.tld {
# remove any paths you are NOT using from `not path` line.
# Order: LZ, LZ, WebScrobbler, LFM, LFM
@if-not-scrobble {
not path /1/* /api/listenbrainz* /api/webscrobbler* /2.0/* /api/lastfm*
}
# if request is to any route not listed above, force client to basic auth
# you must hash your password using `caddy hash-password`
# https://caddyserver.com/docs/command-line#caddy-hash-password
basic_auth @if-not-scrobble {
msUser $2a$14$.UWNn4Zn.cQHY6Z1mkXXrOhO7mg4BC2wiC.4Tb8dNBMidjSRHAw3e
}
# requests will be proxied they are to a scrobble endpoint or basic auth has been passed.
# can use container/service name if Caddy & MS are on the same docker network.
# otherwise, replace `multi-scrobbler` with host IP
reverse_proxy multi-scrobbler:9078
}