Browse documentation
Documentation for v0.14.0View original source ↗

Docker deployment

Soundsible ships a multi-stage production image and a Compose stack. The image contains FFmpeg, Chromaprint, Python dependencies, and the compiled SolidJS player; Node.js and build tools do not remain in the runtime image.

Images are published to the GitHub Container Registry for linux/amd64 and linux/arm64, so a NAS, a Raspberry Pi, or an Apple Silicon Mac runs the same image as an x86 server without compiling anything.

TagWhat it is
ghcr.io/arzuparreta/soundsible:edgeEvery commit that lands on main. Current default.
ghcr.io/arzuparreta/soundsible:latestThe most recent tagged release.
ghcr.io/arzuparreta/soundsible:X.Y.Z · :X.YA specific release, pinned.

Every published image carries a signed build-provenance attestation. Verify one before you run it:

gh attestation verify oci://ghcr.io/arzuparreta/soundsible:edge --repo Arzuparreta/soundsible

Quick start

No checkout, no build toolchain:

curl -O https://raw.githubusercontent.com/Arzuparreta/soundsible/main/compose.yaml
docker compose up -d
docker compose ps

Or without Compose at all:

docker run -d --name soundsible \
  -p 5005:5005 \
  -v soundsible-config:/config \
  -v soundsible-data:/data \
  -v soundsible-cache:/cache \
  -v soundsible-logs:/logs \
  -v soundsible-music:/music \
  ghcr.io/arzuparreta/soundsible:edge

Pin a release instead of tracking main by setting SOUNDSIBLE_TAG in a .env file beside compose.yaml, or by naming the tag directly in docker run.

When the service reports healthy, open http://localhost:5005/player/. The first boot creates a local provider configuration for /music. Later boots reuse /config/config.json and never replace it.

The default stack uses five named volumes. With the default Compose project name, Docker stores them as soundsible_soundsible-*:

VolumeContainer pathContents
soundsible_soundsible-config/configInstance configuration and database: accounts, and each person’s library and playlists
soundsible_soundsible-data/dataQueues, import jobs, listening telemetry, and preserved artwork
soundsible_soundsible-cache/cacheRebuildable covers, previews, and media cache
soundsible_soundsible-logs/logsRuntime logs
soundsible_soundsible-music/musicImported and downloaded audio

docker compose down keeps all five volumes. Do not use down --volumes unless you intentionally want to delete the complete Docker-managed instance.

Use an existing host library

Replace the music volume in compose.yaml with an absolute bind mount:

services:
  soundsible:
    volumes:
      - /srv/music:/music

Soundsible runs as UID/GID 1000:1000. The mounted directory must be readable and writable by that identity if you want Soundsible to save downloads:

sudo chown -R 1000:1000 /srv/music

If the directory must remain read-only, mount it as /music:ro; playback and scanning work, but downloads and library modifications that write audio will not. Open Settings → Library → Rescan files after mounting it. Soundsible indexes supported files in place; it does not copy or rename the originals.

Configuration and security

Compose reads optional values from a .env file beside compose.yaml:

SOUNDSIBLE_TAG=edge
SOUNDSIBLE_PORT=5005
SOUNDSIBLE_ADMIN_TOKEN=replace-with-a-long-random-value
SOUNDSIBLE_YT_SEARCH_SOURCE=ytmusic
SOUNDSIBLE_PREVIEW_CACHE_MB=2048
SOUNDSIBLE_COMMUNITY_DISABLED=false

Generate an admin token with openssl rand -hex 32. Soundsible is designed for a trusted LAN or Tailscale network; do not expose port 5005 directly to the public internet. Put a TLS reverse proxy or Tailscale in front of it when remote access is required.

To supply an existing configuration instead of the automatic local one, mount it under /config and set:

environment:
  SOUNDSIBLE_CONTAINER_AUTO_CONFIGURE: "false"

All runtime environment variables documented in Configuration can be added to the Compose environment section. Paths inside the container must use the container paths (/config, /data, /cache, /logs, /music).

Operations

The Docker path is continuously built and started in GitHub Actions for every pull request and change to main or dev. A scheduled clean rebuild also checks it against freshly pulled base images and package indexes. A green docker check means the actual Compose deployment started healthy, served the player, ran as its unprivileged user, and kept first-run configuration across a container recreation. Only after those checks pass does the publish job push the multi-architecture image, so nothing reaches edge that has not already started and served the player in CI.

View status and logs:

docker compose ps
docker compose logs -f soundsible
curl --fail http://localhost:5005/api/health

Upgrade to a newer image and recreate the service without touching volumes:

docker compose pull
docker compose up -d

docker compose up -d replaces the container when the image changes and keeps all five named volumes. Do not use automatic image-updaters: review and apply Soundsible releases deliberately, so an upstream change cannot silently alter your running music server.

Maintainer dependency updates

The production image installs from the hash-checked requirements.docker.lock, generated for its Python 3.13 runtime. It prevents the same commit from resolving to a different Python dependency set tomorrow. When changing requirements.txt or deliberately refreshing dependencies, regenerate it and commit both files:

python3 -m pip install 'pip-tools==7.5.3'
pip-compile --upgrade --generate-hashes --strip-extras \
  --output-file requirements.docker.lock requirements.txt

CI rejects a Docker lock that does not satisfy a direct requirement. The daily clean Docker rebuild remains responsible for base-image and Debian package changes.

Back up persistent state while the service is stopped:

docker compose stop soundsible
docker run --rm \
  -v soundsible_soundsible-config:/source:ro \
  -v "$PWD":/backup \
  alpine tar czf /backup/soundsible-config-backup.tgz -C /source .
docker run --rm \
  -v soundsible_soundsible-data:/source:ro \
  -v "$PWD":/backup \
  alpine tar czf /backup/soundsible-data-backup.tgz -C /source .
docker compose start soundsible

Back up the music volume separately when it contains the only copy of your audio. The cache and logs volumes are optional in backups.

Build from source instead

compose.yaml deliberately has no build: section, so it can never quietly compile on hardware that cannot afford it. Stack compose.build.yaml on top when you want the image built from your working tree:

git clone https://github.com/Arzuparreta/soundsible.git
cd soundsible
docker compose -f compose.yaml -f compose.build.yaml up -d --build

Set it once for the shell instead of repeating both -f flags:

export COMPOSE_FILE=compose.yaml:compose.build.yaml

This is what CI does, so the pull-request smoke test exercises the commit under review rather than the last published image.

Build the image directly

docker build \
  --build-arg SOUNDSIBLE_VERSION=dev \
  --build-arg VCS_REF="$(git rev-parse --short HEAD)" \
  -t soundsible:dev .
docker run --rm -p 5005:5005 \
  -v soundsible-config:/config \
  -v soundsible-data:/data \
  -v soundsible-cache:/cache \
  -v soundsible-logs:/logs \
  -v soundsible-music:/music \
  soundsible:dev

Search documentation