Edgible cards

Cards / jellyfin

jellyfin

Jellyfin, your films, shows and music, streamed to its apps and the web

App cardpassed 2026-10-12, Edgible 1.4.6Source on GitHub

The apps, ports, auth modes, and places in the jellyfin card

Apps

AppWhatWho can reach itPlace
jellyfinJellyfin web, API, and its TV and phone appsopen to anyonejellyfin

Machine

A place is one serving device. Minimum recommended for each:

PlaceMemoryDiskArchitectureGPU
jellyfin4 GB10 GBamd64, arm64optional

Needs it answers

Why

Films, shows and music you already own shouldn't need a subscription to watch. Jellyfin is a free media server that streams your own library to its TV, phone and desktop apps and to any browser, from a machine you own.

What

One app, jellyfin, on the place jellyfin, on none. That is deliberate: Jellyfin's TV, phone and desktop apps cannot get past an Edgible sign-in, so org would stop them playing. Jellyfin's own login protects it, and nobody can sign up: the setup wizard makes the admin from the command line before anything is public, and the admin adds everyone else.

It runs one service, jellyfin, from the image Jellyfin publishes, pinned to 12.2.20261005-225228. Your media folder is mounted read-only, so Jellyfin never changes your files. Hardware transcoding is optional: on Linux with an Intel or AMD GPU, uncomment the devices: lines in the Compose file. Without it, Jellyfin transcodes on the CPU, or not at all when the app plays the file as it is.

To use it in a card, copy the jellyfin service, its two volumes, and the JELLYFIN_ lines.

Settings, users and watch history live in the volume jellyfin-config, and artwork and transcodes in jellyfin-cache. Back up jellyfin-config; the cache rebuilds. Your media stays in JELLYFIN_MEDIA_DIR, outside Docker. The memory below is Jellyfin's own documented minimum, which is higher than an empty test library measures; transcoding several streams wants more. The disk is for Jellyfin itself, not your media. Minimum recommended for the place jellyfin: 4 GB of memory and 10 GB of disk, on an arm64 or amd64 machine, with a GPU if you have one (it runs without).

The Compose file is docker-compose.yml, the settings card.env, the card card.yml, and the last test test.yml.

How

Five steps. Edit card.env before you start.

1. Fetch

mkdir -p jellyfin
curl -fsSL https://github.com/Edgible/cards/archive/refs/heads/main.tar.gz \
  | tar -xz --strip-components=2 -C jellyfin cards-main/jellyfin

2. Edit card.env

Set DEVICE to a name edgible device list prints, and JELLYFIN_MEDIA_DIR to the full path of the folder that holds your media. Keep that folder outside jellyfin/, because the last Tear down step deletes jellyfin/. The admin password is generated in the next step.

nano jellyfin/card.env

3. Check

curl -fsSLo check-env.py https://raw.githubusercontent.com/Edgible/card-kit/main/check-env.py
python3 check-env.py jellyfin

It fills each empty secret and moves a taken port, as lines to paste. Run it again until it says no conflicts.

4. Start

docker compose --env-file jellyfin/card.env -f jellyfin/docker-compose.yml up -d --wait
docker compose --env-file jellyfin/card.env -f jellyfin/docker-compose.yml ps

--wait returns when each service is running, and healthy when it has a healthcheck. Then finish Jellyfin's setup wizard, before Publish, so it is never public. Until the wizard is finished, anyone who reaches Jellyfin can make the admin:

sh jellyfin/prepare.sh

prepare.sh is:

#!/bin/sh
# Prepare for the jellyfin card: finish Jellyfin's setup wizard, so it is never public.
# Run it after Start and before Publish, from the directory that holds jellyfin/:
#   sh jellyfin/prepare.sh
set -eu
cd "$(dirname "$0")"
set -a; . ./card.env; set +a
COMPOSE=${COMPOSE:-docker compose --env-file card.env -f docker-compose.yml}

B="http://127.0.0.1:$JELLYFIN_PORT"
H='Content-Type: application/json'
curl -fsS -X POST "$B/Startup/Configuration" -H "$H" \
  -d '{"UICulture":"en-US","MetadataCountryCode":"US","PreferredMetadataLanguage":"en"}'
curl -fsS "$B/Startup/User" >/dev/null
curl -fsS -X POST "$B/Startup/User" -H "$H" \
  -d "{\"Name\":\"$JELLYFIN_ADMIN_USER\",\"Password\":\"$JELLYFIN_ADMIN_PASSWORD\"}"
curl -fsS -X POST "$B/Startup/RemoteAccess" -H "$H" \
  -d '{"EnableRemoteAccess":true,"EnableAutomaticPortMapping":false}'
curl -fsS -X POST "$B/Startup/Complete"

It prints nothing when it works. The first start downloads about 400 MB.

5. Publish

set -euo pipefail
set -a
. jellyfin/card.env
set +a
device_id=$(edgible device list --json | jq -er --arg name "$DEVICE" '
  map(select(.name == $name))
  | if length == 1 then .[0].id
    else error("need exactly one device named " + $name + " (" + (map(.status + " " + .id) | join(", ")) + ")")
    end
')
edgible app create existing \
  --non-interactive \
  --name jellyfin \
  --port "$JELLYFIN_PORT" \
  --protocol https \
  --auth-modes none \
  --device-id "$device_id"
edgible app list

Verify

jellyfin uses none.

curl -sS -o /dev/null -w '%{http_code}\n' "https://<jellyfin hostname>"

That prints 302: Jellyfin sending you to its web app, with no Edgible sign-in, as its apps need. Sign in with JELLYFIN_ADMIN_USER and JELLYFIN_ADMIN_PASSWORD, and add a library pointing at /media. In a Jellyfin app, set the server to https://<jellyfin hostname> and sign in the same way.

The rest of the setup is in the Jellyfin docs.

Tear down

Four steps, in this order. Step 1 runs wherever edgible is logged in. Steps 2 to 4 run on the machine that runs the containers. Steps 2 and 3 read card.env, so keep it until step 4.

1. Unpublish

edgible app delete jellyfin --yes

2. Stop

docker compose --env-file jellyfin/card.env -f jellyfin/docker-compose.yml down

3. Delete the data

Skip this step to keep the data. The loop copies each volume to a .tgz file in this directory first.

for volume in $(docker volume ls -q --filter label=com.docker.compose.project=jellyfin); do
  docker run --rm -v "$volume:/data:ro" -v "$PWD:/backup" alpine tar -czf "/backup/$volume.tgz" -C /data .
done
docker compose --env-file jellyfin/card.env -f jellyfin/docker-compose.yml down --volumes

4. Remove the card

rm -rf jellyfin