Sequshii

Requirements

One x86-64 or ARM64 machine with Docker, 512 MB of RAM, and read access to your audio files. ffmpeg ships inside the image, so there is nothing else to install.

Disk use beyond the library itself is the index plus the transcode cache. Budget roughly 90 MB per 100,000 tracks for the index, and cap the cache with SEQ_CACHE_SIZE if space is tight.

Install

Quick start

docker run -d --name sequshii \
  -p 127.0.0.1:4533:4533 \
  -v /srv/music:/data:ro \
  -v sequshii-data:/var/lib/sequshii \
  sequshii/server:0.9.4

Open http://127.0.0.1:4533. The first account you create becomes the administrator; there is no default password.

Compose

# docker-compose.yml
services:
  sequshii:
    image: sequshii/server:0.9.4
    container_name: sequshii
    ports:
      - "127.0.0.1:4533:4533"
    volumes:
      - ./data:/var/lib/sequshii
      - /srv/music:/data:ro
    environment:
      SEQ_SCAN_INTERVAL: 15m
      SEQ_TRANSCODE: auto
      SEQ_LOG_LEVEL: info
    restart: unless-stopped
Bind to loopback. The examples publish on 127.0.0.1 deliberately. Sequshii has no rate limiting of its own — put TLS and throttling in front of it rather than exposing 4533 to the internet.

Library layout

Any structure works. The scanner reads tags, not paths, and falls back to the folder name only when a track has no album tag at all.

Reverse proxy

Streaming responses are long-lived and must not be buffered. Both examples below turn buffering off and raise the read timeout.

nginx

server {
    listen 443 ssl;
    http2 on;
    server_name music.example.com;

    ssl_certificate     /etc/letsencrypt/live/music.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/music.example.com/privkey.pem;

    client_max_body_size 0;

    location / {
        proxy_pass http://127.0.0.1:4533;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $http_connection;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_buffering off;
        proxy_read_timeout 3600s;
    }
}

Caddy

music.example.com {
    reverse_proxy 127.0.0.1:4533 {
        flush_interval -1
    }
}
Serving from a subpath needs SEQ_BASE_URL set to the same prefix, otherwise the player requests its assets from the domain root and you get a blank page with 404s in the console.

Configuration

Every option is an environment variable. Values shown are the defaults.

SEQ_PORT4533 — listen port inside the container
SEQ_DATA_DIR/var/lib/sequshii — index, cache, and settings
SEQ_MUSIC_DIR/data — mount your library here, read-only is fine
SEQ_SCAN_INTERVAL15m — set to 0 to scan only on demand
SEQ_SCAN_WATCHtrue — inotify on top of the interval; turn off for network mounts
SEQ_TRANSCODEauto — one of auto, never, always
SEQ_CACHE_SIZE2GB — transcode cache ceiling, evicted least-recently-used
SEQ_BASE_URLempty — set when serving under a subpath
SEQ_SESSION_TTL720h — how long a browser session stays signed in
SEQ_LOG_LEVELinfo — error, warn, info, debug
SEQ_METRICSfalse — exposes Prometheus metrics on /metrics

Transcoding

With auto, Sequshii checks what the browser advertises and sends the original file when it can be played directly. FLAC to Firefox and Chrome goes out untouched; Safari gets AAC because it will not decode FLAC in an <audio> element reliably.

Each device remembers its own ceiling. A phone on mobile data can sit at 128 kbps Opus while the desktop on the same account gets the original file. The ceiling is per device, not per user.

DSF is always transcoded. Nothing in a browser plays DSD natively, and the conversion to 24-bit PCM happens once and is then cached.

Users

Accounts are local. There is no OAuth, no LDAP, and no plan for either during beta. An administrator can create accounts from Settings, and each account keeps its own queue, position, ratings, and history.

Deleting an account removes its play data but never touches files on disk.

Subsonic API

A subset of the Subsonic API is available under /rest/ so existing mobile clients work. Implemented: browsing, search, streaming, playlists, star and unstar, and scrobble submission.

Not implemented: podcasts, internet radio, jukebox mode, video, and chat. Clients that assume those exist may show empty sections rather than an error.

Token authentication uses the account password. Generate a separate app password in Settings rather than reusing the one you sign in with.

Troubleshooting

The scan finds nothing

Check the mount from inside the container: docker exec sequshii ls /data. An empty result means the volume path is wrong. If files are listed but the count stays at zero, run docker logs sequshii — permission errors on the first unreadable folder abort that branch of the walk.

Playback stalls after about a minute

Almost always proxy buffering. Set proxy_buffering off in nginx or flush_interval -1 in Caddy, and raise the read timeout above the length of your longest track.

Gaps between tracks on Safari

Safari does not honour the preload hint the way other browsers do. Gapless works on desktop Safari 17 and later; on iOS there is currently a short gap and no way around it from the server side.

Artwork is missing for some albums

Embedded art above 8 MB is skipped to keep the index small. Drop a cover.jpg beside the files and rescan.

Backups

Only SEQ_DATA_DIR matters. Stop the container, copy the directory, start it again — the SQLite index is not safe to copy while it is being written.

docker stop sequshii
tar czf sequshii-$(date +%F).tar.gz ./data
docker start sequshii

The transcode cache inside that directory is disposable. Exclude cache/ if you want a smaller archive; it rebuilds on demand.