halkyon/deploy/sidecars/README.md
Tizian 「ティツィアーン」 8c57bdf4d1
docs(deploy): Jellyfin's group gets the ID its compose file runs it with
The sidecar's steps made Jellyfin's user with its own group, to which
useradd gave a system group ID (987 on learn.halkyon.eu's server), while
compose.jellyfin.yaml runs it as 61096:61096. The group is now made
first with the same ID, and the steps say why useradd's warning about an
ID above the system range is meant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-14 01:55:11 +02:00

4.4 KiB
Raw Blame History

Sidecars

Services an instance may run beside itself (decided 2026-10-14), each switched on by naming its compose file after the instance's own in deploy/.env:

COMPOSE_FILE=compose.yaml:compose.jellyfin.yaml

A sidecar's compose file adds its service and, if it is reached from outside, mounts its site from this folder into Caddy's /etc/caddy/sidecars/, which the Caddyfile imports. It joins the edge network beside Caddy and the server's public API, never the internal one where Postgres is, and publishes no port of its own. Its process runs as a user ID of its own, which no person, no other container and not the CI runner uses. redeploy.sh deploys whatever .env switches on, and recreates Caddy when a sidecar's site changes.

Sidecar Compose file Site
Jellyfin, which people watch and listen to learn from compose.jellyfin.yaml jellyfin.caddy

Jellyfin

A Jellyfin server beside the instance, which the instance then suggests to its people (JELLYFIN_URL, set by the compose file): the app's Jellyfin sign-in fills it in and lists the people it shows on its login screen. Videos stream as stored, nothing is transcoded. Caddy refuses every change to a user from outside, so an account without a password (a demo's) stays everyone's; the admin signs in through an SSH tunnel only.

Steps, in order; ✱ marks a step as root.

  1. ✱ Its user and folders (the operator, on the instance's server, as a user with sudo): the user and group ID 61096 are Jellyfin's alone, as the compose file runs it (useradd warns that the ID lies above the system range, which is meant: it must not meet a container's IDs); the media folder is deploy's, so it can copy files in, readable by all.

    sudo groupadd --system --gid 61096 jellyfin
    sudo useradd --system --uid 61096 --gid 61096 --no-create-home --shell /usr/sbin/nologin jellyfin
    cd ~deploy/halkyon-learn/deploy
    sudo mkdir -p jellyfin/config jellyfin/cache jellyfin/media
    sudo chown -R jellyfin:jellyfin jellyfin/config jellyfin/cache
    sudo chown -R deploy:deploy jellyfin/media
    
  2. DNS (the operator, at the domain's DNS): the Jellyfin domain, such as jellyfin.example.org, pointing at the instance's server (A, and AAAA if it has an IPv6 address).

  3. Switch it on (the operator, on the instance's server, as deploy): in deploy/.env,

    COMPOSE_FILE=compose.yaml:compose.jellyfin.yaml
    JELLYFIN_DOMAIN=jellyfin.example.org
    
  4. The media (the operator, on their own machine): a folder per film, show or album, as Jellyfin expects them, into deploy/jellyfin/media/, readable by all:

    rsync -av --chmod=D755,F644 "<folder>" <deploy's ssh alias>:halkyon-learn/deploy/jellyfin/media/movies/
    
  5. Start it (the operator, on the instance's server, as deploy): cd ~/halkyon-learn/deploy && docker compose up -d. Caddy and the server are recreated with it (the site, and the instance's suggestion); the instance is away for seconds.

  6. Set Jellyfin up through a tunnel (the operator, on their own machine): ssh -N -L 8096:172.30.80.10:8096 <deploy's ssh alias>, then http://localhost:8096.

    • The wizard: an admin of a name nobody guesses, its password in a password manager; a library of the type Movies (or Shows, Music) on /media/…; remote connections allowed.
    • Dashboard › Networking › Known proxies: 172.30.80.2 (Caddy's address on edge). Jellyfin then sees each visitor's own address, and the tunnel as local.
    • Dashboard › General: Quick Connect off, unless people sign in with it.
    • Dashboard › Users › the admin: Hide this user from login screens; Allow remote connections to this server off.
    • For a demo, Dashboard › Users › +: an account without a password, shown on login screens, seeing the demo's library alone; off: playback and conversion that need transcoding, content downloading, remote control of other users, deleting media.
  7. Check from outside (anyone, anywhere): https://<domain>/System/Info/Public answers, /Users/Public lists the demo account, a POST to /Users/Password gets 403, and the instance's instance.info() names the domain as jellyfinUrl.

Switching it off: the compose file out of COMPOSE_FILE, then docker compose up -d --remove-orphans; deploy/jellyfin/ stays until removed by hand.