build(train): Train's server and BRouter deployable beside the instance (ADR 0030, D46)

deploy/compose.train.yaml adds Train's server at train.halkyon.eu, a
member of Learn's register, with its database halkyon_train in the
instance's PostgreSQL, and BRouter beside it alone (v1.7.10, checked by
SHA-256, no log), its segments of the operator's region kept current
monthly. Nothing changes until deploy/.env names the compose file:
redeploy.sh and backup.sh take Train in only then, and the operator's
steps are in sidecars/README.md. restic now forgets snapshots grouped by
host alone, so adding Train's dump leaves no group behind for good.

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-29 00:05:39 +01:00
commit a8f7c26e69
Signed by: raisondetredev
GPG key ID: 07F6FCF405488B64
2 changed files with 483 additions and 36 deletions

View file

@ -0,0 +1,60 @@
# Train's server image (ADR 0030, D46). Built from the repository root (the build
# context), because the workspace's root pubspec and lockfile live there:
#
# docker build -f apps/train/halkyon_train_server/Dockerfile .
#
# Learn's server image (apps/learn/halkyon_learn_server/Dockerfile) for Train: the
# same Dart, the same Ubuntu runtime and start command; no git, no repositories
# folder, no data of its own.
# ── Build stage: compile the server to a native executable ────────────────────────
FROM dart:3.13.4 AS build
WORKDIR /app
COPY pubspec.yaml pubspec.lock ./
COPY tool/workspace_only.sh tool/
COPY apps/train/halkyon_train_server apps/train/halkyon_train_server
COPY packages/halkyon_base_server packages/halkyon_base_server
COPY packages/halkyon_base_client packages/halkyon_base_client
COPY packages/halkyon_core packages/halkyon_core
COPY packages/halkyon_llm packages/halkyon_llm
COPY packages/halkyon_oidc_server packages/halkyon_oidc_server
COPY packages/halkyon_oidc_client packages/halkyon_oidc_client
# The workspace root with only the server and the modules it builds on, as Learn's
# image has it (the reasons there).
RUN sh tool/workspace_only.sh apps/train/halkyon_train_server packages/halkyon_base_server packages/halkyon_base_client packages/halkyon_core packages/halkyon_llm packages/halkyon_oidc_server packages/halkyon_oidc_client
RUN dart pub get
WORKDIR /app/apps/train/halkyon_train_server
RUN dart build cli --target bin/main.dart --output build
RUN mv build/bundle/bin/main build/bundle/bin/server
RUN mkdir -p config migrations
# ── Runtime stage ─────────────────────────────────────────────────────────────────
# Ubuntu 24.04 as Learn's; CA certificates for outgoing TLS (Polar's firmware
# service, D40).
FROM ubuntu:24.04
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
ENV runmode=production
ENV serverid=default
ENV logging=normal
ENV role=monolith
COPY --from=build /app/apps/train/halkyon_train_server/build/bundle/ ./
COPY --from=build /app/apps/train/halkyon_train_server/config/ config/
COPY --from=build /app/apps/train/halkyon_train_server/migrations/ migrations/
COPY --from=build /app/apps/train/halkyon_train_server/lib/src/generated/protocol.yaml lib/src/generated/protocol.yaml
# No root rights needed: it listens on 8080 and 8082 and writes nothing.
RUN useradd --system --no-create-home --shell /usr/sbin/nologin app
USER app
# The API server, and the web server the register tells of accounts gone (ADR
# 0016), reached on the instance's own network alone.
EXPOSE 8080 8082
ENTRYPOINT ["/bin/sh", "-c", "exec ./bin/server --mode=$runmode --server-id=$serverid --logging=$logging --role=$role \"$@\"", "--"]
CMD []

View file

@ -1,27 +1,20 @@
# This is the configuration file for your production environment.
# Typically, you will want to route the traffic through a load balancer
# which adds SSL security through https. If you use Serverpod's standard
# Terraform scripts to deploy your server, all you need to change in
# this file is the examplepod.com domain name.
# Train's server on learn.halkyon.eu's server, at train.halkyon.eu (ADR 0030, D46),
# behind the instance's Caddy (deploy/compose.train.yaml): its API and its web server
# on the one domain, as Learn's; its database in the instance's PostgreSQL.
# Configuration for the main API server.
apiServer:
port: 8080
publicHost: api.examplepod.com
publicHost: train.halkyon.eu
publicPort: 443
publicScheme: https
# Configuration for the Insights server.
insightsServer:
port: 8081
publicHost: insights.examplepod.com
publicPort: 443
publicScheme: https
# No insightsServer, as Learn's: without the block Serverpod doesn't start Insights.
# Configuration for the web server.
webServer:
port: 8082
publicHost: app.examplepod.com
publicHost: train.halkyon.eu
publicPort: 443
publicScheme: https
@ -30,11 +23,12 @@ webServer:
# If you are connecting on a public IP (e.g. on AWS or Google Cloud Run), you
# connect on the public IP of the database e.g. database.examplepod.com.
database:
host: database.private-production.examplepod.com
host: postgres
port: 5432
name: serverpod
user: postgres
requireSsl: true
name: halkyon_train
user: halkyon_train
# On the instance's own network, never leaving the server.
requireSsl: false
#isUnixSocket: true # defaults to false
#maxConnectionCount: 10 # Defaults to 10, a negative or null value removes the limit