Skip to content

Latest commit

 

History

History
269 lines (197 loc) · 11.4 KB

install.md

File metadata and controls

269 lines (197 loc) · 11.4 KB

slskr Install And Service Runbook

This is the operator-facing shape for the bundled slskr app. It assumes one installed binary that runs the daemon/API with slskr serve, plus the built React Web UI assets from web/build when you want the full browser client shown in the README screenshots. If those assets are missing, slskr serve falls back to a minimal built-in operator dashboard. The full UI is served at / by default; the fallback dashboard is also available at /dashboard.

Build

cargo build --release -p slskr

The binary lands at target/release/slskr. For a local user install:

install -Dm755 target/release/slskr "$HOME/.local/bin/slskr"

Tagged releases provide native AArch64 Linux archives for both glibc and musl:

  • aarch64-unknown-linux-gnu for standard glibc distributions.
  • aarch64-unknown-linux-musl for a static musl build, including Alpine-style deployments.

On an AArch64 Linux host, the same archives can be built locally with:

rustup target add aarch64-unknown-linux-gnu aarch64-unknown-linux-musl
sudo apt-get install musl-tools
scripts/build-release-archive.sh --target aarch64-unknown-linux-gnu
scripts/build-release-archive.sh --target aarch64-unknown-linux-musl

Cross-compiling those targets from x86-64 additionally requires matching AArch64 C linkers; the release workflow avoids that dependency by building on native ARM64 runners.

The Linux release installer and the Proxmox LXC setup script select the x86_64 or aarch64 GNU archive from uname -m, so the same installation entry point works on both supported Linux architectures.

Config And State

Default config file:

$XDG_CONFIG_HOME/slskr/config.toml

If XDG_CONFIG_HOME is unset, the fallback is:

$HOME/.config/slskr/config.toml

Default state directory:

$XDG_STATE_HOME/slskr

If XDG_STATE_HOME is unset, the fallback is:

$HOME/.local/state/slskr

Use SLSKR_CONFIG=/path/to/config.toml and SLSKR_STATE_DIR=/path/to/state to override those paths. Environment variables override config-file values.

On Unix, SLSKR_STATE_DIR must be a real directory rather than a symlink. slskr creates or tightens it to mode 0700 because it contains message, transfer, share-index, SQLite, and durable mesh identity state.

In the native/current profile, the TLS 1.3 mesh-service/private-gateway listener shares the regular Soulseek TCP listener when mesh overlay is enabled, including with DHT disabled; forward that one peer TCP port. Startup fails if a required listener cannot bind or the durable certificate/key pair is missing, malformed, or inconsistent. Read certificateSha256 from authenticated GET /api/mesh/transport and place that 64-character hexadecimal digest in the Pod's gatewayCertificateSha256 policy. The effective overlay port must be reachable by Pod members; the normal HTTP API port does not carry overlay traffic.

Mainline-DHT rendezvous defaults on in the native/current profile. Disable it with SLSKR_DHT_ENABLED / [dht].enabled. The peer listener determines the single public TCP/UDP port: customizing soulseek.listen_port or SLSKR_LISTENER_BIND projects DHT, overlay UDP, and both QUIC ALPNs to that port. Forward that one port for both TCP and UDP. QUIC uses one endpoint with bounded in-process delivery through the shared socket, including with DHT disabled; it creates no backend listener or per-peer forwarding socket. TLS negotiates control/data ALPN after handshake reassembly, so fragmented ClientHellos and both protocols from one peer socket do not require a first-packet selector. Separate native/current overlay or obfuscation binds are rejected; remove those overrides or match the peer bind. Frozen compatibility profiles retain their historical port configuration. Port 0 is accepted only when DHT is disabled. Outbound-only Pod members can enable DHT without a shared public TCP overlay listener to discover pinned gateway candidates.

Frozen slskdN capability messages do not contain an overlay certificate hash or HTTP range URL. Configure verified peers with [[mesh.trusted_peers]], or supply the same array as JSON in SLSKR_TRUSTED_MESH_PEERS. Each entry requires peer_id, Soulseek username, an IP-literal overlay_endpoint, and a 64-hex-digit certificate_sha256; range_endpoint is optional and may use {sha256}, {size}, and {recordingId} placeholders. slskr rejects duplicate identities, zero or non-unicast overlay destinations, credential-bearing URLs, query/fragment URLs, all-zero pins, and more than 256 entries. These values are counted but never emitted by the sanitized configuration endpoint.

Start from slskr.config.example.toml. Configure API tokens through your service manager, deployment config, or secret manager. For Soulseek credentials, prefer first-run Web UI entry with the OS credential store for user installs, systemd credentials for Linux services, runtime-only memory when you do not want persistence, the restricted local credential-file fallback when a better store is unavailable, or env/config credentials from your service/container secret manager. See credential-storage.md for the full credential-source matrix.

SQLite persistence is default-off. Enable the durable compatibility-store path with SLSKR_PERSISTENCE_ENABLED=true or [persistence].enabled = true; share index, event, search, transfer rows and transfer event trail, user, browse, message, room, collection/library, social/security, OAuth, webhook, and runtime projections write through to SQLite. Transfer projection restart state and event TSV mirrors are also maintained in the slskr state directory.

Third-Party Integrations

Spotify OAuth

Spotify supports a browser clickthrough authorization flow. Configure:

