feat(deploy)!: Jellyfin on halkyon.li as the sidecar, ADR 0032's home end gone (ADR 0039, D15)
The Jellyfin sidecar takes its library from a folder on the host where .env names one (JELLYFIN_MEDIA, read-only), else from deploy/jellyfin/media as before. On halkyon.li that is /data/media: the library moves out of the developer's home, which Jellyfin's own user can't enter. The sidecar README says how the home end's configuration, accounts and libraries move in, with its network settings corrected for Caddy before it starts. BREAKING CHANGE: compose.jellyfin-home.yaml, deploy/home-jellyfin/ and jellyfin.caddy's JELLYFIN_UPSTREAM are gone with ADR 0032, whose server end retires with learn.halkyon.eu's server; it was never brought up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
fd9c2dfe76
commit
2218695dcf
2 changed files with 113 additions and 496 deletions
|
|
@ -18,7 +18,6 @@ site changes.
|
|||
| Sidecar | Compose file | Site |
|
||||
|---|---|---|
|
||||
| Jellyfin, which people watch and listen to learn from | `compose.jellyfin.yaml` | `jellyfin.caddy` |
|
||||
| Jellyfin at home, published through a WireGuard tunnel, in its place | `compose.jellyfin-home.yaml` | `jellyfin.caddy` |
|
||||
| LanguageTool, which checks spelling and grammar | `compose.languagetool.yaml` | none |
|
||||
| Halkyon Train's server, with BRouter for its routes | `compose.train.yaml` | `train.caddy` |
|
||||
| Train's own map tiles, beside Train | `compose.maps.yaml` | `train-maps.caddy` (in Train's site) |
|
||||
|
|
@ -111,154 +110,57 @@ Steps, in order; ✱ marks a step as root.
|
|||
Switching it off: the compose file out of `COMPOSE_FILE`, then `docker compose up -d
|
||||
--remove-orphans`; `deploy/jellyfin/` stays until removed by hand.
|
||||
|
||||
## Jellyfin at home
|
||||
## Jellyfin on halkyon.li, moved in from ADR 0032's home end
|
||||
|
||||
The Jellyfin sidecar's site, served by the instance, with Jellyfin on the operator's own
|
||||
machine rather than beside the instance (ADR 0032): `compose.jellyfin-home.yaml` on the
|
||||
instance's server, `home-jellyfin/` on that machine, a WireGuard tunnel between them
|
||||
that the machine dials out on. People reach the instance's server alone; nothing names
|
||||
the home network's address, and its router opens no port. Caddy's rules are the
|
||||
sidecar's (`jellyfin.caddy`), and the tunnel reaches Jellyfin from Caddy alone and
|
||||
nothing of the instance's server (`home-jellyfin/server/wg-jellyfin-rules.sh`; nor can
|
||||
the CI runner reach it, `IPAddressDeny`). The instance suggests it only while it
|
||||
answers: `JELLYFIN_URL` stays unset, so the instance looks at `jellyfin.` on its own
|
||||
domain, which `JELLYFIN_DOMAIN` must therefore be. With the machine off, asleep or
|
||||
offline, Caddy answers 502, and the instance stops suggesting it at its first look
|
||||
after that, within about an hour. It takes the place of the sidecar, never runs
|
||||
beside it.
|
||||
On halkyon.li (ADR 0039, D15), the Jellyfin that ran as ADR 0032's home end becomes the
|
||||
sidecar above, with its configuration, accounts and library kept, on the same machine.
|
||||
Its library stays on the host rather than in `deploy/jellyfin/media`. Once, in place of
|
||||
the *Jellyfin* steps 1 and 4 to 6, after `../host/README.md`, step 4 (which stopped it),
|
||||
✱ as root:
|
||||
|
||||
The tunnel's addresses: 10.61.96.1 the instance's end, 10.61.96.2 the home end, UDP
|
||||
51820 on the instance's server. Steps, in order; ✱ marks a step as root, 🏠 one on the
|
||||
home machine.
|
||||
|
||||
1. 🏠 **The home end's key** (the operator, in `deploy/home-jellyfin/` of their
|
||||
checkout): WireGuard's own tool from the image, so nothing is installed; the
|
||||
private key goes into the git-ignored config, which only its owner reads, the
|
||||
public key is printed for step 3.
|
||||
1. ✱ **Its user**, the sidecar's (ID 61096), as *Jellyfin*, step 1 has it.
|
||||
2. ✱ **The library on the HDD, readable by Jellyfin**: the developer's home is closed to
|
||||
other users, and Jellyfin runs as its own. `/home` is a bind mount of `/data/home`,
|
||||
so this is a rename on one filesystem, instant whatever its size:
|
||||
|
||||
```sh
|
||||
cd deploy/home-jellyfin
|
||||
image=$(sed -n 's/^ *image: \(lscr.io\/linuxserver\/wireguard@.*\)/\1/p' compose.yaml)
|
||||
(umask 077 && mkdir -p wireguard/wg_confs &&
|
||||
docker run --rm --entrypoint wg "$image" genkey > wireguard/home.key)
|
||||
docker run --rm -i --entrypoint wg "$image" pubkey < wireguard/home.key
|
||||
sudo mv /home/raisondetredev/Media /data/media
|
||||
sudo chmod -R a+rX /data/media
|
||||
```
|
||||
|
||||
2. ✱ **The instance's end** (the operator, on the instance's server, as a user with
|
||||
sudo): WireGuard's tools, the key, and the files from the checkout. The key is in
|
||||
the password manager too: a new server needs it again, or the home end a new
|
||||
public key.
|
||||
`.env`: `JELLYFIN_MEDIA=/data/media`. Jellyfin's libraries keep their paths
|
||||
(`/media/…`), as the folder is mounted where it was.
|
||||
3. ✱ **Its configuration and cache into the deploy**, still Jellyfin's:
|
||||
|
||||
```sh
|
||||
sudo apt-get install wireguard-tools
|
||||
(umask 077 && wg genkey | sudo tee /etc/wireguard/wg-jellyfin.key | wg pubkey)
|
||||
from=~deploy/halkyon/deploy/home-jellyfin/server
|
||||
sudo install -m 0600 "$from/wg-jellyfin.conf" /etc/wireguard/wg-jellyfin.conf
|
||||
sudo install -m 0700 "$from/wg-jellyfin-rules.sh" /etc/wireguard/wg-jellyfin-rules.sh
|
||||
sudo install -D -m 0644 "$from/wg-quick-after-docker.conf" \
|
||||
/etc/systemd/system/wg-quick@wg-jellyfin.service.d/after-docker.conf
|
||||
old=/home/raisondetredev/project-halkyon/halkyon/deploy/home-jellyfin
|
||||
sudo install -d -o 61096 -g 61096 ~deploy/halkyon/deploy/jellyfin
|
||||
sudo mv "$old/jellyfin/config" "$old/jellyfin/cache" ~deploy/halkyon/deploy/jellyfin/
|
||||
```
|
||||
|
||||
The printed public key is the instance's, for step 4.
|
||||
4. ✱ **Its network settings for Caddy**, before it starts: ADR 0032's would count the
|
||||
admin's requests as remote and lock them out. In
|
||||
`~deploy/halkyon/deploy/jellyfin/config/network.xml` (`sudoedit`), the local networks
|
||||
emptied and Caddy named as the proxy, as *Jellyfin*, step 6 has them:
|
||||
|
||||
3. ✱ **Introduce the home end, open the port, start it** (as in step 2):
|
||||
`sudo nano /etc/wireguard/wg-jellyfin.conf`, the home end's public key from step 1
|
||||
in place of `<the home end's public key>`; where the host has a firewall, UDP 51820
|
||||
opened (`sudo ufw allow 51820/udp`); the runner's unit as the checkout has it, so it
|
||||
can't reach the tunnel; then the tunnel.
|
||||
```xml
|
||||
<LocalNetworkSubnets />
|
||||
<KnownProxies>
|
||||
<string>172.30.80.2</string>
|
||||
<string>fd4a:6c6b:7e80::2</string>
|
||||
</KnownProxies>
|
||||
```
|
||||
|
||||
5. ✱ **ADR 0032's tunnel removed**, its key with it (it never had a peer):
|
||||
|
||||
```sh
|
||||
sudo install -m 0644 ~deploy/halkyon/deploy/runner/forgejo-runner.service \
|
||||
/etc/systemd/system/forgejo-runner.service
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl restart forgejo-runner
|
||||
sudo systemctl enable --now wg-quick@wg-jellyfin
|
||||
sudo rm -rf "$old"
|
||||
```
|
||||
|
||||
4. 🏠 **The home end's config, folders and media** (in `deploy/home-jellyfin/`):
|
||||
`wg0.conf.example` as `wireguard/wg_confs/wg0.conf`, with the key from step 1 and
|
||||
the instance's public key from step 2; Jellyfin's folders owned by its user ID
|
||||
(61096, as on the instance's server: no person and no other container uses it); the
|
||||
media folder named in `.env` and readable by all, a folder per film, show or album
|
||||
as Jellyfin expects them.
|
||||
|
||||
```sh
|
||||
(umask 077 && sed "s|<the home end's private key>|$(cat wireguard/home.key)|" \
|
||||
wg0.conf.example > wireguard/wg_confs/wg0.conf)
|
||||
nano wireguard/wg_confs/wg0.conf # the instance's public key
|
||||
sudo install -d -o 61096 -g 61096 jellyfin/config jellyfin/cache
|
||||
echo "JELLYFIN_MEDIA=$HOME/Videos" > .env
|
||||
chmod -R o+rX "$HOME/Videos"
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
`sudo wg show wg-jellyfin` on the instance's server now shows a handshake.
|
||||
|
||||
Whenever `wg0.conf` fails to come up (a placeholder or a wrong key, an endpoint that
|
||||
doesn't resolve: why it names the server by its address, ADR 0032, D11, and a new
|
||||
address of the server's goes there too), the image's client mode deletes the namespace's default route
|
||||
(`ip route del default` in its `svc-wireguard/run`, ls126), and Jellyfin with it loses
|
||||
the internet: TMDb's metadata and images fail with *Network is unreachable*, and a
|
||||
library scanned then gets frames of its videos for posters. A tunnel that comes up
|
||||
keeps the route, even before its first handshake. Fixing `wg0.conf` alone isn't enough:
|
||||
`docker compose up -d --force-recreate`, both containers, since Jellyfin lives in
|
||||
WireGuard's namespace and a restart of WireGuard alone leaves it in the old one. The
|
||||
folder `wireguard/` is the container's user's (61096) from its first start on, so
|
||||
`wg0.conf` is edited with sudo.
|
||||
|
||||
5. 🏠 **Set Jellyfin up** at http://localhost:8096 on the home machine, before the site is
|
||||
switched on: the sidecar's step 6, but for its networking, which is the tunnel's:
|
||||
- Dashboard › Networking › **LAN networks**: `172.29.96.1/32` alone, the gateway
|
||||
through which this machine's loopback reaches it (`home-jellyfin/compose.yaml`).
|
||||
Left empty, Jellyfin counts every private range as local, the tunnel's too, and an
|
||||
admin without remote access could sign in through it.
|
||||
- Dashboard › Networking › **Known proxies**: `10.61.96.1`, as which Docker on the
|
||||
instance's server masquerades Caddy's requests. Jellyfin then sees each visitor's
|
||||
own address.
|
||||
- **Allow remote connections** on; the admin hidden from login screens, its remote
|
||||
connections off; Quick Connect, the demo account and its lockout as in the
|
||||
sidecar's step 6. Every account but those meant for everyone hidden from login
|
||||
screens: the instance suggests this server to all its people.
|
||||
|
||||
6. **Switch the site on** (the operator, on the instance's server, as `deploy`): in
|
||||
`deploy/.env`, `JELLYFIN_URL` left empty,
|
||||
|
||||
```sh
|
||||
COMPOSE_FILE=compose.learn.yaml:compose.jellyfin-home.yaml
|
||||
JELLYFIN_DOMAIN=jellyfin.halkyon.eu
|
||||
```
|
||||
|
||||
then `cd ~/halkyon/deploy && docker compose up -d`. Caddy and the server are
|
||||
recreated with it; the instance is away for seconds.
|
||||
|
||||
7. **Check from outside** (anyone, anywhere): the sidecar's step 7; and on the instance's
|
||||
server, as `deploy`, that nothing reaches the home end but Caddy, and the home end
|
||||
nothing of the server:
|
||||
|
||||
```sh
|
||||
# Refused (on edge, but not at Caddy's address): times out.
|
||||
docker run --rm --network halkyon-learn-edge caddy:2 \
|
||||
wget -T 5 -q -O /dev/null http://10.61.96.2:8096/System/Info/Public && echo LEAK
|
||||
# Caddy itself gets through.
|
||||
docker compose exec -T caddy wget -T 5 -q -O - http://10.61.96.2:8096/System/Info/Public
|
||||
```
|
||||
|
||||
and on the home machine, in `deploy/home-jellyfin/`:
|
||||
|
||||
```sh
|
||||
# Refused (nothing new from the tunnel reaches the host): gives up after 5 s. The
|
||||
# image's nc is OpenBSD's, whose own -w ends the try.
|
||||
docker compose exec -T wireguard nc -w 5 -z 10.61.96.1 22 && echo LEAK
|
||||
```
|
||||
|
||||
Stopping the home end (`docker compose stop`) makes the site answer 502, and
|
||||
`instance.info()` names no `jellyfinUrl` after the instance's next look, within about
|
||||
an hour.
|
||||
|
||||
Switching it off: on the instance's server the compose file out of `COMPOSE_FILE`, `docker
|
||||
compose up -d --remove-orphans`, and ✱ `sudo systemctl disable --now
|
||||
wg-quick@wg-jellyfin`, the port closed again; at home `docker compose down`, with
|
||||
`deploy/home-jellyfin/jellyfin/` kept until removed by hand.
|
||||
6. **Switch it on** as *Jellyfin*, step 3 (`JELLYFIN_DOMAIN=jellyfin.halkyon.li`), and
|
||||
start it (step 5). The admin then works through *Jellyfin*, step 6's tunnel from
|
||||
melchior, and checks under Dashboard › Networking that the settings of step 4 hold.
|
||||
Check from outside as step 7.
|
||||
|
||||
## LanguageTool
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,5 @@
|
|||
respond @userChanges 403
|
||||
respond /Startup/* 403
|
||||
|
||||
# The sidecar's Jellyfin, or Jellyfin at home through WireGuard
|
||||
# (compose.jellyfin-home.yaml, ADR 0032).
|
||||
reverse_proxy {$JELLYFIN_UPSTREAM:jellyfin:8096}
|
||||
reverse_proxy jellyfin:8096
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue