web/deploy: add one-shot install.sh

Adds web/deploy/install.sh — full LXC setup in one command. It derives the
repo path from its own location (clone anywhere; /opt/ponfw recommended),
installs git/node/npm if missing (checks Node >= 18), creates the ponfw
service user, runs npm install --omit=dev, writes /etc/pon-fleet-web.env on
first run, and installs+enables the systemd unit with WorkingDirectory set to
the checkout. Idempotent; warns if cloned under /home (ProtectHome blocks it).

README + CLAUDE.md §16 updated to lead with install.sh and clarify the clone
location.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Jon Vanvik 2026-06-23 14:30:06 +02:00
parent c2206ad5a7
commit de037c8795
3 changed files with 126 additions and 23 deletions

96
web/deploy/install.sh Executable file
View file

@ -0,0 +1,96 @@
#!/usr/bin/env bash
# One-shot setup for the PON Fleet web server on a Debian 13 LXC.
#
# Clone the repo first (anywhere — /opt/ponfw recommended), then run this
# from inside the checkout as root:
#
# git clone ssh://forgejo@int.git.vanvikinternet.no/Svorka/ponfw.git /opt/ponfw
# sudo /opt/ponfw/web/deploy/install.sh
#
# It installs runtime deps (tough-cookie only; skips Electron), creates an
# unprivileged service user, writes /etc/pon-fleet-web.env on first run, and
# installs + enables a systemd unit pointed at THIS checkout. Safe to re-run.
set -euo pipefail
SERVICE="pon-fleet-web"
SERVICE_USER="ponfw"
ENV_FILE="/etc/pon-fleet-web.env"
# Repo root is two levels up from this script (web/deploy/install.sh).
SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)"
REPO="$(cd "$SCRIPT_DIR/../.." && pwd)"
DEPLOY="$REPO/web/deploy"
if [[ $EUID -ne 0 ]]; then
echo "Run as root: sudo $0" >&2
exit 1
fi
echo "==> Repo checkout: $REPO"
case "$REPO" in
/home/*)
echo "!! WARNING: the repo is under /home. The hardened systemd unit sets" >&2
echo "!! ProtectHome=true, which will stop the service from reading it." >&2
echo "!! Clone to /opt/ponfw instead, or remove ProtectHome from the unit." >&2
;;
esac
# --- dependencies (git, node, npm) ---
need=()
command -v git >/dev/null 2>&1 || need+=(git)
command -v node >/dev/null 2>&1 || need+=(nodejs)
command -v npm >/dev/null 2>&1 || need+=(npm)
if (( ${#need[@]} )); then
echo "==> apt-get install ${need[*]}"
apt-get update -y
apt-get install -y "${need[@]}"
fi
NODE_MAJOR="$(node -p 'process.versions.node.split(".")[0]' 2>/dev/null || echo 0)"
if (( NODE_MAJOR < 18 )); then
echo "!! Node $(node -v 2>/dev/null || echo '?') is too old (need >= 18)." >&2
echo "!! Install a newer Node (e.g. via NodeSource) and re-run." >&2
exit 1
fi
echo "==> Using $(node -v)"
# --- service user ---
if ! id -u "$SERVICE_USER" >/dev/null 2>&1; then
echo "==> Creating system user $SERVICE_USER"
adduser --system --group --no-create-home "$SERVICE_USER"
fi
# --- runtime deps (npm install, not ci: package-lock.json is gitignored) ---
echo "==> Installing runtime dependencies"
( cd "$REPO" && npm install --omit=dev --no-audit --no-fund )
# --- env file (first run only; never clobber operator edits) ---
if [[ -f "$ENV_FILE" ]]; then
echo "==> $ENV_FILE already exists — leaving it untouched"
else
echo "==> Writing $ENV_FILE from the example (review it)"
install -m 0640 "$DEPLOY/pon-fleet-web.env.example" "$ENV_FILE"
fi
# --- systemd unit, with WorkingDirectory pointed at THIS checkout ---
echo "==> Installing systemd unit"
sed "s|^WorkingDirectory=.*|WorkingDirectory=$REPO/web|" \
"$DEPLOY/$SERVICE.service" > "/etc/systemd/system/$SERVICE.service"
systemctl daemon-reload
systemctl enable --now "$SERVICE"
sleep 1
systemctl --no-pager --lines=10 status "$SERVICE" || true
IP="$(hostname -I 2>/dev/null | awk '{print $1}')"
cat <<MSG
==> Done — $SERVICE is enabled and running.
Config: $ENV_FILE Logs: journalctl -u $SERVICE -f
Update: sudo $DEPLOY/update.sh
Point Nginx Proxy Manager at this LXC:
Forward Hostname/IP: ${IP:-<this-lxc-ip>} Forward Port: 8080 Scheme: http
Add your Access List, request an SSL cert, enable Block Common Exploits.
(If NPM runs on a different host, set HOST=0.0.0.0 in $ENV_FILE and
restart: systemctl restart $SERVICE)
MSG