Security
Why Not Expose It?
Section titled “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
Section titled “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
Section titled “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
Section titled “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:9078Alternatively, 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:9078Disable Web
Section titled “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
Section titled “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.
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
Section titled “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
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.
Using a file provider:
http: routers: ms-route: entryPoints: - "websecure"
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: middlewares: ms-auth: basicAuth: users:- 1.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(...) - 2.can use container/docker service name if traefik and MS are on the same docker network, otherwise replace domain with the host IP
- 3.use htpasswd cli to generate password, or the htpasswd generator tool in self-hosted it-tools
The above could also be done using docker provider labels.
multi-scrobbler.domain.tld { @if-not-scrobble { } msUser $2a$14$.UWNn4Zn.cQHY6Z1mkXXrOhO7mg4BC2wiC.4Tb8dNBMidjSRHAw3e }}- 1.remove any paths you are NOT using. Order: LZ, LZ, WebScrobbler, LFM, LFM
- 2.if request is to any route not listed above, force client to basic auth. You must hash your password using
caddy hash-password - 3.requests will be proxied if 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-scrobblerwith host IP