feat(deploy): local chess.local instance for VDJ-RIG
A second, LAN-only deploy alongside the CT 690 / chess.sethpc.xyz instance. Runs on VDJ-RIG as a persistent systemd daemon, served on port 80 and reachable at http://chess.local via an mDNS alias. - blind-chess-local.service: server unit; binds port 80 as the non-root blindchess user via CAP_NET_BIND_SERVICE. - chess-mdns-alias{,.service}: publishes the chess.local mDNS name with avahi-publish -a -R (-R skips the reverse PTR, which would otherwise collide with the host's own <hostname>.local record). - install-local.sh: idempotent root-side installer (Node 22 via NodeSource, avahi-utils, blindchess user, /opt/blind-chess, units). - CLAUDE.md: documents the local instance under Operations. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
[Unit]
|
||||
Description=blind_chess server — local LAN instance (chess.local)
|
||||
Documentation=https://git.sethpc.xyz/Seth/blind_chess
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=blindchess
|
||||
Group=blindchess
|
||||
WorkingDirectory=/opt/blind-chess/server
|
||||
ExecStart=/usr/bin/node /opt/blind-chess/server/dist/server.js
|
||||
Environment=NODE_ENV=production
|
||||
Environment=PORT=80
|
||||
Environment=HOST=0.0.0.0
|
||||
Environment=STATIC_DIR=/opt/blind-chess/client/dist
|
||||
Environment=PUBLIC_BASE=http://chess.local
|
||||
Environment=LOG_LEVEL=info
|
||||
Restart=always
|
||||
RestartSec=2s
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
# Bind privileged port 80 as a non-root user
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
|
||||
# Hardening
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ReadWritePaths=/opt/blind-chess
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
# Publish "chess.local" as an mDNS alias for this host's primary IPv4 address.
|
||||
# Invoked by chess-mdns-alias.service (blind_chess local deploy).
|
||||
#
|
||||
# avahi-daemon already advertises the host's own <hostname>.local; this adds
|
||||
# the friendly "chess.local" name pointing at the same machine. Runs in the
|
||||
# foreground holding the registration until the service is stopped.
|
||||
set -euo pipefail
|
||||
|
||||
IP="$(hostname -I | awk '{print $1}')"
|
||||
if [ -z "$IP" ]; then
|
||||
echo "chess-mdns-alias: no IPv4 address found" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "chess-mdns-alias: publishing chess.local -> $IP"
|
||||
# -R/--no-reverse: skip the reverse (PTR) record. avahi-daemon already owns the
|
||||
# PTR for this IP via the host's own <hostname>.local, so publishing chess.local
|
||||
# for the same address *with* a reverse entry collides ("Local name collision").
|
||||
# Clients only need the forward A record, which -a still publishes.
|
||||
exec avahi-publish -a -R chess.local "$IP"
|
||||
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Publish chess.local mDNS alias for the blind_chess local deploy
|
||||
Requires=avahi-daemon.service
|
||||
After=avahi-daemon.service network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/local/bin/chess-mdns-alias
|
||||
Restart=always
|
||||
RestartSec=5s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
# blind_chess — local (chess.local) deploy installer.
|
||||
#
|
||||
# Run as root ON THE TARGET HOST. Expects a staging directory containing:
|
||||
# server/ pnpm-deploy bundle (dist/ + node_modules/)
|
||||
# client-dist/ vite build output
|
||||
# chess-mdns-alias mDNS alias helper script
|
||||
# blind-chess-local.service systemd unit for the server
|
||||
# chess-mdns-alias.service systemd unit for the mDNS alias
|
||||
#
|
||||
# Usage: sudo bash install-local.sh [STAGE_DIR]
|
||||
# (STAGE_DIR defaults to the directory containing this script)
|
||||
set -euo pipefail
|
||||
|
||||
STAGE="${1:-$(cd "$(dirname "$0")" && pwd)}"
|
||||
echo "=== blind_chess local install (staging: $STAGE) ==="
|
||||
|
||||
# --- Node.js 22 (Debian trixie ships only 20; blind_chess needs >=22) ---
|
||||
need_node=1
|
||||
if command -v node >/dev/null 2>&1; then
|
||||
major="$(node -e 'process.stdout.write(String(process.versions.node.split(".")[0]))' 2>/dev/null || echo 0)"
|
||||
if [ "${major:-0}" -ge 22 ] 2>/dev/null; then need_node=0; fi
|
||||
fi
|
||||
if [ "$need_node" -eq 1 ]; then
|
||||
echo "--- installing Node.js 22 via NodeSource ---"
|
||||
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
|
||||
apt-get install -y -o DPkg::Lock::Timeout=600 nodejs
|
||||
fi
|
||||
echo "node: $(node --version)"
|
||||
|
||||
# --- avahi-utils provides avahi-publish ---
|
||||
command -v avahi-publish >/dev/null 2>&1 || \
|
||||
apt-get install -y -o DPkg::Lock::Timeout=600 avahi-utils
|
||||
|
||||
# --- dedicated unprivileged service user ---
|
||||
getent passwd blindchess >/dev/null 2>&1 || \
|
||||
useradd --system --user-group --no-create-home --shell /usr/sbin/nologin blindchess
|
||||
|
||||
# --- deploy tree under /opt/blind-chess ---
|
||||
install -d /opt/blind-chess
|
||||
rm -rf /opt/blind-chess/server /opt/blind-chess/client
|
||||
cp -a "$STAGE/server" /opt/blind-chess/server
|
||||
install -d /opt/blind-chess/client
|
||||
cp -a "$STAGE/client-dist" /opt/blind-chess/client/dist
|
||||
chown -R blindchess:blindchess /opt/blind-chess
|
||||
|
||||
# --- mDNS alias helper ---
|
||||
install -m 0755 "$STAGE/chess-mdns-alias" /usr/local/bin/chess-mdns-alias
|
||||
|
||||
# --- systemd units (the server unit installs under the canonical name) ---
|
||||
install -m 0644 "$STAGE/blind-chess-local.service" /etc/systemd/system/blind-chess.service
|
||||
install -m 0644 "$STAGE/chess-mdns-alias.service" /etc/systemd/system/chess-mdns-alias.service
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now chess-mdns-alias.service
|
||||
systemctl enable --now blind-chess.service
|
||||
|
||||
echo "=== install complete ==="
|
||||
systemctl --no-pager --lines=0 status blind-chess.service chess-mdns-alias.service || true
|
||||
Reference in New Issue
Block a user