halkyon/deploy/compose.train.yaml
Tizian 「ティツィアーン」 fd9c2dfe76
feat(meditate,deploy): Meditate beside the instance, and every server's public address from .env
Meditate's deploy step (ADR 0038, step 7; ADR 0039, D14), as Todo's: the
server's Dockerfile with the library's check compiled beside it, its
production config on its own database and role, compose.meditate.yaml as a
member of the register, its site sending /library/* to the web server and
the rest to the API server, the operator's library read-only in a compose
file of its own, and redeploy.sh, backup.sh and the image replay taking it
in.

Every server's public address now comes from .env (Serverpod's
SERVERPOD_API_SERVER_PUBLIC_HOST and _WEB_SERVER_, which win over the
config file): Train, Todo and Meditate from their domains, Learn from
LEARN_PUBLIC_HOST, unset learn.halkyon.eu as before. Without it a server on
halkyon.li would name halkyon.eu in its SimpleLogin callback, profile pages
and privacy page.

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

124 lines
4.9 KiB
YAML

# Halkyon Train's server beside the instance (ADR 0030, D46), with the BRouter that
# plans its routes (D11, D44). Switched on in .env, with Train's domain and secrets:
#
# COMPOSE_FILE=compose.learn.yaml:compose.train.yaml
# TRAIN_DOMAIN=train.halkyon.eu
#
# Train is a member of the instance's register, which Learn's server holds (ADR 0016):
# one account a person, signing in through the register, the shared INSTANCE_SECRET
# on every call between them, which reach each other on the instance's own networks
# alone. Its database is `halkyon_train` in the instance's PostgreSQL, under a role of
# its own that can't connect to Learn's. BRouter has no site and no sign-in: only
# Train's server reaches it, on a network of their own, and asks it nothing that is
# logged. Its segments (Europe's, about 3.3 GB) are in ./brouter/segments, which the
# refresher keeps current monthly, owned by a user ID of their own, which no person,
# no other container and not the CI runner uses. Setting it up: sidecars/README.md.
services:
train-server:
build:
context: ..
dockerfile: apps/train/halkyon_train_server/Dockerfile
image: halkyon-train-server
restart: unless-stopped
# As Learn's: migrations at every start (redeploy.sh has applied them before).
command: ["--apply-migrations"]
environment:
SERVERPOD_DATABASE_PASSWORD: ${TRAIN_POSTGRES_PASSWORD:?set TRAIN_POSTGRES_PASSWORD in deploy/.env}
SERVERPOD_PASSWORD_serverSideSessionKeyHashPepper: ${TRAIN_SESSION_KEY_HASH_PEPPER:?set TRAIN_SESSION_KEY_HASH_PEPPER in deploy/.env}
# Its public address, which config/production.yaml names otherwise: the
# instance's own domain.
SERVERPOD_API_SERVER_PUBLIC_HOST: ${TRAIN_DOMAIN:?set TRAIN_DOMAIN in deploy/.env}
SERVERPOD_WEB_SERVER_PUBLIC_HOST: ${TRAIN_DOMAIN:?set TRAIN_DOMAIN in deploy/.env}
# The register (ADR 0016): Learn's web server, on the instance's own network,
# and the secret every call between them carries.
ACCOUNT_REGISTER_URL: http://server:8082/
SERVERPOD_PASSWORD_instanceSecret: ${INSTANCE_SECRET:?set INSTANCE_SECRET in deploy/.env}
# Caddy, as for Learn's server (compose.learn.yaml).
TRUSTED_PROXIES: 172.30.80.2 fd4a:6c6b:7e80::2
SOURCE_URL: ${SOURCE_URL:-}
DATA_LOCATION: ${DATA_LOCATION:-}
BACKUP_LOCATION: ${BACKUP_LOCATION:-}
# Routes (D44), from the BRouter below.
BROUTER_URL: http://brouter:17777/
# The Loop's firmware through the instance (D40): on unless `off`.
LOOP_FIRMWARE_RELAY: ${LOOP_FIRMWARE_RELAY:-}
# Workouts' weather from Open-Meteo (ADR 0036): on unless `off`; a key
# for its paid hosts where the instance is used commercially.
WEATHER: ${WEATHER:-}
OPEN_METEO_API_KEY: ${OPEN_METEO_API_KEY:-}
# The map source (D22); empty: OpenFreeMap.
MAP_STYLE_URL: ${MAP_STYLE_URL:-}
MAP_DARK_STYLE_URL: ${MAP_DARK_STYLE_URL:-}
MAP_SOURCE_NAME: ${MAP_SOURCE_NAME:-}
MAP_ATTRIBUTION: ${MAP_ATTRIBUTION:-}
MAP_ABOUT_URL: ${MAP_ABOUT_URL:-}
networks:
- default
- edge
- routing
depends_on:
postgres:
condition: service_healthy
logging:
driver: journald
brouter:
build:
context: ..
dockerfile: deploy/brouter/Dockerfile
image: halkyon-brouter
restart: unless-stopped
user: "61177:61177"
read_only: true
tmpfs:
- /tmp:size=16m,uid=61177,gid=61177
volumes:
- ./brouter/segments:/segments4:ro
# Beside Train's server alone: no site, no published port, never beside Caddy or
# Postgres.
networks:
- routing
mem_limit: 640m
# No log at all: BRouter writes each route's waypoints to its output, and where
# people run must never be kept. To look into a failure, switch to journald for
# a while.
logging:
driver: none
brouter-segments:
image: halkyon-brouter
restart: unless-stopped
user: "61177:61177"
read_only: true
command: ["/app/segments.sh"]
environment:
# `west,south,east,north` of the segments' south-west corners; Europe's.
BROUTER_REGION: ${BROUTER_REGION:--25,35,40,70}
volumes:
- ./brouter/segments:/segments4
# Out to brouter.de on `downloads`, an ordinary bridge with a way out to anywhere,
# shared with the map's and the search's downloads where their compose files are on.
networks:
- downloads
mem_limit: 64m
logging:
driver: journald
caddy:
environment:
TRAIN_DOMAIN: ${TRAIN_DOMAIN:?set TRAIN_DOMAIN in deploy/.env}
volumes:
- ./sidecars/train.caddy:/etc/caddy/sidecars/train.caddy:ro
server:
environment:
# Train's web server, told when an account goes (ADR 0016), beside the members
# the other compose files and INSTANCE_MEMBERS name.
INSTANCE_MEMBER_TRAIN: http://train-server:8082/
networks:
# Train's server and BRouter, without a way out.
routing:
internal: true
downloads: