feat(deploy): sidecars beside the instance, Jellyfin the first, behind an edge network

An instance may now run services beside itself, each a compose file of
its own switched on in deploy/.env (COMPOSE_FILE=compose.yaml:compose.
jellyfin.yaml), so the deploy runs them with the instance. The first is
Jellyfin, which people watch and listen to learn from: the instance then
suggests it (JELLYFIN_URL from JELLYFIN_DOMAIN), and Caddy serves its
site, refusing every change to a user from outside, so a passwordless
demo account stays everyone's; its admin signs in through an SSH tunnel.

The instance's compose gets a second network, `edge`, for Caddy (at a
fixed address, which sidecars trust as their proxy) and the server;
Postgres stays on the internal one. Caddy loses its needless way to
Postgres, and a sidecar never gains one. A sidecar publishes no port,
as the CI runner may reach 127.0.0.1, and runs as a user ID of its own.
Caddy imports the sidecars' sites from sidecars/, mounted by their
compose files (none without), and redeploy.sh recreates it when one
changes. sidecars/README.md has the steps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
Tizian 「ティツィアーン」 2026-10-14 00:16:53 +02:00
commit 4b45cacfa4
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64

View file

@ -8,7 +8,15 @@
# Only Caddy publishes ports. Docker opens published ports directly in the kernel's
# packet filter, past ufw, and the Serverpod server listens on every interface, so the
# server and Postgres publish nothing: they're reachable only inside this project's
# network, where Caddy finds the server by its service name.
# networks, where Caddy finds the server by its service name.
#
# Two networks (decided 2026-10-14): `edge`, Caddy's, which the server shares with it,
# and the internal default one, where the server reaches Postgres. Caddy never reaches
# Postgres, nor does a sidecar behind Caddy.
#
# Sidecars (decided 2026-10-14) are each a compose file of their own beside this one,
# switched on in .env (COMPOSE_FILE=compose.yaml:compose.jellyfin.yaml): each adds its
# service and mounts its site into Caddy's sidecars/ folder (sidecars/README.md).
name: halkyon-learn
@ -32,6 +40,11 @@ services:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data # certificates: must survive restarts (rate limits)
- caddy_config:/config
networks:
edge:
# Fixed, so containers behind Caddy can trust it as their proxy (the
# visitor's own address comes in X-Forwarded-For).
ipv4_address: 172.30.80.2
depends_on:
- server
logging: *logging
@ -72,6 +85,9 @@ services:
# Every release of every published studyset: backed up beside the database
# (backup.sh), never deleted with `down -v`.
- repositories:/app/repositories
networks:
- default
- edge
depends_on:
postgres:
condition: service_healthy
@ -115,6 +131,13 @@ services:
retries: 12
logging: *logging
networks:
edge:
name: halkyon-learn-edge
ipam:
config:
- subnet: 172.30.80.0/24
volumes:
caddy_data:
caddy_config: