New deployments/ergo/: the Ergo IRC server behind Caddy for Let's Encrypt TLS
and the IRC-over-WebSocket endpoint. Docker rather than a native OpenRC/systemd
service, because Alpine's apk ergo trails upstream (3.24 ships 2.18.0 against a
2.19.1 security release) and Debian/Alma package it at all -- so native would
mean three install paths plus a per-distro ACME client.
Both containers run with network_mode: host. IRC bans, throttling and cloaking
key on the client's address, and Docker's userland proxy would hide every IPv6
client behind the bridge gateway; host mode also makes the repo's INPUT firewall
genuinely govern 80/443/6697. Caddy reaches Ergo over loopback, which is what
lets Ergo honour X-Forwarded-For (proxy-allowed-from defaults to localhost) and
mark web sessions secure.
- deploy.sh generates ircd.yaml ONCE from the pulled image's own default.yaml
(version-matched), rewriting the listeners/websockets blocks wholesale rather
than patching lines, then asserts hard post-conditions and validates with
`ergo run --smoke` in a throwaway container before anything starts.
- update.sh: pinned vX.Y.Z tags, GHSA + "### Security" release-note policies,
pre-flight against the new image, user NOTICE + grace, stop-consistent DB
snapshot, health check (IRC-level, not a bare TCP connect) and rollback that
restores the DB only when the schema actually moved. Compatibility-break
releases are held for review. certsync copies Caddy's cert pairwise-atomically
and verifies the fingerprint served on 6697 after the rehash.
- ergoctl: status/users/logs, validated edit+rehash, oper add/passwd/rm,
moderation, backup/restore, cert and update passthrough. Talks IRC to the
loopback listener over bash /dev/tcp and strips control characters from
replies.
- Ergo runs as a non-root system user, read-only rootfs, all caps dropped;
Caddy keeps only NET_BIND_SERVICE, with admin API and HTTP/3 off.
Reviewed adversarially across six lenses; 20 confirmed findings fixed, notably
a dead SIGHUP fallback (`rc=$?` after an `if` is always 0), several `set -e`
aborts from non-total pipelines, a release-list cache that only ever populated
in a subshell, and re-runs that used shell defaults instead of the deployed
.env. Verified locally: bash -n, LF endings, the ircd.yaml render against the
real 2.19.1 template in both PLAINTEXT modes, the yaml/oper/version/env helpers,
and the IRC client against a fake server (registration, oper, rehash success and
400-failure, control-character stripping, server-down paths). Not yet exercised
on a Docker host: the containers themselves, ACME issuance and cert sync.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>