v0.13.0 web and terminal client enhance, replay api, linux server deploy, doc and dependency update
test / test (push) Canceled after 0s
test / test (push) Canceled after 0s
This commit is contained in:
1 parent
52ac0fe31a
commit
f1ac4cbbe7
71 files changed
+7677
-537
No files matched your search
+27
-7
@@ -1,7 +1,12 @@
|
||||
# Deployment Scripts
|
||||
|
||||
Run in this order; each script's header documents its inputs. The full guide is
|
||||
[doc/deployment.md](../doc/deployment.md).
|
||||
Each script's header documents its inputs. Day-to-day database work (psql,
|
||||
accounts, deleting games, starting fresh) is in
|
||||
[doc/database.md](../doc/database.md).
|
||||
|
||||
## FreeBSD jail
|
||||
|
||||
Full guide: [doc/deployment.md](../doc/deployment.md). Run in this order:
|
||||
|
||||
| Order | Where | Step | Purpose |
|
||||
|---|---|---|---|
|
||||
@@ -9,13 +14,28 @@ Run in this order; each script's header documents its inputs. The full guide is
|
||||
| 2 | Jail, once | `pkg install postgresql18-server postgresql18-client stockfish` | Packages |
|
||||
| 3 | Build machine | `make server-freebsd` | Static `bin/chess-server-freebsd-amd64` |
|
||||
| 4 | Jail (root) | `freebsd/setup-jail.sh` | PostgreSQL setup, database, `chessd` service, optional log rotation and backups; rerun to upgrade |
|
||||
| 5 | Bastille host | `freebsd/nginx-chess.conf` | nginx locations for `/chess/api/` and `/chess/health` |
|
||||
| 5 | Bastille host | `nginx-chess.conf` | nginx locations for `/chess/api/`, `/chess/health`, and the `/chess` short link |
|
||||
| 6 | Jail, once | `chess-server db user add -username <name>` | First account (see the guide) |
|
||||
|
||||
Supporting files, installed by `setup-jail.sh`:
|
||||
## Linux with systemd
|
||||
|
||||
Full guide: [doc/deployment-linux.md](../doc/deployment-linux.md) (Debian,
|
||||
Ubuntu, Arch; PostgreSQL 17+ already running).
|
||||
|
||||
| Order | Where | Step | Purpose |
|
||||
|---|---|---|---|
|
||||
| 1 | Host | `make server` | Static `bin/chess-server` |
|
||||
| 2 | Host (root) | `CHESS_BINARY=bin/chess-server linux/setup.sh` | Account, database, `chessd` systemd service, key, optional backup timer; rerun to upgrade |
|
||||
| 3 | Host (root) | `chess-db user add -username <name>` | First account |
|
||||
| 4 | nginx | `nginx-chess.conf` with `127.0.0.1:8080` | Optional reverse proxy |
|
||||
|
||||
## Files
|
||||
|
||||
- `postgresql/setup.sql` — role, database, and schema (owner or split mode)
|
||||
- `postgresql/chess-backup.sh` — nightly `pg_dump` with 14-day retention
|
||||
- `nginx-chess.conf` — nginx locations, with placeholders
|
||||
- `freebsd/rc.d/chessd` — `daemon(8)` service script
|
||||
- `freebsd/chess-backup.sh` — nightly `pg_dump` with 14-day retention
|
||||
- `linux/chessd.service` — sandboxed systemd unit; `linux/chess-backup.{service,timer}`
|
||||
|
||||
Keep deployment-specific values (addresses, host names) in `rc.conf` and the
|
||||
host nginx configuration, not in this repository.
|
||||
Keep deployment-specific values (addresses, host names) in `rc.conf`,
|
||||
`/etc/chessd/chessd.env`, and the nginx configuration, not in this repository.
|
||||
@@ -1,23 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Nightly logical backup of the chess database. setup-jail.sh installs this as
|
||||
# /usr/local/sbin/chess-backup and schedules it as the postgres user through
|
||||
# /usr/local/etc/cron.d/chess-backup.
|
||||
#
|
||||
# CHESS_BACKUP_DIR destination (default: /var/db/postgres/backups)
|
||||
# CHESS_BACKUP_KEEP days of dumps to keep (default: 14)
|
||||
#
|
||||
# Restore into a freshly provisioned database with:
|
||||
# su -m postgres -c 'pg_restore --no-owner --role=chess -d chess <dump>'
|
||||
# (use --role=chess_owner for the split-privilege setup).
|
||||
set -eu
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
|
||||
|
||||
dir=${CHESS_BACKUP_DIR:-/var/db/postgres/backups}
|
||||
keep=${CHESS_BACKUP_KEEP:-14}
|
||||
umask 077
|
||||
mkdir -p "$dir"
|
||||
|
||||
target="$dir/chess-$(date -u +%Y%m%dT%H%M%SZ).dump"
|
||||
pg_dump --format=custom --dbname=chess --file="$target.partial"
|
||||
mv "$target.partial" "$target"
|
||||
find "$dir" -name 'chess-*.dump' -type f -mtime "+$keep" -delete
|
||||
@@ -9,7 +9,7 @@
|
||||
# restart stops every service in the jail, including a running chess-server.
|
||||
#
|
||||
# After setup-jail.sh has run inside the jail, add the location block from
|
||||
# deploy/freebsd/nginx-chess.conf to the host nginx configuration, then
|
||||
# deploy/nginx-chess.conf to the host nginx configuration, then
|
||||
# nginx -t && service nginx reload
|
||||
set -eu
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
|
||||
|
||||
@@ -78,7 +78,7 @@ yes_no() {
|
||||
[ "$(id -u)" -eq 0 ] || die "run as root"
|
||||
[ "$(uname -s)" = FreeBSD ] || die "this script targets FreeBSD"
|
||||
[ -f "$CHESS_BINARY" ] || die "CHESS_BINARY not found: $CHESS_BINARY"
|
||||
for f in "$repo/deploy/postgresql/setup.sql" "$here/rc.d/chessd" "$here/chess-backup.sh"; do
|
||||
for f in "$repo/deploy/postgresql/setup.sql" "$here/rc.d/chessd" "$repo/deploy/postgresql/chess-backup.sh"; do
|
||||
[ -f "$f" ] || die "missing $f; run from a complete repository copy"
|
||||
done
|
||||
yes_no SPLIT_PRIVILEGES "$SPLIT_PRIVILEGES"
|
||||
@@ -182,12 +182,20 @@ fi
|
||||
|
||||
bindir=$(dirname "$bin")
|
||||
[ -d "$bindir" ] || install -d -o root -g wheel -m 0755 "$bindir"
|
||||
if [ -f "$bin" ] && ! cmp -s "$CHESS_BINARY" "$bin"; then
|
||||
log "keeping the previous binary as $bin.prev"
|
||||
cp -p "$bin" "$bin.prev"
|
||||
fi
|
||||
# Root-owned: the service account cannot replace its own executable file.
|
||||
install -o root -g wheel -m 0555 "$CHESS_BINARY" "$bin"
|
||||
if [ -f "$bin" ] && cmp -s "$CHESS_BINARY" "$bin"; then
|
||||
# Same content, possibly the installed file itself (a rerun with
|
||||
# CHESS_BINARY pointing at it): install(1) refuses to copy a file onto
|
||||
# itself, so only normalize ownership and mode.
|
||||
chown root:wheel "$bin"
|
||||
chmod 0555 "$bin"
|
||||
else
|
||||
if [ -f "$bin" ]; then
|
||||
log "keeping the previous binary as $bin.prev"
|
||||
cp -p "$bin" "$bin.prev"
|
||||
fi
|
||||
install -o root -g wheel -m 0555 "$CHESS_BINARY" "$bin"
|
||||
fi
|
||||
|
||||
[ -d "$RC_DIR" ] || install -d "$RC_DIR"
|
||||
if [ -f "$RC_DIR/chessd" ] && ! cmp -s "$here/rc.d/chessd" "$RC_DIR/chessd"; then
|
||||
@@ -247,7 +255,7 @@ fi
|
||||
if [ "$ENABLE_BACKUP" = yes ]; then
|
||||
# Nightly pg_dump at 03:30 as postgres, keeping 14 days.
|
||||
[ -d "$SBIN_DIR" ] || install -d "$SBIN_DIR"
|
||||
install -o root -g wheel -m 0555 "$here/chess-backup.sh" "$SBIN_DIR/chess-backup"
|
||||
install -o root -g wheel -m 0555 "$repo/deploy/postgresql/chess-backup.sh" "$SBIN_DIR/chess-backup"
|
||||
[ -d "$BACKUP_DIR" ] || install -d -o postgres -g postgres -m 0700 "$BACKUP_DIR"
|
||||
[ -d "$CRON_DIR" ] || install -d "$CRON_DIR"
|
||||
printf '%s\n' \
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# Nightly pg_dump of the chess database; started by chess-backup.timer.
|
||||
# Installed by deploy/linux/setup.sh when ENABLE_BACKUP=yes. Dumps go to
|
||||
# backups/ in the postgres home (/var/lib/postgresql on Debian and Ubuntu,
|
||||
# /var/lib/postgres on Arch) and are kept for 14 days.
|
||||
|
||||
[Unit]
|
||||
Description=Back up the chess database
|
||||
After=postgresql.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
User=postgres
|
||||
Group=postgres
|
||||
ExecStart=/usr/local/sbin/chess-backup
|
||||
NoNewPrivileges=yes
|
||||
PrivateTmp=yes
|
||||
ProtectSystem=full
|
||||
@@ -0,0 +1,12 @@
|
||||
# Runs chess-backup.service nightly; a missed run (machine off) runs at boot.
|
||||
|
||||
[Unit]
|
||||
Description=Nightly chess database backup
|
||||
|
||||
[Timer]
|
||||
OnCalendar=*-*-* 03:30:00
|
||||
RandomizedDelaySec=15min
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
@@ -0,0 +1,61 @@
|
||||
# chess-server as a systemd service. Installed by deploy/linux/setup.sh as
|
||||
# /etc/systemd/system/chessd.service; settings live in /etc/chessd/chessd.env.
|
||||
# Local changes belong in a drop-in (systemctl edit chessd), which setup.sh
|
||||
# never overwrites.
|
||||
|
||||
[Unit]
|
||||
Description=Chess API server
|
||||
Documentation=https://github.com/lixenwraith/chess/blob/main/doc/deployment-linux.md
|
||||
Wants=network-online.target postgresql.service
|
||||
After=network-online.target postgresql.service
|
||||
# PostgreSQL may still be starting at boot; keep retrying instead of giving up.
|
||||
StartLimitIntervalSec=0
|
||||
|
||||
[Service]
|
||||
Type=exec
|
||||
User=chess
|
||||
Group=chess
|
||||
EnvironmentFile=/etc/chessd/chessd.env
|
||||
# Stockfish is /usr/games/stockfish on Debian and Ubuntu, /usr/bin elsewhere.
|
||||
Environment=PATH=/usr/local/bin:/usr/bin:/bin:/usr/games
|
||||
# ${VAR} stays one argument (the DSN has spaces); $CHESSD_FLAGS splits into
|
||||
# words and expands to nothing when empty.
|
||||
ExecStart=/usr/local/bin/chess-server \
|
||||
-api-host ${CHESSD_HOST} -api-port ${CHESSD_PORT} \
|
||||
-dsn ${CHESSD_DSN} -jwt-secret-file ${CHESSD_JWT_KEY} \
|
||||
-trusted-proxies ${CHESSD_TRUSTED_PROXIES} \
|
||||
$CHESSD_FLAGS
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
# /var/lib/chessd holds the JWT key; the service can read and write nothing
|
||||
# else. PostgreSQL is reached over its Unix socket under /run.
|
||||
StateDirectory=chessd
|
||||
StateDirectoryMode=0700
|
||||
UMask=0077
|
||||
NoNewPrivileges=yes
|
||||
ProtectSystem=strict
|
||||
ProtectHome=yes
|
||||
PrivateTmp=yes
|
||||
PrivateDevices=yes
|
||||
ProtectKernelTunables=yes
|
||||
ProtectKernelModules=yes
|
||||
ProtectKernelLogs=yes
|
||||
ProtectControlGroups=yes
|
||||
ProtectClock=yes
|
||||
ProtectHostname=yes
|
||||
ProtectProc=invisible
|
||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
||||
RestrictNamespaces=yes
|
||||
RestrictRealtime=yes
|
||||
RestrictSUIDSGID=yes
|
||||
LockPersonality=yes
|
||||
MemoryDenyWriteExecute=yes
|
||||
SystemCallArchitectures=native
|
||||
SystemCallFilter=@system-service
|
||||
SystemCallFilter=~@privileged
|
||||
CapabilityBoundingSet=
|
||||
AmbientCapabilities=
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Executable
+262
@@ -0,0 +1,262 @@
|
||||
#!/usr/bin/env bash
|
||||
# Install or upgrade chess-server as the systemd service `chessd` on a Linux
|
||||
# host (Debian, Ubuntu, Arch, or another systemd distribution) that already
|
||||
# runs PostgreSQL 17 or later. Run as root from a checkout:
|
||||
#
|
||||
# sudo CHESS_BINARY=bin/chess-server deploy/linux/setup.sh
|
||||
#
|
||||
# Prerequisites: PostgreSQL 17+ running and reachable by the postgres account
|
||||
# over its Unix socket; stockfish; the chess-server binary (`make server`).
|
||||
#
|
||||
# Inputs (environment):
|
||||
# CHESS_BINARY required: chess-server binary to install
|
||||
# TRUSTED_PROXIES reverse proxy address(es) whose X-Real-IP is trusted,
|
||||
# e.g. 127.0.0.1 for nginx on this host; stored in
|
||||
# chessd.env (kept from the existing file when unset)
|
||||
# CHESSD_HOST listen address for a first install (default 127.0.0.1)
|
||||
# CHESSD_PORT listen port for a first install (default 8080)
|
||||
# SPLIT_PRIVILEGES yes|no (default no); see deploy/postgresql/setup.sql
|
||||
# ENABLE_BACKUP yes|no (default no): nightly pg_dump systemd timer
|
||||
# PG_HBA yes|no (default no): if the chess role cannot connect,
|
||||
# add `local chess chess peer` to pg_hba.conf and reload
|
||||
#
|
||||
# What it installs:
|
||||
# account chess (system, no login shell, home /var/lib/chessd)
|
||||
# /usr/local/bin/chess-server (previous copy kept as .prev)
|
||||
# /usr/local/sbin/chess-db runs `chess-server db ...` as chess
|
||||
# /etc/chessd/chessd.env settings, written on first install only
|
||||
# /var/lib/chessd/jwt.key JWT signing key, generated once
|
||||
# /etc/systemd/system/chessd.service (+ chess-backup.{service,timer})
|
||||
#
|
||||
# Steps (idempotent; rerun to upgrade):
|
||||
# 1. checks: root, systemd, PostgreSQL version and socket, stockfish
|
||||
# 2. role, database, and schema from deploy/postgresql/setup.sql when
|
||||
# neither exists; the chess role must connect over the socket
|
||||
# 3. stop chessd; install files; key; schema migration
|
||||
# 4. enable and start chessd; check /health
|
||||
set -euo pipefail
|
||||
umask 022
|
||||
|
||||
here=$(cd "$(dirname "$0")" && pwd)
|
||||
repo=$(cd "$here/../.." && pwd)
|
||||
|
||||
: "${CHESS_BINARY:?set CHESS_BINARY to the chess-server binary to install}"
|
||||
TRUSTED_PROXIES=${TRUSTED_PROXIES-__keep__}
|
||||
CHESSD_HOST=${CHESSD_HOST:-127.0.0.1}
|
||||
CHESSD_PORT=${CHESSD_PORT:-8080}
|
||||
SPLIT_PRIVILEGES=${SPLIT_PRIVILEGES:-no}
|
||||
ENABLE_BACKUP=${ENABLE_BACKUP:-no}
|
||||
PG_HBA=${PG_HBA:-no}
|
||||
# System locations and the service manager; overridable only to test the
|
||||
# script.
|
||||
BIN_DIR=${BIN_DIR:-/usr/local/bin}
|
||||
SBIN_DIR=${SBIN_DIR:-/usr/local/sbin}
|
||||
CONF_DIR=${CONF_DIR:-/etc/chessd}
|
||||
STATE_DIR=${STATE_DIR:-/var/lib/chessd}
|
||||
UNIT_DIR=${UNIT_DIR:-/etc/systemd/system}
|
||||
SYSTEMCTL=${SYSTEMCTL:-systemctl}
|
||||
|
||||
user=chess
|
||||
bin="$BIN_DIR/chess-server"
|
||||
env_file="$CONF_DIR/chessd.env"
|
||||
key="$STATE_DIR/jwt.key"
|
||||
|
||||
log() { printf '==> %s\n' "$*"; }
|
||||
warn() { printf 'setup: warning: %s\n' "$*" >&2; }
|
||||
die() { printf 'setup: %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
# pg runs psql as the postgres account over the default socket (or $PGHOST).
|
||||
pg() { runuser -u postgres -- psql -X -w -A -t -q -v ON_ERROR_STOP=1 "$@"; }
|
||||
|
||||
# --- 1. checks ---------------------------------------------------------------
|
||||
[ "$(id -u)" -eq 0 ] || die "run as root"
|
||||
for setting in SPLIT_PRIVILEGES ENABLE_BACKUP PG_HBA; do
|
||||
case "${!setting}" in
|
||||
yes | no) ;;
|
||||
*) die "$setting must be yes or no" ;;
|
||||
esac
|
||||
done
|
||||
if [ "$SYSTEMCTL" = systemctl ] && [ ! -d /run/systemd/system ]; then
|
||||
die "systemd is not running; see doc/deployment-linux.md to run chess-server another way"
|
||||
fi
|
||||
for tool in runuser psql useradd; do
|
||||
command -v "$tool" >/dev/null || die "$tool not found"
|
||||
done
|
||||
[ -f "$CHESS_BINARY" ] || die "CHESS_BINARY not found: $CHESS_BINARY"
|
||||
# A binary for another OS or architecture fails here rather than at start.
|
||||
case "$("$CHESS_BINARY" db 2>&1 || true)" in
|
||||
*"subcommand required"*) ;;
|
||||
*) die "$CHESS_BINARY does not run on this host (wrong OS or architecture?)" ;;
|
||||
esac
|
||||
for f in "$repo/deploy/postgresql/setup.sql" "$here/chessd.service" \
|
||||
"$here/chess-backup.service" "$here/chess-backup.timer" "$repo/deploy/postgresql/chess-backup.sh"; do
|
||||
[ -f "$f" ] || die "missing $f; run from a complete checkout"
|
||||
done
|
||||
if ! command -v stockfish >/dev/null && [ ! -x /usr/games/stockfish ]; then
|
||||
warn "stockfish not found: install it (Debian/Ubuntu: apt install stockfish; Arch: pacman -S stockfish)"
|
||||
fi
|
||||
|
||||
version=$(pg -d postgres -c 'SHOW server_version_num') ||
|
||||
die "cannot reach PostgreSQL as postgres over its Unix socket: start it (systemctl start postgresql; on Arch run initdb first, see doc/deployment-linux.md) or set PGHOST"
|
||||
[ "$version" -ge 170000 ] || die "PostgreSQL 17 or later required (found $version)"
|
||||
socket=${PGHOST:-$(pg -d postgres -c 'SHOW unix_socket_directories' | cut -d, -f1 | tr -d ' ')}
|
||||
case "$socket" in
|
||||
/*) ;;
|
||||
*) die "no usable Unix socket directory ($socket); set PGHOST to it" ;;
|
||||
esac
|
||||
dsn="host=$socket dbname=chess"
|
||||
log "PostgreSQL $version, socket $socket"
|
||||
|
||||
# --- 2. account, role, database ----------------------------------------------
|
||||
if ! id "$user" >/dev/null 2>&1; then
|
||||
nologin=$(command -v nologin || echo /usr/sbin/nologin)
|
||||
log "creating system account $user"
|
||||
useradd --system --user-group --home-dir "$STATE_DIR" --no-create-home \
|
||||
--shell "$nologin" --comment "chess-server" "$user"
|
||||
fi
|
||||
group=$(id -gn "$user")
|
||||
|
||||
role=$(pg -d postgres -c "SELECT 1 FROM pg_roles WHERE rolname = 'chess'")
|
||||
database=$(pg -d postgres -c "SELECT 1 FROM pg_database WHERE datname = 'chess'")
|
||||
case "$role$database" in
|
||||
11) log "role and database chess exist" ;;
|
||||
"")
|
||||
log "creating role chess, database chess, and schema chess (split privileges: $SPLIT_PRIVILEGES)"
|
||||
split=false
|
||||
[ "$SPLIT_PRIVILEGES" = yes ] && split=true
|
||||
# Fed on stdin: postgres may not be able to read the checkout.
|
||||
pg -d postgres -v split="$split" -f - <"$repo/deploy/postgresql/setup.sql"
|
||||
;;
|
||||
*) die "only one of role chess and database chess exists; drop it or create the other (doc/database.md)" ;;
|
||||
esac
|
||||
|
||||
chess_can_connect() {
|
||||
runuser -u "$user" -- psql -X -w -A -t -q -h "$socket" -d chess -c 'SELECT current_user' >/dev/null 2>&1
|
||||
}
|
||||
if ! chess_can_connect; then
|
||||
hba=$(pg -d postgres -c 'SHOW hba_file')
|
||||
if [ "$PG_HBA" != yes ]; then
|
||||
die "the chess account cannot connect to database chess over $socket. Add this line to
|
||||
$hba above the other 'local' lines, then reload PostgreSQL (or rerun with PG_HBA=yes):
|
||||
local chess chess peer"
|
||||
fi
|
||||
saved="$hba.chessd-$(date -u +%Y%m%dT%H%M%SZ)"
|
||||
cp -p "$hba" "$saved"
|
||||
awk 'BEGIN { done = 0 }
|
||||
!done && /^[[:space:]]*local[[:space:]]/ { print "local chess chess peer"; done = 1 }
|
||||
{ print }
|
||||
END { if (!done) print "local chess chess peer" }' "$saved" >"$hba"
|
||||
pg -d postgres -c 'SELECT pg_reload_conf()' >/dev/null
|
||||
log "pg_hba.conf: added local chess chess peer (previous copy $saved)"
|
||||
chess_can_connect || die "the chess account still cannot connect; check $hba"
|
||||
fi
|
||||
|
||||
# --- 3. files ----------------------------------------------------------------
|
||||
if "$SYSTEMCTL" is-active --quiet chessd 2>/dev/null; then
|
||||
log "stopping chessd"
|
||||
"$SYSTEMCTL" stop chessd
|
||||
fi
|
||||
|
||||
install -d -m 0755 "$BIN_DIR" "$SBIN_DIR"
|
||||
if [ -f "$bin" ] && cmp -s "$CHESS_BINARY" "$bin"; then
|
||||
chown root:root "$bin"
|
||||
chmod 0755 "$bin"
|
||||
else
|
||||
if [ -f "$bin" ]; then
|
||||
log "keeping the previous binary as $bin.prev"
|
||||
cp -p "$bin" "$bin.prev"
|
||||
fi
|
||||
install -o root -g root -m 0755 "$CHESS_BINARY" "$bin"
|
||||
fi
|
||||
|
||||
cat >"$SBIN_DIR/chess-db.new" <<EOF
|
||||
#!/bin/sh
|
||||
# Runs \`chess-server db ...\` as the chess account against the chess database,
|
||||
# e.g. chess-db user add -username alice. Installed by deploy/linux/setup.sh.
|
||||
set -a
|
||||
. "$env_file"
|
||||
exec runuser -u $user -- env CHESS_DSN="\$CHESSD_DSN" "$bin" db "\$@"
|
||||
EOF
|
||||
chmod 0755 "$SBIN_DIR/chess-db.new"
|
||||
mv "$SBIN_DIR/chess-db.new" "$SBIN_DIR/chess-db"
|
||||
|
||||
install -d -o root -g "$group" -m 0750 "$CONF_DIR"
|
||||
if [ ! -f "$env_file" ]; then
|
||||
proxies=$TRUSTED_PROXIES
|
||||
[ "$proxies" = __keep__ ] && proxies=
|
||||
log "writing $env_file"
|
||||
cat >"$env_file" <<EOF
|
||||
# chessd settings, read by chessd.service; restart chessd after a change.
|
||||
CHESSD_HOST=$CHESSD_HOST
|
||||
CHESSD_PORT=$CHESSD_PORT
|
||||
# PostgreSQL over the Unix socket as the OS account chess (peer or trust).
|
||||
CHESSD_DSN="$dsn"
|
||||
CHESSD_JWT_KEY=$key
|
||||
# Reverse proxy address(es), comma-separated, whose X-Real-IP is trusted.
|
||||
CHESSD_TRUSTED_PROXIES=$proxies
|
||||
# Extra server flags, e.g. -max-users 500 -db-cleanup report
|
||||
CHESSD_FLAGS=
|
||||
EOF
|
||||
elif [ "$TRUSTED_PROXIES" != __keep__ ]; then
|
||||
sed -i "s|^CHESSD_TRUSTED_PROXIES=.*|CHESSD_TRUSTED_PROXIES=$TRUSTED_PROXIES|" "$env_file"
|
||||
log "$env_file: CHESSD_TRUSTED_PROXIES=$TRUSTED_PROXIES"
|
||||
fi
|
||||
chown root:"$group" "$env_file"
|
||||
chmod 0640 "$env_file"
|
||||
# The settings in effect, which may differ from this run's defaults.
|
||||
# shellcheck disable=SC1090
|
||||
settings=$(set -a && . "$env_file" && printf '%s|%s|%s|%s' \
|
||||
"$CHESSD_HOST" "$CHESSD_PORT" "$CHESSD_TRUSTED_PROXIES" "$CHESSD_DSN")
|
||||
IFS='|' read -r host port proxies dsn <<<"$settings"
|
||||
[ -n "$proxies" ] || warn "no trusted proxy: behind a reverse proxy every client shares one rate-limit bucket (set TRUSTED_PROXIES)"
|
||||
|
||||
install -d -o "$user" -g "$group" -m 0700 "$STATE_DIR"
|
||||
if [ ! -f "$key" ]; then
|
||||
log "generating JWT signing key $key"
|
||||
(umask 077 && head -c 48 /dev/urandom | base64 -w0 >"$key")
|
||||
fi
|
||||
chown "$user:$group" "$key"
|
||||
chmod 0600 "$key"
|
||||
|
||||
install -o root -g root -m 0644 "$here/chessd.service" "$UNIT_DIR/chessd.service"
|
||||
if [ "$ENABLE_BACKUP" = yes ]; then
|
||||
install -o root -g root -m 0755 "$repo/deploy/postgresql/chess-backup.sh" "$SBIN_DIR/chess-backup"
|
||||
install -o root -g root -m 0644 "$here/chess-backup.service" "$UNIT_DIR/chess-backup.service"
|
||||
install -o root -g root -m 0644 "$here/chess-backup.timer" "$UNIT_DIR/chess-backup.timer"
|
||||
fi
|
||||
"$SYSTEMCTL" daemon-reload
|
||||
|
||||
log "creating or migrating the chess schema"
|
||||
if [ "$SPLIT_PRIVILEGES" = yes ]; then
|
||||
runuser -u postgres -- "$bin" db init \
|
||||
-dsn "host=$socket dbname=chess user=postgres options='-c role=chess_owner -c search_path=chess'"
|
||||
else
|
||||
runuser -u "$user" -- "$bin" db init -dsn "$dsn"
|
||||
fi
|
||||
|
||||
# --- 4. start ----------------------------------------------------------------
|
||||
if [ "$ENABLE_BACKUP" = yes ]; then
|
||||
"$SYSTEMCTL" enable --now chess-backup.timer
|
||||
log "backups: chess-backup.timer -> $(getent passwd postgres | cut -d: -f6)/backups"
|
||||
fi
|
||||
"$SYSTEMCTL" enable chessd
|
||||
"$SYSTEMCTL" start chessd
|
||||
|
||||
case "$host" in
|
||||
0.0.0.0 | "" | ::) probe=127.0.0.1 ;;
|
||||
*:*) probe="[$host]" ;;
|
||||
*) probe=$host ;;
|
||||
esac
|
||||
url="http://$probe:$port/health"
|
||||
health=
|
||||
for _ in $(seq 1 30); do
|
||||
if health=$(curl -fsS --max-time 2 "$url" 2>/dev/null); then
|
||||
break
|
||||
fi
|
||||
sleep 0.5
|
||||
done
|
||||
case "$health" in
|
||||
*'"storage":"ok"'*) log "chessd is up: $health" ;;
|
||||
*) die "chessd did not report healthy storage at $url (journalctl -u chessd): ${health:-no answer}" ;;
|
||||
esac
|
||||
log "done. Create an account with: chess-db user add -username <name>"
|
||||
@@ -1,16 +1,18 @@
|
||||
# Host nginx for chess: browsers (web and WASM clients) call
|
||||
# <origin>/chess/api/... and <origin>/chess/health, which map to the server's
|
||||
# /api/... and /health. Replace <jail-address> and <port> (chessd_port,
|
||||
# default 8080).
|
||||
# nginx for chess: browsers (web and WASM clients) call <origin>/chess/api/...
|
||||
# and <origin>/chess/health, which map to the server's /api/... and /health;
|
||||
# /chess itself redirects to the project page. Replace <server-address> and
|
||||
# <port>: the FreeBSD jail's address and chessd_port, or 127.0.0.1 and
|
||||
# CHESSD_PORT for a Linux install on the same host (default port 8080).
|
||||
#
|
||||
# chess-server keys rate limits on X-Real-IP, trusted only from the addresses
|
||||
# in chessd_trusted_proxies: the address this nginx uses to reach the jail.
|
||||
# in its trusted proxies (chessd_trusted_proxies or CHESSD_TRUSTED_PROXIES):
|
||||
# the address this nginx connects from, as the server sees it.
|
||||
# $remote_addr must be the real client: with PROXY protocol in front of nginx,
|
||||
# set real_ip_header proxy_protocol and set_real_ip_from for that hop.
|
||||
|
||||
# --- http {} context ---
|
||||
upstream chess_api {
|
||||
server <jail-address>:<port>;
|
||||
server <server-address>:<port>;
|
||||
keepalive 16;
|
||||
}
|
||||
|
||||
@@ -43,10 +45,21 @@ location = /chess/health {
|
||||
proxy_read_timeout 10s;
|
||||
}
|
||||
|
||||
# Everything else under /chess is not served by the API.
|
||||
# Short link: /chess and /chess/ redirect to the page that embeds the client
|
||||
# (adjust /projects/chess/). 302 rather than 301: browsers cache a 301
|
||||
# indefinitely, which would loop if the direction is ever reversed. A server
|
||||
# listening on a non-default port (PROXY protocol or TLS passthrough behind a
|
||||
# front end) needs `absolute_redirect off;` so the port does not leak into
|
||||
# Location. If this server block also answers for other host names, guard with
|
||||
# a host map so only the main site redirects.
|
||||
location = /chess {
|
||||
return 404;
|
||||
return 302 /projects/chess/$is_args$args;
|
||||
}
|
||||
location = /chess/ {
|
||||
return 302 /projects/chess/$is_args$args;
|
||||
}
|
||||
|
||||
# Everything else under /chess is not served by the API.
|
||||
location /chess/ {
|
||||
return 404;
|
||||
}
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
# Nightly logical backup of the chess database, run as the postgres account.
|
||||
# Installed as /usr/local/sbin/chess-backup by deploy/freebsd/setup-jail.sh
|
||||
# (scheduled through /usr/local/etc/cron.d/chess-backup) and by
|
||||
# deploy/linux/setup.sh (scheduled by the chess-backup.timer systemd unit).
|
||||
#
|
||||
# CHESS_BACKUP_DIR destination (default: backups/ in the postgres home,
|
||||
# e.g. /var/db/postgres/backups on FreeBSD)
|
||||
# CHESS_BACKUP_KEEP days of dumps to keep (default: 14)
|
||||
#
|
||||
# Restore into a freshly provisioned database as the postgres account:
|
||||
# pg_restore --no-owner --role=chess -d chess <dump>
|
||||
# (use --role=chess_owner for the split-privilege setup).
|
||||
set -eu
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
|
||||
|
||||
dir=${CHESS_BACKUP_DIR:-${HOME:?}/backups}
|
||||
keep=${CHESS_BACKUP_KEEP:-14}
|
||||
umask 077
|
||||
mkdir -p "$dir"
|
||||
|
||||
target="$dir/chess-$(date -u +%Y%m%dT%H%M%SZ).dump"
|
||||
if ! pg_dump --format=custom --dbname=chess --file="$target.partial"; then
|
||||
rm -f "$target.partial"
|
||||
exit 1
|
||||
fi
|
||||
mv "$target.partial" "$target"
|
||||
find "$dir" -name 'chess-*.dump' -type f -mtime "+$keep" -delete
|
||||
Reference in new issue
Block a user