docker::install is the Linux counterpart of install::install_base and shares none
of its code (the Windows installer and its folder checks are untouched). Same
order of events: signed manifest, folder / space / game data checks, verified
download, extraction into <dest>.installing, database, one rename. Docker must be
usable; a failure removes the containers, the volume and the staging folder.
The databases start from the package's own dumps, Database/baseline/<kind>.sql.zst,
in the format of the Manager's backups, taken in a state where every migration of
the package is applied. The installer imports them, records the migrations as
applied (baseline) in a few bulk statements, and creates the acore account, the
realm port and the console account. Rebuilding from the repository's SQL does not
work: pending migrations such as rev_20260903_01_live_class_baseline are guards
generated from the maintainers' live database and refuse to run on a database
built from the base scripts, whatever the order.
- coa-release export-baseline --server DIR --out DIR produces the dumps from a
prepared server (repack or Docker).
- The game data stays where the person has it (dataDir in docker.json, mounted
read-only), checked at install time.
- ensure_main_configs creates worldserver.conf / authserver.conf from their
.dist templates when missing, at install and at every start, never overwriting.
- Fix (affects the backend merged in 0.6.0): the database container's health check
is now a ping over TCP. On a new volume the image first runs a temporary server
that answers on its socket but takes no network connection, so the container was
healthy about four seconds (10 s against 14 s measured) before TCP worked.
- docs/ARCHITECTURE.md: D13 (installation, package contract) and D14 (how Windows
and Linux code are kept apart).
Tested: 12 new tests (folder rules, settings, package checks, bulk ledger SQL,
failure cleanup with an in-memory docker), and real runs of the whole chain
through examples/docker_install: baseline dumps exported from a prepared
server, package signed with a throwaway key, installed in 171 s, started by the
Manager (database healthy, world ready in 8 s, auth up), console reached with the
account the installer created, 1630 migrations recorded as applied.
Db runs mysql, mysqldump and mysqladmin inside the database container with
docker exec -i when the server folder is a Docker installation, connecting over
TCP on the container's loopback like the repack's commands do on the host. The
password still travels only in MYSQL_PWD. Every caller keeps using Db unchanged
(accounts, backups, population, migrations, the RA service account), and the
host needs no MySQL client. The repack path is untouched: one line before its
tools are looked up. A stopped container or a missing one is reported as a
database that is not running.
Tested: 4 new tests (commands built for the container, no password on a command
line, repack unchanged, error classification), and a real run against the
Docker folder: SQL queries, a quick backup (156 characters tables), restore with
the previous database kept, a damaged backup refused, the RA service account
created by SQL, the world server console reached through its published
loopback port, an account created through it and listed by the Manager.
A server folder with Settings/docker.json is a Docker installation: MySQL, the
auth server and the world server run in containers controlled through the
docker command line. Every other folder is a repack and goes through the
unchanged Windows code. driver::run, process::observe and layout::scan check
for the marker first and hand over to coa_core::docker.
- start: network, runtime image (libraries only, binaries are mounted from
Core/), database healthy, world listening, then auth. A container that stops
while starting reports the cause found in its log (DatabaseNotRunning,
PortInUse, ...). New error code DockerUnavailable (docker missing, stopped,
or not usable by this user).
- stop: world (180 s to save), auth, database; exit code 0 observed.
- observe: container state, health and port readiness mapped to the existing
ServiceState. Readiness is a connection that stays open, because Docker's
proxy accepts connections before the server inside listens.
- passwords go by environment, never on a command line; the remote console is
published on 127.0.0.1 only; the server's own database updater is turned off
(it needs a mysql client the image does not have and stops the server).
Tested: 18 new tests with an in-memory Docker, and a real run through
examples/drive: database, world (ready in 11 s) and auth started from a
package-shaped folder, stopped with exit code 0 and restarted.
Not included: installation, database setup, backups and SQL through the
container, updates, firewall/exposure, the client under Wine/Proton.
PLAY turns into UPDATE CLIENT when a tracked client is outdated; with no client linked
it offers choosing an existing folder or downloading from the community launcher servers
(resumable, hash-verified, free-space checked, progress and stop). Files the player changed
are kept on request or moved aside, never silently replaced. Existing clients can be adopted
from Settings. Fresh downloads get a realmlist for each installed locale.
Fixes zero-length files in the downloader (found by the live probe).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>