[integrations.spotify]
enabled = true
client_id = "spotify-app-client-id"
# Optional; PKCE/browser authorization does not require a client secret.
# client_secret = "spotify-app-client-secret"
# Optional override. If omitted, slskr uses the existing WebUI/API port:
# redirect_uri = "http://127.0.0.1:5030/api/integrations/spotify/callback"

Register the exact redirect URI shown in the WebUI with the Spotify developer dashboard. slskr multiplexes the callback on the existing HTTP listener at /api/integrations/spotify/callback; no second callback service or port is required.

Security behavior:

  • Authorization requests create a cryptographically random server-side state.
  • Pending OAuth state expires after 10 minutes.
  • State is single-use; replayed callbacks are rejected.
  • Callbacks missing state, using invalid state, or using expired state are rejected.
  • The callback response does not echo the authorization code.

Lidarr

Lidarr does not provide OAuth. Configure its local URL and API key:

[integrations.lidarr]
enabled = true
url = "http://127.0.0.1:8686"
api_key = "lidarr-api-key"

The WebUI exposes the closest safe flow: Check Status, Load Wanted, Sync Wanted, and Manual Import actions over Lidarr's API-key authentication. slskr pins the resolved integration address, does not follow HTTP redirects, and caps JSON responses at 2 MiB.

First Run

Loopback-only HTTP binds default to no API auth unless SLSKR_API_TOKEN is configured. Non-loopback binds require an API token unless SLSKR_AUTH_DISABLED=true is explicitly set.

SLSKR_CONFIG="$HOME/.config/slskr/config.toml" slskr serve

Open:

http://127.0.0.1:5030/

When API auth is enabled, enter the configured token in the dashboard's browser-session form. API clients can send the same token as:

Authorization: Bearer <token>

Systemd User Service

Example user unit:

[Unit]
Description=slskr daemon
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=%h/.local/bin/slskr serve
Environment=SLSKR_CONFIG=%h/.config/slskr/config.toml
Environment=SLSKR_STATE_DIR=%h/.local/state/slskr
Restart=on-failure
RestartSec=5s
NoNewPrivileges=true
PrivateTmp=true

[Install]
WantedBy=default.target

For a user service, credential_store = "os" is usually the most convenient Soulseek credential store. If you prefer systemd credentials, set credential_store = "systemd" in config and add credentials named slsk-username and slsk-password to the unit with LoadCredential= or LoadCredentialEncrypted=.

Place it at:

$HOME/.config/systemd/user/slskr.service

Then:

systemctl --user daemon-reload
systemctl --user enable --now slskr.service
systemctl --user status slskr.service

System Service

For a host-level service, create a dedicated user and keep config/state under /etc/slskr and /var/lib/slskr:

[Unit]
Description=slskr daemon
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=slskr
Group=slskr
ExecStart=/usr/local/bin/slskr serve
Environment=SLSKR_CONFIG=/etc/slskr/config.toml
Environment=SLSKR_STATE_DIR=/var/lib/slskr
LoadCredentialEncrypted=slsk-username:/etc/credstore.encrypted/slskr-slsk-username.cred
LoadCredentialEncrypted=slsk-password:/etc/credstore.encrypted/slskr-slsk-password.cred
Restart=on-failure
RestartSec=5s
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/var/lib/slskr

[Install]
WantedBy=multi-user.target

If shared directories live outside /var/lib/slskr, add them to ReadWritePaths= or ReadOnlyPaths= as appropriate.

For systemd credentials, set credential_store = "systemd" under [network]. slskr reads $CREDENTIALS_DIRECTORY/slsk-username and $CREDENTIALS_DIRECTORY/slsk-password at service start. As an alternative, pass one JSON credential named slskr-soulseek with {"username":"...","password":"..."}. Use systemd-creds encrypt to create the encrypted credential files referenced by LoadCredentialEncrypted=. The systemd credential store is read-only inside slskr; update credentials by changing the unit credentials and restarting the service.

Container Shape

The container should run the same app command:

slskr serve

The image runs slskr as PID 1, declares SIGTERM as its stop signal, and performs the same graceful Soulseek disconnect used by the HTTP shutdown route. Keep the default state layout, or create any explicitly configured download and incomplete directories before starting the container.

Mount config read-only and state read-write:

/config/config.toml -> SLSKR_CONFIG=/config/config.toml
/state             -> SLSKR_STATE_DIR=/state

Expose the HTTP bind only to the intended network. If exposing outside localhost, set SLSKR_API_TOKEN, keep auth enabled, and prefer a reverse proxy that preserves Host, Origin, and Referer headers.

Peer listener ports must match the configured advertised ports. For NAT-PMP/UPnP or VPN forwarded ports, set the advertised regular and obfuscated ports to the public mappings.

Exposure Rules

  • Default to loopback HTTP bind.
  • Require SLSKR_API_TOKEN for non-loopback binds.
  • Keep GET /, GET /api/health, GET /api/version, and GET /api/v0/capabilities public only as health/version/capability surfaces.
  • Keep protected API routes behind bearer or same-site browser-cookie auth.
  • Preserve same-origin headers through reverse proxies so cross-site mutating requests continue to be rejected.
  • Keep credentials, WireGuard configs, NAT-PMP lease output, cookies, transfer state, share cache, and logs in the deployment paths intended for those files, with permissions scoped to the service user.