Installation¶
Nessie runs on a Linux machine next to your music: a Raspberry Pi is the ideal cheap one. The easiest way to run it is Docker Compose, which starts Nessie and its PostgreSQL database together.
Docker Compose¶
You need Docker with the Compose plugin, and git.
git clone https://github.com/jonp92/Nessie.git
cd Nessie/deploy/example
cp .env.example .env # then set MUSIC_DIR and POSTGRES_PASSWORD
docker compose up -d --build
Open http://<server-address>:8000. With no libraries yet, the app opens Settings →
Libraries: add /music (or a folder inside it) and the scan starts.
The compose file, deploy/example/compose.yaml:
# Nessie with its own Postgres: a starting point for your own server. See docs/install.md
# (https://getnessie.app/install/). Copy .env.example to .env next to this file and fill it in, then:
#
# docker compose up -d --build
#
# Upgrading: git pull, then the same command. The database is migrated when the container starts.
name: nessie
services:
nessie:
build: ../..
image: nessie:local
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- "${NESSIE_PORT:-8000}:8000"
env_file: .env
environment:
DATABASE_URL: postgresql+psycopg://${POSTGRES_USER:-nessie}:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-nessie}
# The folders Settings → Libraries can add, inside the container
LIBRARY_BROWSE_ROOTS: '["/music"]'
volumes:
- data:/data
- ${MUSIC_DIR:?set MUSIC_DIR to your music folder}:/music:ro
# Playing on the server's speakers: uncomment these, and set MPV_AUDIO_DEVICE in .env
# (docker compose run --rm nessie mpv --audio-device=help lists them)
# - /dev/snd:/dev/snd
# device_cgroup_rules:
# - "c 116:* rmw" # ALSA's devices
# group_add:
# - "${AUDIO_GID:-29}" # the host's audio group: getent group audio
extra_hosts:
# Lidarr and the like, on this machine: LIDARR_URL=http://host.docker.internal:8686
- "host.docker.internal:host-gateway"
db:
image: postgres:17
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER:-nessie}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB:-nessie}
volumes:
- db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 5
volumes:
data:
db:
and its .env, where every setting from Configuration can go too:
# Nessie: copy to .env next to compose.yaml and fill in. Every setting in docs/configuration.md
# can go here too.
# Your music, on this machine (mounted read-only at /music)
MUSIC_DIR=/srv/music
NESSIE_PORT=8000
POSTGRES_PASSWORD=change-me
# The server's name in the app's output menu
PLAYER_NAME=Living Room
# MPV_AUDIO_DEVICE=alsa/hw:CARD=Device,DEV=0
# Sent to MusicBrainz with artwork lookups, as it asks: an email address or URL
MUSICBRAINZ_CONTACT=you@example.com
# Let Settings → Server change the settings it lists (saved in the data volume)
ALLOW_REMOTE_SETTINGS=true
- The music is mounted read-only at
/music. More than one folder? Mount each one (say/music/rock,/music/jazz) and list them inLIBRARY_BROWSE_ROOTS. - Settings, artwork and volume are kept in the
datavolume, the library in thedbvolume. - Playing on the server's speakers needs the sound card in the container: uncomment the
/dev/sndlines, and pick the device withMPV_AUDIO_DEVICE(docker compose run --rm nessie mpv --audio-device=helplists them). Without it, music plays in the browser and the apps.
Upgrading: git pull, then docker compose up -d --build again. The database is brought up to
date when the container starts. Back it up first with
docker compose exec db pg_dump -Fc -U nessie nessie > nessie.dump.
Without Docker¶
Requirements¶
- Python 3.12 or newer (developed on 3.14)
- PostgreSQL (Docker is fine for just the database)
- mpv for playback on the server
- ffmpeg: optional, only used by some tests
- shairport-sync: optional, for AirPlay. It
needs metadata support and the pipe turned on in its config:
metadata = { enabled = "yes"; include_cover_art = "yes"; pipe_name = "/tmp/shairport-sync-metadata"; };
Setup¶
cp .env.example .env # then set POSTGRES_PASSWORD (and DATABASE_URL to match)
docker compose up -d # PostgreSQL on :5432, Adminer on :8080
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
alembic upgrade head # create or update the database tables
uvicorn app.main:app --host 0.0.0.0 --port 8000 --timeout-graceful-shutdown 3
--timeout-graceful-shutdown 3 because the app keeps its live updates (/v1/events) open: without
it, stopping or reloading the server waits for every open page. Stopping with one open logs
Cancel 1 running task(s), timeout graceful shutdown exceeded, which is expected; the page
reconnects by itself. Behind a proxy, live updates need the response passed on as it comes:
Caddy does that for text/event-stream already, and Nessie sends X-Accel-Buffering: no for nginx.
Libraries can also be added from the command line:
python -m app.cli scan /media/usb/Music --name "USB Music"
Run alembic upgrade head again after pulling changes: new versions may add database
migrations.
The classic app¶
The app before this one is still at http://<server-address>:8000/v2/ (linked as Classic
view in the sidebar). Both use the same API and data.
HTTPS¶
Over plain http://<lan-address> everything works except the service worker, so there is no
offline music on phones. Browsers won't register one on a page with a certificate error even
after the warning is accepted, so the certificate has to be trusted: for example, a local
certificate authority installed on each device, Caddy with tls internal, or a Tailscale
HTTPS certificate.
To reach Nessie away from home, and to let each person sign in, see Profiles and sign-in.