#!/usr/bin/env bash # Prepare a host for Hnefatafl. 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 'tafl.kestrelsnest.social, hnefatafl..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 }" apt-get update -q apt-get install -qy curl rsync # 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 # 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 hnefatafl &>/dev/null; then if getent group hnefatafl >/dev/null; then echo "a system group is already called hnefatafl; pick another service user name" >&2 exit 1 fi useradd -r -m -d /opt/hnefatafl-home hnefatafl fi mkdir -p /opt/hnefatafl/build /opt/hnefatafl/app /var/lib/hnefatafl/rooms /var/log/hnefatafl chown -R root:caddy /opt/hnefatafl/build chmod -R g+rX /opt/hnefatafl/build chown -R hnefatafl:hnefatafl /var/lib/hnefatafl sed "s|__HOST__|$HOST|" "$(dirname "$0")/Caddyfile.tmpl" > /etc/caddy/sites/hnefatafl.caddy caddy validate --config /etc/caddy/Caddyfile # 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 ufw allow 80/tcp ufw allow 443/tcp ufw --force enable echo "host ready for hnefatafl: now run deploy/deploy.sh from your machine"