v0.13.0 web and terminal client enhance, replay api, linux server deploy, doc and dependency update
test / test (push) Canceled after 0s

This commit is contained in:
lixen committed 2026-09-28 22:35:52 -04:00
1 parent 52ac0fe31a
commit f1ac4cbbe7
71 files changed
+7677 -537

No files matched your search

+27 -7
View File
@@ -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.
-23
View File
@@ -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
+1 -1
View File
@@ -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
+15 -7
View File
@@ -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' \
+17
View File
@@ -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
+12
View File
@@ -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
+61
View File
@@ -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
+262
View File
@@ -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;
}
+28
View File
@@ -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