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>
43 lines
1.6 KiB
YAML
43 lines
1.6 KiB
YAML
#cloud-config
|
|
#
|
|
# Ergo (IRC server) -- harden SSH, then deploy, on a fresh host.
|
|
#
|
|
# Fill in REPO_URL and the values in the runcmd block, then paste this as the
|
|
# instance user-data. DNS for ERGO_DOMAIN must point at this host and ports
|
|
# 80/443 must be reachable before boot, or the Let's Encrypt cert request fails
|
|
# (Ergo then keeps serving a self-signed cert until certsync catches up).
|
|
# 6697/tcp (IRC over TLS) is opened on the host firewall as well.
|
|
|
|
packages:
|
|
- git
|
|
|
|
runcmd:
|
|
- hostnamectl set-hostname irc || true
|
|
- |
|
|
set -e
|
|
REPO_URL=https://git.anomalous.dev/57_Wolve/automations.git
|
|
REPO_BRANCH=main
|
|
HARDEN_SSH=1 # harden SSH on this fresh VM (set 0 to skip)
|
|
SSH_PORT=22
|
|
ALLOWED_IP= # optional: whitelist your client IP in sshguard
|
|
git clone --depth 1 --branch "$REPO_BRANCH" "$REPO_URL" /opt/automations
|
|
cd /opt/automations
|
|
|
|
# Harden SSH first (PQ KEX, key-only auth, sshguard + deny-by-default
|
|
# firewall). Because the Ergo stack uses host networking, that firewall
|
|
# genuinely governs 80/443/6697 -- deploy.sh registers them with it.
|
|
if [ "$HARDEN_SSH" = 1 ]; then
|
|
SSH_PORT="$SSH_PORT" ALLOWED_IP="$ALLOWED_IP" SKIP_PROMPTS=1 FORCE=1 \
|
|
bash scripts/harden-ssh.sh
|
|
fi
|
|
|
|
# Deploy Ergo. The admin oper password is generated and stored in
|
|
# /srv/ergo/secrets/admin.pass (also printed to this log once).
|
|
ERGO_DOMAIN=irc.example.com \
|
|
ACME_EMAIL=admin@example.com \
|
|
NETWORK_NAME=ExampleNet \
|
|
PLAINTEXT=0 \
|
|
UPDATE_POLICY=latest \
|
|
SKIP_PROMPTS=1 \
|
|
bash deployments/ergo/deploy.sh
|