Install with Docker
Kryspal Media runs as two containers, the server and its PostgreSQL database, started with one Docker Compose file. The images support x86 (amd64) and ARM (arm64).
On this page
Before you start#
- Docker and Docker Compose v2 are installed.
- You know where your media lives on the host (for example
/volume1/movies).
Install with one command (Linux host or VPS)#
For a Linux machine or VPS that already has Docker. The script writes the compose file, starts it and waits until the server is healthy. Replace /srv/media with the folder that holds your movies and series:
curl -fsSL https://media.kryspal.net/install.sh | bash -s -- --media /srv/media
Run the same command again to upgrade; see Upgrade and back up.
-
Read the script first. Download it, read it, then run it:
curl -fsSL https://media.kryspal.net/install.sh -o install.sh less install.sh bash install.sh --media /srv/media -
More than one media folder. Repeat
--media, for example--media /volume1/movies --media /volume2/tv. One folder is mounted at/media; with several, each is mounted at/mediaplus its full path, such as/media/volume1/movies. To keep other container paths, see Media outside /media.curl -fsSL https://media.kryspal.net/install.sh | bash -s -- \ --media /volume1/movies \ --media /volume2/tv
On an upgrade --media is ignored; to change the folders, edit compose.yaml.
- Where things are. The compose file and a small .env are in /opt/kryspal-media (change it with --dir). The data is in the Docker volumes kryspal-media_data, kryspal-media_pgdata and kryspal-media_db.
- If Docker is missing, the script stops and says where to get it. --install-docker lets it use Docker's official installer; --no-pull is for an offline host.
- What an upgrade does. It pulls the newest images and recreates the containers, and never deletes your data. Your compose.yaml stays as it is; if a new version changes it, the new file is saved next to it as compose.yaml.new.
- Outside access. The port speaks plain HTTP, so put a reverse proxy with HTTPS in front of it and never forward port 5797. See Remote access.
- Not for a NAS. A project made from the command line is not shown in a NAS container manager. Use Docker Compose there.
Install on a NAS with Docker Compose#
Use this on Synology, QNAP and other NAS systems, where you create a project by pasting compose YAML into the container manager. Any other host with Docker can use it too.
-
Create a folder, and in it a file named
compose.yamlwith this content (in a NAS container manager, paste it where it asks for the compose file):services: server: image: kryspal/kryspalmedia:latest restart: unless-stopped stop_grace_period: 60s ports: - "5797:5797" # LAN - "5798:5798" # WAN # - "7359:7359/udp" # discovery environment: EXTERNAL_HTTP_ADDR: ":5798" # WAN volumes: - /path/to/media:/media # 2+ folders: use these instead # - /mnt/movies:/media/mnt/movies # - /mnt/tv:/media/mnt/tv - data:/var/lib/mediaserver - db:/var/lib/kryspal-db:ro depends_on: - postgres postgres: image: kryspal/kryspalmedia-postgres:16 restart: unless-stopped stop_grace_period: 60s volumes: - pgdata:/var/lib/postgresql/data - db:/var/lib/kryspal-db volumes: data: pgdata: db: -
Replace
/path/to/mediawith your media folder on the host. For more than one folder, add onevolumesline per folder, mounted under/mediaplus its full path, for example- /mnt/tv:/media/mnt/tv. A folder mounted outside/mediais refused by the server. -
Start it (in a NAS container manager, create and start the project):
docker compose up -d -
Open
http://<host>:5797and follow the setup wizard to create the first administrator. See First-time setup. The admin console is athttp://<host>:5797/web/. - In your player (Infuse and others), enter the server address
http://<host>:5797and a member account.
NAS with file ACLs (UGREEN, Synology and similar). The server runs as user mediaserver (uid and gid 1000) inside the container. On these systems the permission shown by ls is not the whole story: access is decided by the NAS's own ACL, which is often granted to a group such as admin, not to gid 1000. The symptom is "library root unavailable: … permission denied" (the library shows as offline) although the folder looks open to everyone. The one-line installer checks this for you: it tries each media folder with a throw-away read-only container and, when a folder cannot be read, adds the first group of your user that works as group_add in compose.yaml. With your own compose file, add the group that can read your media to the server service, then run docker compose up -d again:
group_add:
- "10" # the gid from `id -g` of the user that can read the files
To make the media folder completely read-only, add :ro to its line; subtitle download, NFO and image write-back, and deleting files then cannot work.
To upgrade, run docker compose pull and docker compose up -d. The database structure is upgraded automatically on first start; on a large library this can take a minute or two. See Upgrade and back up.
Ports, folders and data#
Automatic discovery. Emby and Jellyfin use 7359/udp too, so the compose file leaves this line commented out. install.sh turns it on when the port is free.
To let players find the server by themselves:
- Make sure Emby or Jellyfin is not using 7359/udp.
- Remove the
#in front of the7359:7359/udpline in the compose file. - Recreate the container.
Players can always type the server address instead.
| What | Details |
|---|---|
| HTTP port | 5797. Players, the Kryspal web player and the admin console all use it. |
| Outside-access port | 5798. Forward only this one on your router; connections that arrive here always count as outside your network. |
| Discovery port | 7359 (UDP), off by default in the compose file. Lets players on your local network find the server. See below. |
| Server data | The data volume (/var/lib/mediaserver): keys, settings, uploaded images, installed plugins, and the image cache (thumbnails and pre-generated posters; the cache is rebuilt if you delete it). Back it up. |
| Database | The pgdata volume in the database container. Items, members, watch history. |
| Database password | The db volume. The password is generated automatically on first start and shared between the two containers; you never type it. |
| Database port | 5432 is not published to the host. Only the Docker network can reach it. |
| Media | Mounted at /media inside the container (the example mounts /path/to/media). With several folders from the install script, each one is at /media plus its full path, for example /media/volume1/movies. When you create a library in the admin console, enter the path as the container sees it, for example /media/Movies. Your media folders are read-only by default; Kryspal writes to them or deletes files in them only when you turn on subtitle download, write-back (NFO and images) or Allow deletion on a library. |
The database is not reachable from outside, and its password is generated for you.
Extras you can add#
- Access from outside your network. The compose file already publishes port 5798 (
WAN) and setsEXTERNAL_HTTP_ADDR: ":5798". Forward only 5798 on your router. Everything that arrives on this port counts as outside your network. We do not use 8920 because it clashes with Emby's HTTPS port when both run on one machine. - NAS file permissions. If your NAS uses file ACLs (for example Synology), add
user: "<uid>:<gid>"to the server, using the owner of your media files (id -uandid -g). - A bigger database memory setting. On a host with plenty of memory you can add a
command:to thepostgresservice to raise PostgreSQL's memory settings.
Use your own PostgreSQL#
You need PostgreSQL 16 or newer with the pg_bigm extension, which the Chinese search uses. Create a database and a user for Kryspal Media, remove the postgres service, the pgdata and db volumes, and the server's depends_on and db volume line, then add an environment: section to the server with DATABASE_URL set to your own connection string, for example postgres://user:password@db.example:5432/kryspal?sslmode=disable. The server creates its tables on first start. An account with enough privileges must run CREATE EXTENSION pg_bigm beforehand.
Automated deployments#
If you deploy by script and do not want the wizard, add INITIAL_ADMIN_PASSWORD to the server's environment: section. When the database has no members yet, the server creates the administrator at startup and the setup wizard is skipped. If you leave it out, the wizard runs.
The server keeps restarting and the log says "the data directory does not match this database"#
At start-up the server checks that the server identity and keys in the data volume are the same ones the database has on record. If they differ, it refuses to start, the container restarts over and over, and the log shows this line: the data directory does not match this database.
- First check that the
datavolume is mounted. The most common cause is a NAS that mounts an external or network disk later than the container starts, so the server sees an empty folder. Once the disk is mounted, restart the container:docker compose restart server. - Only if you changed the keys or the data folder on purpose, accept the change: add
ACCEPT_DATA_DIR_CHANGE: "true"to the server'senvironment:section and start it once. After it starts successfully, remove that line.