Waving Hands moves to the shared hall host

The kit's shared setup, its own Caddy site file and access log (the
visitors, rollup and pulse read it), the gate taking a SITE override,
and the host's address everywhere. The old droplet forwards to hall
until the A record moves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG
This commit is contained in:
Eric Wagoner
2026-09-25 17:04:35 -04:00
co-authored by Claude Opus 5.5
parent e1833e4e3c
commit f0d06db108
12 changed files with 142 additions and 133 deletions
+58 -23
View File
@@ -1,34 +1,69 @@
#!/usr/bin/env bash
# One-time droplet setup. Copy this script and Caddyfile.tmpl to the droplet
# and run ON the droplet as root:
# bash setup-droplet.sh 'hands.kestrelsnest.social, waving-hands.<droplet-ip>.sslip.io'
# The argument is the Caddy site address line: one name, or several
# separated by commas. Every name must already resolve to this droplet.
# Waving Hands is a static site: Caddy serves the built files and terminates
# TLS. There is no application process to install or supervise.
# Prepare a host for Waving Hands. The host may be shared with other games of
# Kestrel's Hall: each keeps its own Caddy site file in /etc/caddy/sites, its
# own port, service user, data directory and access log, and this script
# touches nothing that belongs to another game. Copy it and Caddyfile.tmpl
# to the host and run ON it as root; safe to run again.
# bash setup-droplet.sh 'hands.kestrelsnest.social, waving-hands.<host-ip>.sslip.io'
# The argument is this game's Caddy site address line: one name, or several
# separated by commas. Every name must already resolve to this host.
set -euo pipefail
HOST="${1:?usage: setup-droplet.sh <hostname>}"
HOST="${1:?usage: setup-droplet.sh <site address line>}"
apt-get update -q
apt-get install -qy curl rsync
# Caddy (auto-HTTPS)
apt-get install -qy debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
| gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
| tee /etc/apt/sources.list.d/caddy-stable.list
apt-get update -q && apt-get install -qy caddy
# Caddy (auto-HTTPS), once per host.
if ! command -v caddy >/dev/null; then
apt-get install -qy debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
| gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
| tee /etc/apt/sources.list.d/caddy-stable.list
apt-get update -q && apt-get install -qy caddy
fi
# Site directory, readable by Caddy.
mkdir -p /opt/waving-hands/build
chown -R root:caddy /opt/waving-hands
chmod -R g+rX /opt/waving-hands
# Node 22, once per host; every game runs its server on it.
if ! command -v node >/dev/null || [[ "$(node -v)" != v22* ]]; then
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt-get install -qy nodejs
fi
# The host's Caddyfile only gathers the games' site files. A Caddyfile that
# is neither Caddy's stock one nor this is a single-game host from before the
# shared layout: stop rather than overwrite it.
ROOT_CADDY='# Kestrel'"'"'s Hall: every game on this host brings its own site file.
import sites/*.caddy'
mkdir -p /etc/caddy/sites
if ! grep -q '^import sites/\*.caddy' /etc/caddy/Caddyfile 2>/dev/null; then
if [ -s /etc/caddy/Caddyfile ] && ! grep -q 'root \* /usr/share/caddy' /etc/caddy/Caddyfile; then
echo "/etc/caddy/Caddyfile holds another site; move it into /etc/caddy/sites/ first" >&2
exit 1
fi
printf '%s\n' "$ROOT_CADDY" > /etc/caddy/Caddyfile
fi
# This game: its user, its directories, its site.
# The service user shares the slug. A slug that is already a system group
# (Ubuntu ships "dip", "games", "audio" and others) cannot also be a user:
# stop and say so, and choose another user name in this script and the unit.
if ! id -u waving-hands &>/dev/null; then
if getent group waving-hands >/dev/null; then
echo "a system group is already called waving-hands; pick another service user name" >&2
exit 1
fi
useradd -r -m -d /opt/waving-hands-home waving-hands
fi
mkdir -p /opt/waving-hands/build /opt/waving-hands/app /var/lib/waving-hands/rooms /var/log/waving-hands
chown -R root:caddy /opt/waving-hands/build
chmod -R g+rX /opt/waving-hands/build
chown -R waving-hands:waving-hands /var/lib/waving-hands
sed "s|__HOST__|$HOST|" "$(dirname "$0")/Caddyfile.tmpl" > /etc/caddy/sites/waving-hands.caddy
# Caddy: the site and the duel server's paths, from the template beside this script.
sed "s|__HOST__|$HOST|" "$(dirname "$0")/Caddyfile.tmpl" > /etc/caddy/Caddyfile
caddy validate --config /etc/caddy/Caddyfile
systemctl reload caddy
# Validation as root touches the access logs; Caddy runs as caddy and must own them.
chown -R caddy:caddy /var/lib/caddy
systemctl reload-or-restart caddy
# Firewall: ssh + web only.
ufw allow OpenSSH
@@ -36,4 +71,4 @@ ufw allow 80/tcp
ufw allow 443/tcp
ufw --force enable
echo "droplet ready: now run deploy/deploy.sh <ip> from your machine"
echo "host ready for waving-hands: now run deploy/deploy.sh <ip> from your machine"