Security
Access controls
-
IP allow/deny lists:
ip_whitelist/ip_blacklist, they accept individual IPs or CIDR ranges. -
Listener scopes: each listener has a scope (
public,usersoradmin) that sets which routes it serves, based on the address and port it listens on. See Listener scopes.-
public_hostsandpublic_portgive listeners thepublicscope (public routes). -
admin_hostsandadmin_portgive listeners theadminscope (admin panel and control API). -
The other addresses have the
usersscope. -
restrict_control_api(on by default) keeps the control API onadminscope listeners. Turn it off to also serve it onusersones (it is still protected by its token). -
Remark: By default, a single listener serves everything.
-
-
Trusted
Hostheaders:trusted_hostscontrols whichHostheader values are accepted.-
Remark: If the server is reachable beyond your own machine, it is recommended to set this. You can also use
external_hostnamefor share links. -
A
Hostheader that isn’t just ahostname[:port](scheme, path,user@, spaces, control characters…) is always refused (with HTTP 400).
-
-
Legacy authentication:
legacy_authcontrols whether the older MD5-token/cleartext Subsonic authentication mode is accepted. Many clients still need it.-
Remark: API-key authentication is always available regardless of this setting, so clients that support
apiKeycan use an app password with this turned off. -
Remark: The Subsonic protocol sends credentials in the URL query string, so they can end up in reverse-proxy access logs. See Credentials in proxy logs.
-
-
App passwords: clients should use app passwords, which can be revoked, limited to read-only access and set to expire, instead of the account password.
-
User management over the API:
api_user_managementcontrols whether admins can create, update and delete users, and change other users’ passwords, through the Subsonic API. It is off by default. The admin panel is not affected.
Security logging and CrowdSec
Auth failures, rate-limit blocks and IP-filter denials are logged as BSN-SEC event=... ip=... endpoint="..." user="..." lines (credentials not included, usernames sanitised) and a ready-made CrowdSec parser and scenarios are available in the crowdsec/ directory. Remember to set up reverse_proxy so the logged IPs are the real client ones.
Beets config protection
The Beets config can load plugins and run commands, so editing it from the admin panel has some restrictions:
-
allow_beets_config_editmust be enabled before server runs (it can’t be changed from the Web UI). -
Code-execution settings are blocked: even when editing is on, the panel refuses to add or modify the
inlineandhookplugins,pluginpath,item_fields/album_fields, and options holding a command or binary (convert.command,play.command,keyfinder.bin, etc).Settings already present in the file are honoured as long as they are unchanged.
See Blocked settings for the full list.
-
Disk writes need opt-in: imports that would modify files (tags, copy/move, or plugins such as
scrub,embedartorfetchartinautomode) requireallow_disk_writes.See Disk writes.
Note
These are guard rails against a compromised or careless admin session, not a sandbox. Someone who has write access to the config file on the server can obviously still change them.
Adaptive login rate-limiting
Two independent buckets slow down brute-force attempts:
-
Per-pair of (IP, username):
rate_limit_max_failuresfailed attempts withinrate_limit_block_windowseconds blocks that specific (IP, username) pair. -
Per-IP:
rate_limit_max_failuresfailed attempts from an IP (using any username) withinrate_limit_block_windowseconds blocks that IP. This catches attackers rotating usernames to dodge the per-user limit above. -
Tokenised URLs (the unauthenticated stream URLs handed to Sonos/Chromecast speakers, and the image links in artist/album info) stop working after 12 hours (streams) or 24 hours (images) without being used. A speaker playing a queue or a client re-fetching an image keeps its link alive. Stale links return 404, and the client gets a fresh one the next time it asks.
See the configuration reference for any of the settings mentioned here.
Services on your local network
To prevent users from making the server contact things it should not (a request forgery, or SSRF), BeetstreamNext restricts connections to private addresses (localhost, 192.168.x.x, Docker container names, etc.).
When you need BeetstreamNext to reach a self-hosted service (for example a multi-scrobbler instance, an admin can whitelist it in the local_services setting (hostnames, IP addresses or CIDR ranges are accepted).
-
A hostname is trusted whatever address it resolves to (convenient for container names).
-
An IP or a range is trusted by address.
-
Ports are not restricted.
-
The whitelist only applies to services that an admin or user configures, like external scrobbling. Simple fetchable URLs like podcast feeds, radio streams, images, always stay restricted to public-only.